summaryrefslogtreecommitdiff
path: root/pycryptopp/test/test_ecdsa.py
diff options
context:
space:
mode:
Diffstat (limited to 'pycryptopp/test/test_ecdsa.py')
-rw-r--r--pycryptopp/test/test_ecdsa.py263
1 files changed, 0 insertions, 263 deletions
diff --git a/pycryptopp/test/test_ecdsa.py b/pycryptopp/test/test_ecdsa.py
deleted file mode 100644
index d70a000..0000000
--- a/pycryptopp/test/test_ecdsa.py
+++ /dev/null
@@ -1,263 +0,0 @@
-#!/usr/bin/env python
-
-import random
-import base64
-
-import os
-SEED = os.environ.get('REPEATABLE_RANDOMNESS_SEED', None)
-
-if SEED is None:
- # Generate a seed which is fairly short (to ease cut-and-paste, writing it
- # down, etc.). Note that Python's random module's seed() function is going
- # to take the hash() of this seed, which is a 32-bit value (currently) so
- # there is no point in making this seed larger than 32 bits. Make it 30
- # bits, which conveniently fits into six base-32 chars. Include a separator
- # because chunking facilitates memory (including working and short-term
- # memory) in humans.
- chars = "ybndrfg8ejkmcpqxot1uwisza345h769" # Zooko's choice, rationale in "DESIGN" doc in z-base-32 project
- SEED = ''.join([random.choice(chars) for x in range(3)] + ['-'] + [random.choice(chars) for x in range(3)])
-
-import logging
-logging.info("REPEATABLE_RANDOMNESS_SEED: %s\n" % SEED)
-logging.info("In order to reproduce this run of the code, set the environment variable \"REPEATABLE_RANDOMNESS_SEED\" to %s before executing.\n" % SEED)
-random.seed(SEED)
-
-def seed_which_refuses(a):
- logging.warn("I refuse to reseed to %s -- I already seeded with %s.\n" % (a, SEED,))
- return
-random.seed = seed_which_refuses
-
-from random import randrange
-
-import unittest
-
-from pycryptopp.publickey import ecdsa
-
-def randstr(n, rr=randrange):
- return ''.join([chr(rr(0, 256)) for x in xrange(n)])
-
-from base64 import b32encode
-def ab(x): # debuggery
- if len(x) >= 3:
- return "%s:%s" % (len(x), b32encode(x[-3:]),)
- elif len(x) == 2:
- return "%s:%s" % (len(x), b32encode(x[-2:]),)
- elif len(x) == 1:
- return "%s:%s" % (len(x), b32encode(x[-1:]),)
- elif len(x) == 0:
- return "%s:%s" % (len(x), "--empty--",)
-
-def div_ceil(n, d):
- """
- The smallest integer k such that k*d >= n.
- """
- return (n/d) + (n%d != 0)
-
-KEYBITS=192
-
-# The number of bytes required for a seed to have the same security level as a
-# key in this elliptic curve: 2 bits of public key per bit of security.
-SEEDBITS=div_ceil(192, 2)
-SEEDBYTES=div_ceil(SEEDBITS, 8)
-
-# The number of bytes required to encode a public key in this elliptic curve.
-PUBKEYBYTES=div_ceil(KEYBITS, 8)+1 # 1 byte for the sign of the y component
-
-# The number of bytes requires to encode a signature in this elliptic curve.
-SIGBITS=KEYBITS*2
-SIGBYTES=div_ceil(SIGBITS, 8)
-
-class Signer(unittest.TestCase):
- def test_construct(self):
- seed = randstr(SEEDBYTES)
- ecdsa.SigningKey(seed)
-
- def test_sign(self):
- seed = randstr(SEEDBYTES)
- signer = ecdsa.SigningKey(seed)
- sig = signer.sign("message")
- self.failUnlessEqual(len(sig), SIGBYTES)
-
- def test_sign_and_verify(self):
- seed = randstr(SEEDBYTES)
- signer = ecdsa.SigningKey(seed)
- sig = signer.sign("message")
- v = signer.get_verifying_key()
- self.failUnless(v.verify("message", sig))
-
- def test_sign_and_verify_emptymsg(self):
- seed = randstr(SEEDBYTES)
- signer = ecdsa.SigningKey(seed)
- sig = signer.sign("")
- v = signer.get_verifying_key()
- self.failUnless(v.verify("", sig))
-
- def test_construct_from_same_seed_is_reproducible(self):
- seed = randstr(SEEDBYTES)
- signer1 = ecdsa.SigningKey(seed)
- signer2 = ecdsa.SigningKey(seed)
- self.failUnlessEqual(signer1.get_verifying_key().serialize(), signer2.get_verifying_key().serialize())
-
- # ... and using different seeds constructs a different private key.
- seed3 = randstr(SEEDBYTES)
- assert seed3 != seed, "Internal error in Python random module's PRNG (or in pycryptopp's hacks to it to facilitate testing) -- got two identical strings from randstr(%s)" % SEEDBYTES
- signer3 = ecdsa.SigningKey(seed3)
- self.failIfEqual(signer1.get_verifying_key().serialize(), signer3.get_verifying_key().serialize())
-
- # Also try the all-zeroes string just because bugs sometimes are
- # data-dependent on zero or cause bogus zeroes.
- seed4 = '\x00'*SEEDBYTES
- assert seed4 != seed, "Internal error in Python random module's PRNG (or in pycryptopp's hacks to it to facilitate testing) -- got the all-zeroes string from randstr(%s)" % SEEDBYTES
- signer4 = ecdsa.SigningKey(seed4)
- self.failIfEqual(signer4.get_verifying_key().serialize(), signer1.get_verifying_key().serialize())
-
- signer5 = ecdsa.SigningKey(seed4)
- self.failUnlessEqual(signer5.get_verifying_key().serialize(), signer4.get_verifying_key().serialize())
-
- def test_construct_short_seed(self):
- try:
- ecdsa.SigningKey("\x00\x00\x00")
- except ecdsa.Error, le:
- self.failUnless("seed is required to be of length " in str(le), le)
- else:
- self.fail("Should have raised error from seed being too short.")
-
- def test_construct_bad_arg_type(self):
- try:
- ecdsa.SigningKey(1)
- except TypeError, le:
- self.failUnless("must be string" in str(le), le)
- else:
- self.fail("Should have raised error from seed being of the wrong type.")
-
-class Verifier(unittest.TestCase):
- def test_from_signer_and_serialize_and_deserialize(self):
- seed = randstr(SEEDBYTES)
- signer = ecdsa.SigningKey(seed)
-
- verifier = signer.get_verifying_key()
- s1 = verifier.serialize()
- self.failUnlessEqual(len(s1), PUBKEYBYTES)
- ecdsa.VerifyingKey(s1)
- s2 = verifier.serialize()
- self.failUnlessEqual(s1, s2)
-
-def flip_one_bit(s):
- assert s
- i = randrange(0, len(s))
- result = s[:i] + chr(ord(s[i])^(0x01<<randrange(0, 8))) + s[i+1:]
- assert result != s, "Internal error -- flip_one_bit() produced the same string as its input: %s == %s" % (result, s)
- return result
-
-def randmsg():
- # Choose a random message size from a range probably large enough to
- # exercise any different code paths which depend on the message length.
- randmsglen = randrange(1, SIGBYTES*2+2)
- return randstr(randmsglen)
-
-class SignAndVerify(unittest.TestCase):
- def _help_test_sign_and_check_good_keys(self, signer, verifier):
- msg = randmsg()
-
- sig = signer.sign(msg)
- self.failUnlessEqual(len(sig), SIGBYTES)
- self.failUnless(verifier.verify(msg, sig))
-
- # Now flip one bit of the signature and make sure that the signature doesn't check.
- badsig = flip_one_bit(sig)
- self.failIf(verifier.verify(msg, badsig))
-
- # Now generate a random signature and make sure that the signature doesn't check.
- badsig = randstr(len(sig))
- assert badsig != sig, "Internal error -- randstr() produced the same string twice: %s == %s" % (badsig, sig)
- self.failIf(verifier.verify(msg, badsig))
-
- # Now flip one bit of the message and make sure that the original signature doesn't check.
- badmsg = flip_one_bit(msg)
- self.failIf(verifier.verify(badmsg, sig))
-
- # Now generate a random message and make sure that the original signature doesn't check.
- badmsg = randstr(len(msg))
- assert badmsg != msg, "Internal error -- randstr() produced the same string twice: %s == %s" % (badmsg, msg)
- self.failIf(verifier.verify(badmsg, sig))
-
- def _help_test_sign_and_check_bad_keys(self, signer, verifier):
- """
- Make sure that this signer/verifier pair cannot produce and verify signatures.
- """
- msg = randmsg()
-
- sig = signer.sign(msg)
- self.failUnlessEqual(len(sig), SIGBYTES)
- self.failIf(verifier.verify(msg, sig))
-
- def test(self):
- seed = randstr(SEEDBYTES)
- signer = ecdsa.SigningKey(seed)
- verifier = signer.get_verifying_key()
- self._help_test_sign_and_check_good_keys(signer, verifier)
-
- vstr = verifier.serialize()
- self.failUnlessEqual(len(vstr), PUBKEYBYTES)
- verifier2 = ecdsa.VerifyingKey(vstr)
- self._help_test_sign_and_check_good_keys(signer, verifier2)
-
- signer2 = ecdsa.SigningKey(seed)
- self._help_test_sign_and_check_good_keys(signer2, verifier2)
-
- verifier3 = signer2.get_verifying_key()
- self._help_test_sign_and_check_good_keys(signer, verifier3)
-
- # Now test various ways that the keys could be corrupted or ill-matched.
-
- # Flip one bit of the public key.
- badvstr = flip_one_bit(vstr)
- try:
- badverifier = ecdsa.VerifyingKey(badvstr)
- except ecdsa.Error:
- # Ok, fine, the verifying key was corrupted and Crypto++ detected this fact.
- pass
- else:
- self._help_test_sign_and_check_bad_keys(signer, badverifier)
-
- # Randomize all bits of the public key.
- badvstr = randstr(len(vstr))
- assert badvstr != vstr, "Internal error -- randstr() produced the same string twice: %s == %s" % (badvstr, vstr)
- try:
- badverifier = ecdsa.VerifyingKey(badvstr)
- except ecdsa.Error:
- # Ok, fine, the key was corrupted and Crypto++ detected this fact.
- pass
- else:
- self._help_test_sign_and_check_bad_keys(signer, badverifier)
-
- # Flip one bit of the private key.
- badseed = flip_one_bit(seed)
- badsigner = ecdsa.SigningKey(badseed)
- self._help_test_sign_and_check_bad_keys(badsigner, verifier)
-
- # Randomize all bits of the private key.
- badseed = randstr(len(seed))
- assert badseed != seed, "Internal error -- randstr() produced the same string twice: %s == %s" % (badseed, seed)
- badsigner = ecdsa.SigningKey(badseed)
- self._help_test_sign_and_check_bad_keys(badsigner, verifier)
-
-class Compatibility(unittest.TestCase):
- def test_compatibility(self):
- # Confirm that the KDF used by the SigningKey constructor doesn't
- # change without suitable backwards-compability
- seed = base64.b32decode('XS27TJRP3JBZKDEFBDKQ====')
- signer = ecdsa.SigningKey(seed)
- v1 = signer.get_verifying_key()
- vs = v1.serialize()
- vs32 = base64.b32encode(vs)
- self.failUnlessEqual(vs32, "ANPNDWJWHQXYSQMD4L36D7WQEGXA42MS5JRUFIWA")
- v2 = ecdsa.VerifyingKey(vs)
- #print base64.b32encode(signer.sign("message"))
- sig32 = "EA3Y7A4T62J3K6MUPJQN3WJ5S4SS53EGZXOSTQW7EQ7OXEMS6QJLYL63BLHMHZD7KFT37KEPJBAKI==="
- sig = base64.b32decode(sig32)
- self.failUnless(v1.verify("message", sig))
- self.failUnless(v2.verify("message", sig))
-
-if __name__ == "__main__":
- unittest.main()