You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
486 lines
21 KiB
486 lines
21 KiB
import unittest |
|
import os |
|
import time |
|
import shutil |
|
import subprocess |
|
from binascii import hexlify, unhexlify |
|
from hashlib import sha1, sha256 |
|
|
|
from keys import SigningKey, VerifyingKey |
|
from keys import BadSignatureError |
|
import util |
|
from util import sigencode_der, sigencode_strings |
|
from util import sigdecode_der, sigdecode_strings |
|
from curves import Curve, UnknownCurveError |
|
from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p |
|
import der |
|
|
|
class SubprocessError(Exception): |
|
pass |
|
|
|
def run_openssl(cmd): |
|
OPENSSL = "openssl" |
|
p = subprocess.Popen([OPENSSL] + cmd.split(), |
|
stdout=subprocess.PIPE, |
|
stderr=subprocess.STDOUT) |
|
stdout, ignored = p.communicate() |
|
if p.returncode != 0: |
|
raise SubprocessError("cmd '%s %s' failed: rc=%s, stdout/err was %s" % |
|
(OPENSSL, cmd, p.returncode, stdout)) |
|
return stdout |
|
|
|
BENCH = False |
|
|
|
class ECDSA(unittest.TestCase): |
|
def test_basic(self): |
|
priv = SigningKey.generate() |
|
pub = priv.get_verifying_key() |
|
|
|
data = "blahblah" |
|
sig = priv.sign(data) |
|
|
|
self.failUnless(pub.verify(sig, data)) |
|
self.failUnlessRaises(BadSignatureError, pub.verify, sig, data+"bad") |
|
|
|
pub2 = VerifyingKey.from_string(pub.to_string()) |
|
self.failUnless(pub2.verify(sig, data)) |
|
|
|
def test_bad_usage(self): |
|
# sk=SigningKey() is wrong |
|
self.failUnlessRaises(TypeError, SigningKey) |
|
self.failUnlessRaises(TypeError, VerifyingKey) |
|
|
|
def test_lengths(self): |
|
default = NIST192p |
|
priv = SigningKey.generate() |
|
pub = priv.get_verifying_key() |
|
self.failUnlessEqual(len(pub.to_string()), default.verifying_key_length) |
|
sig = priv.sign("data") |
|
self.failUnlessEqual(len(sig), default.signature_length) |
|
if BENCH: |
|
print |
|
for curve in (NIST192p, NIST224p, NIST256p, NIST384p, NIST521p): |
|
start = time.time() |
|
priv = SigningKey.generate(curve=curve) |
|
pub1 = priv.get_verifying_key() |
|
keygen_time = time.time() - start |
|
pub2 = VerifyingKey.from_string(pub1.to_string(), curve) |
|
self.failUnlessEqual(pub1.to_string(), pub2.to_string()) |
|
self.failUnlessEqual(len(pub1.to_string()), |
|
curve.verifying_key_length) |
|
start = time.time() |
|
sig = priv.sign("data") |
|
sign_time = time.time() - start |
|
self.failUnlessEqual(len(sig), curve.signature_length) |
|
if BENCH: |
|
start = time.time() |
|
pub1.verify(sig, "data") |
|
verify_time = time.time() - start |
|
print "%s: siglen=%d, keygen=%0.3fs, sign=%0.3f, verify=%0.3f" \ |
|
% (curve.name, curve.signature_length, |
|
keygen_time, sign_time, verify_time) |
|
|
|
def test_serialize(self): |
|
seed = "secret" |
|
curve = NIST192p |
|
secexp1 = util.randrange_from_seed__trytryagain(seed, curve.order) |
|
secexp2 = util.randrange_from_seed__trytryagain(seed, curve.order) |
|
self.failUnlessEqual(secexp1, secexp2) |
|
priv1 = SigningKey.from_secret_exponent(secexp1, curve) |
|
priv2 = SigningKey.from_secret_exponent(secexp2, curve) |
|
self.failUnlessEqual(hexlify(priv1.to_string()), |
|
hexlify(priv2.to_string())) |
|
self.failUnlessEqual(priv1.to_pem(), priv2.to_pem()) |
|
pub1 = priv1.get_verifying_key() |
|
pub2 = priv2.get_verifying_key() |
|
data = "data" |
|
sig1 = priv1.sign(data) |
|
sig2 = priv2.sign(data) |
|
self.failUnless(pub1.verify(sig1, data)) |
|
self.failUnless(pub2.verify(sig1, data)) |
|
self.failUnless(pub1.verify(sig2, data)) |
|
self.failUnless(pub2.verify(sig2, data)) |
|
self.failUnlessEqual(hexlify(pub1.to_string()), |
|
hexlify(pub2.to_string())) |
|
|
|
def test_nonrandom(self): |
|
s = "all the entropy in the entire world, compressed into one line" |
|
def not_much_entropy(numbytes): |
|
return s[:numbytes] |
|
# we control the entropy source, these two keys should be identical: |
|
priv1 = SigningKey.generate(entropy=not_much_entropy) |
|
priv2 = SigningKey.generate(entropy=not_much_entropy) |
|
self.failUnlessEqual(hexlify(priv1.get_verifying_key().to_string()), |
|
hexlify(priv2.get_verifying_key().to_string())) |
|
# likewise, signatures should be identical. Obviously you'd never |
|
# want to do this with keys you care about, because the secrecy of |
|
# the private key depends upon using different random numbers for |
|
# each signature |
|
sig1 = priv1.sign("data", entropy=not_much_entropy) |
|
sig2 = priv2.sign("data", entropy=not_much_entropy) |
|
self.failUnlessEqual(hexlify(sig1), hexlify(sig2)) |
|
|
|
def failUnlessPrivkeysEqual(self, priv1, priv2): |
|
self.failUnlessEqual(priv1.privkey.secret_multiplier, |
|
priv2.privkey.secret_multiplier) |
|
self.failUnlessEqual(priv1.privkey.public_key.generator, |
|
priv2.privkey.public_key.generator) |
|
|
|
def failIfPrivkeysEqual(self, priv1, priv2): |
|
self.failIfEqual(priv1.privkey.secret_multiplier, |
|
priv2.privkey.secret_multiplier) |
|
|
|
def test_privkey_creation(self): |
|
s = "all the entropy in the entire world, compressed into one line" |
|
def not_much_entropy(numbytes): |
|
return s[:numbytes] |
|
priv1 = SigningKey.generate() |
|
self.failUnlessEqual(priv1.baselen, NIST192p.baselen) |
|
|
|
priv1 = SigningKey.generate(curve=NIST224p) |
|
self.failUnlessEqual(priv1.baselen, NIST224p.baselen) |
|
|
|
priv1 = SigningKey.generate(entropy=not_much_entropy) |
|
self.failUnlessEqual(priv1.baselen, NIST192p.baselen) |
|
priv2 = SigningKey.generate(entropy=not_much_entropy) |
|
self.failUnlessEqual(priv2.baselen, NIST192p.baselen) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
priv1 = SigningKey.from_secret_exponent(secexp=3) |
|
self.failUnlessEqual(priv1.baselen, NIST192p.baselen) |
|
priv2 = SigningKey.from_secret_exponent(secexp=3) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
priv1 = SigningKey.from_secret_exponent(secexp=4, curve=NIST224p) |
|
self.failUnlessEqual(priv1.baselen, NIST224p.baselen) |
|
|
|
def test_privkey_strings(self): |
|
priv1 = SigningKey.generate() |
|
s1 = priv1.to_string() |
|
self.failUnlessEqual(type(s1), str) |
|
self.failUnlessEqual(len(s1), NIST192p.baselen) |
|
priv2 = SigningKey.from_string(s1) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
s1 = priv1.to_pem() |
|
self.failUnlessEqual(type(s1), str) |
|
self.failUnless(s1.startswith("-----BEGIN EC PRIVATE KEY-----")) |
|
self.failUnless(s1.strip().endswith("-----END EC PRIVATE KEY-----")) |
|
priv2 = SigningKey.from_pem(s1) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
s1 = priv1.to_der() |
|
self.failUnlessEqual(type(s1), str) |
|
priv2 = SigningKey.from_der(s1) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
priv1 = SigningKey.generate(curve=NIST256p) |
|
s1 = priv1.to_pem() |
|
self.failUnlessEqual(type(s1), str) |
|
self.failUnless(s1.startswith("-----BEGIN EC PRIVATE KEY-----")) |
|
self.failUnless(s1.strip().endswith("-----END EC PRIVATE KEY-----")) |
|
priv2 = SigningKey.from_pem(s1) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
s1 = priv1.to_der() |
|
self.failUnlessEqual(type(s1), str) |
|
priv2 = SigningKey.from_der(s1) |
|
self.failUnlessPrivkeysEqual(priv1, priv2) |
|
|
|
def failUnlessPubkeysEqual(self, pub1, pub2): |
|
self.failUnlessEqual(pub1.pubkey.point, pub2.pubkey.point) |
|
self.failUnlessEqual(pub1.pubkey.generator, pub2.pubkey.generator) |
|
self.failUnlessEqual(pub1.curve, pub2.curve) |
|
|
|
def test_pubkey_strings(self): |
|
priv1 = SigningKey.generate() |
|
pub1 = priv1.get_verifying_key() |
|
s1 = pub1.to_string() |
|
self.failUnlessEqual(type(s1), str) |
|
self.failUnlessEqual(len(s1), NIST192p.verifying_key_length) |
|
pub2 = VerifyingKey.from_string(s1) |
|
self.failUnlessPubkeysEqual(pub1, pub2) |
|
|
|
priv1 = SigningKey.generate(curve=NIST256p) |
|
pub1 = priv1.get_verifying_key() |
|
s1 = pub1.to_string() |
|
self.failUnlessEqual(type(s1), str) |
|
self.failUnlessEqual(len(s1), NIST256p.verifying_key_length) |
|
pub2 = VerifyingKey.from_string(s1, curve=NIST256p) |
|
self.failUnlessPubkeysEqual(pub1, pub2) |
|
|
|
pub1_der = pub1.to_der() |
|
self.failUnlessEqual(type(pub1_der), str) |
|
pub2 = VerifyingKey.from_der(pub1_der) |
|
self.failUnlessPubkeysEqual(pub1, pub2) |
|
|
|
self.failUnlessRaises(der.UnexpectedDER, |
|
VerifyingKey.from_der, pub1_der+"junk") |
|
badpub = VerifyingKey.from_der(pub1_der) |
|
class FakeGenerator: |
|
def order(self): return 123456789 |
|
badcurve = Curve("unknown", None, FakeGenerator(), (1,2,3,4,5,6)) |
|
badpub.curve = badcurve |
|
badder = badpub.to_der() |
|
self.failUnlessRaises(UnknownCurveError, VerifyingKey.from_der, badder) |
|
|
|
pem = pub1.to_pem() |
|
self.failUnlessEqual(type(pem), str) |
|
self.failUnless(pem.startswith("-----BEGIN PUBLIC KEY-----"), pem) |
|
self.failUnless(pem.strip().endswith("-----END PUBLIC KEY-----"), pem) |
|
pub2 = VerifyingKey.from_pem(pem) |
|
self.failUnlessPubkeysEqual(pub1, pub2) |
|
|
|
def test_signature_strings(self): |
|
priv1 = SigningKey.generate() |
|
pub1 = priv1.get_verifying_key() |
|
data = "data" |
|
|
|
sig = priv1.sign(data) |
|
self.failUnlessEqual(type(sig), str) |
|
self.failUnlessEqual(len(sig), NIST192p.signature_length) |
|
self.failUnless(pub1.verify(sig, data)) |
|
|
|
sig = priv1.sign(data, sigencode=sigencode_strings) |
|
self.failUnlessEqual(type(sig), tuple) |
|
self.failUnlessEqual(len(sig), 2) |
|
self.failUnlessEqual(type(sig[0]), str) |
|
self.failUnlessEqual(type(sig[1]), str) |
|
self.failUnlessEqual(len(sig[0]), NIST192p.baselen) |
|
self.failUnlessEqual(len(sig[1]), NIST192p.baselen) |
|
self.failUnless(pub1.verify(sig, data, sigdecode=sigdecode_strings)) |
|
|
|
sig_der = priv1.sign(data, sigencode=sigencode_der) |
|
self.failUnlessEqual(type(sig_der), str) |
|
self.failUnless(pub1.verify(sig_der, data, sigdecode=sigdecode_der)) |
|
|
|
def test_hashfunc(self): |
|
sk = SigningKey.generate(curve=NIST256p, hashfunc=sha256) |
|
data = "security level is 128 bits" |
|
sig = sk.sign(data) |
|
vk = VerifyingKey.from_string(sk.get_verifying_key().to_string(), |
|
curve=NIST256p, hashfunc=sha256) |
|
self.failUnless(vk.verify(sig, data)) |
|
|
|
sk2 = SigningKey.generate(curve=NIST256p) |
|
sig2 = sk2.sign(data, hashfunc=sha256) |
|
vk2 = VerifyingKey.from_string(sk2.get_verifying_key().to_string(), |
|
curve=NIST256p, hashfunc=sha256) |
|
self.failUnless(vk2.verify(sig2, data)) |
|
|
|
vk3 = VerifyingKey.from_string(sk.get_verifying_key().to_string(), |
|
curve=NIST256p) |
|
self.failUnless(vk3.verify(sig, data, hashfunc=sha256)) |
|
|
|
|
|
class OpenSSL(unittest.TestCase): |
|
# test interoperability with OpenSSL tools. Note that openssl's ECDSA |
|
# sign/verify arguments changed between 0.9.8 and 1.0.0: the early |
|
# versions require "-ecdsa-with-SHA1", the later versions want just |
|
# "-SHA1" (or to leave out that argument entirely, which means the |
|
# signature will use some default digest algorithm, probably determined |
|
# by the key, probably always SHA1). |
|
# |
|
# openssl ecparam -name secp224r1 -genkey -out privkey.pem |
|
# openssl ec -in privkey.pem -text -noout # get the priv/pub keys |
|
# openssl dgst -ecdsa-with-SHA1 -sign privkey.pem -out data.sig data.txt |
|
# openssl asn1parse -in data.sig -inform DER |
|
# data.sig is 64 bytes, probably 56b plus ASN1 overhead |
|
# openssl dgst -ecdsa-with-SHA1 -prverify privkey.pem -signature data.sig data.txt ; echo $? |
|
# openssl ec -in privkey.pem -pubout -out pubkey.pem |
|
# openssl ec -in privkey.pem -pubout -outform DER -out pubkey.der |
|
|
|
def get_openssl_messagedigest_arg(self): |
|
v = run_openssl("version") |
|
# e.g. "OpenSSL 1.0.0 29 Mar 2010", or "OpenSSL 1.0.0a 1 Jun 2010", |
|
# or "OpenSSL 0.9.8o 01 Jun 2010" |
|
vs = v.split()[1].split(".") |
|
if vs >= ["1","0","0"]: |
|
return "-SHA1" |
|
else: |
|
return "-ecdsa-with-SHA1" |
|
|
|
# sk: 1:OpenSSL->python 2:python->OpenSSL |
|
# vk: 3:OpenSSL->python 4:python->OpenSSL |
|
# sig: 5:OpenSSL->python 6:python->OpenSSL |
|
|
|
def test_from_openssl_nist192p(self): |
|
return self.do_test_from_openssl(NIST192p, "prime192v1") |
|
def test_from_openssl_nist224p(self): |
|
return self.do_test_from_openssl(NIST224p, "secp224r1") |
|
def test_from_openssl_nist384p(self): |
|
return self.do_test_from_openssl(NIST384p, "secp384r1") |
|
def test_from_openssl_nist521p(self): |
|
return self.do_test_from_openssl(NIST521p, "secp521r1") |
|
|
|
def do_test_from_openssl(self, curve, curvename): |
|
# OpenSSL: create sk, vk, sign. |
|
# Python: read vk(3), checksig(5), read sk(1), sign, check |
|
mdarg = self.get_openssl_messagedigest_arg() |
|
if os.path.isdir("t"): |
|
shutil.rmtree("t") |
|
os.mkdir("t") |
|
run_openssl("ecparam -name %s -genkey -out t/privkey.pem" % curvename) |
|
run_openssl("ec -in t/privkey.pem -pubout -out t/pubkey.pem") |
|
data = "data" |
|
open("t/data.txt","wb").write(data) |
|
run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig t/data.txt" % mdarg) |
|
run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig t/data.txt" % mdarg) |
|
pubkey_pem = open("t/pubkey.pem").read() |
|
vk = VerifyingKey.from_pem(pubkey_pem) # 3 |
|
sig_der = open("t/data.sig","rb").read() |
|
self.failUnless(vk.verify(sig_der, data, # 5 |
|
hashfunc=sha1, sigdecode=sigdecode_der)) |
|
|
|
sk = SigningKey.from_pem(open("t/privkey.pem").read()) # 1 |
|
sig = sk.sign(data) |
|
self.failUnless(vk.verify(sig, data)) |
|
|
|
def test_to_openssl_nist192p(self): |
|
self.do_test_to_openssl(NIST192p, "prime192v1") |
|
def test_to_openssl_nist224p(self): |
|
self.do_test_to_openssl(NIST224p, "secp224r1") |
|
def test_to_openssl_nist384p(self): |
|
self.do_test_to_openssl(NIST384p, "secp384r1") |
|
def test_to_openssl_nist521p(self): |
|
self.do_test_to_openssl(NIST521p, "secp521r1") |
|
|
|
def do_test_to_openssl(self, curve, curvename): |
|
# Python: create sk, vk, sign. |
|
# OpenSSL: read vk(4), checksig(6), read sk(2), sign, check |
|
mdarg = self.get_openssl_messagedigest_arg() |
|
if os.path.isdir("t"): |
|
shutil.rmtree("t") |
|
os.mkdir("t") |
|
sk = SigningKey.generate(curve=curve) |
|
vk = sk.get_verifying_key() |
|
data = "data" |
|
open("t/pubkey.der","wb").write(vk.to_der()) # 4 |
|
open("t/pubkey.pem","wb").write(vk.to_pem()) # 4 |
|
sig_der = sk.sign(data, hashfunc=sha1, sigencode=sigencode_der) |
|
open("t/data.sig","wb").write(sig_der) # 6 |
|
open("t/data.txt","wb").write(data) |
|
open("t/baddata.txt","wb").write(data+"corrupt") |
|
|
|
self.failUnlessRaises(SubprocessError, run_openssl, |
|
"dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/baddata.txt" % mdarg) |
|
run_openssl("dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/data.txt" % mdarg) |
|
|
|
open("t/privkey.pem","wb").write(sk.to_pem()) # 2 |
|
run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig2 t/data.txt" % mdarg) |
|
run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" % mdarg) |
|
|
|
class DER(unittest.TestCase): |
|
def test_oids(self): |
|
oid_ecPublicKey = der.encode_oid(1, 2, 840, 10045, 2, 1) |
|
self.failUnlessEqual(hexlify(oid_ecPublicKey), "06072a8648ce3d0201") |
|
self.failUnlessEqual(hexlify(NIST224p.encoded_oid), "06052b81040021") |
|
self.failUnlessEqual(hexlify(NIST256p.encoded_oid), |
|
"06082a8648ce3d030107") |
|
x = oid_ecPublicKey + "more" |
|
x1, rest = der.remove_object(x) |
|
self.failUnlessEqual(x1, (1, 2, 840, 10045, 2, 1)) |
|
self.failUnlessEqual(rest, "more") |
|
|
|
def test_integer(self): |
|
self.failUnlessEqual(der.encode_integer(0), "\x02\x01\x00") |
|
self.failUnlessEqual(der.encode_integer(1), "\x02\x01\x01") |
|
self.failUnlessEqual(der.encode_integer(127), "\x02\x01\x7f") |
|
self.failUnlessEqual(der.encode_integer(128), "\x02\x02\x00\x80") |
|
self.failUnlessEqual(der.encode_integer(256), "\x02\x02\x01\x00") |
|
#self.failUnlessEqual(der.encode_integer(-1), "\x02\x01\xff") |
|
|
|
def s(n): return der.remove_integer(der.encode_integer(n) + "junk") |
|
self.failUnlessEqual(s(0), (0, "junk")) |
|
self.failUnlessEqual(s(1), (1, "junk")) |
|
self.failUnlessEqual(s(127), (127, "junk")) |
|
self.failUnlessEqual(s(128), (128, "junk")) |
|
self.failUnlessEqual(s(256), (256, "junk")) |
|
self.failUnlessEqual(s(1234567890123456789012345678901234567890), |
|
( 1234567890123456789012345678901234567890,"junk")) |
|
|
|
def test_number(self): |
|
self.failUnlessEqual(der.encode_number(0), "\x00") |
|
self.failUnlessEqual(der.encode_number(127), "\x7f") |
|
self.failUnlessEqual(der.encode_number(128), "\x81\x00") |
|
self.failUnlessEqual(der.encode_number(3*128+7), "\x83\x07") |
|
#self.failUnlessEqual(der.read_number("\x81\x9b"+"more"), (155, 2)) |
|
#self.failUnlessEqual(der.encode_number(155), "\x81\x9b") |
|
for n in (0, 1, 2, 127, 128, 3*128+7, 840, 10045): #, 155): |
|
x = der.encode_number(n) + "more" |
|
n1, llen = der.read_number(x) |
|
self.failUnlessEqual(n1, n) |
|
self.failUnlessEqual(x[llen:], "more") |
|
|
|
def test_length(self): |
|
self.failUnlessEqual(der.encode_length(0), "\x00") |
|
self.failUnlessEqual(der.encode_length(127), "\x7f") |
|
self.failUnlessEqual(der.encode_length(128), "\x81\x80") |
|
self.failUnlessEqual(der.encode_length(255), "\x81\xff") |
|
self.failUnlessEqual(der.encode_length(256), "\x82\x01\x00") |
|
self.failUnlessEqual(der.encode_length(3*256+7), "\x82\x03\x07") |
|
self.failUnlessEqual(der.read_length("\x81\x9b"+"more"), (155, 2)) |
|
self.failUnlessEqual(der.encode_length(155), "\x81\x9b") |
|
for n in (0, 1, 2, 127, 128, 255, 256, 3*256+7, 155): |
|
x = der.encode_length(n) + "more" |
|
n1, llen = der.read_length(x) |
|
self.failUnlessEqual(n1, n) |
|
self.failUnlessEqual(x[llen:], "more") |
|
|
|
def test_sequence(self): |
|
x = der.encode_sequence("ABC", "DEF") + "GHI" |
|
self.failUnlessEqual(x, "\x30\x06ABCDEFGHI") |
|
x1, rest = der.remove_sequence(x) |
|
self.failUnlessEqual(x1, "ABCDEF") |
|
self.failUnlessEqual(rest, "GHI") |
|
|
|
def test_constructed(self): |
|
x = der.encode_constructed(0, NIST224p.encoded_oid) |
|
self.failUnlessEqual(hexlify(x), "a007" + "06052b81040021") |
|
x = der.encode_constructed(1, unhexlify("0102030a0b0c")) |
|
self.failUnlessEqual(hexlify(x), "a106" + "0102030a0b0c") |
|
|
|
class Util(unittest.TestCase): |
|
def test_trytryagain(self): |
|
tta = util.randrange_from_seed__trytryagain |
|
for i in range(1000): |
|
seed = "seed-%d" % i |
|
for order in (2**8-2, 2**8-1, 2**8, 2**8+1, 2**8+2, |
|
2**16-1, 2**16+1): |
|
n = tta(seed, order) |
|
self.failUnless(1 <= n < order, (1, n, order)) |
|
# this trytryagain *does* provide long-term stability |
|
self.failUnlessEqual("%x"%(tta("seed", NIST224p.order)), |
|
"6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc") |
|
|
|
def test_randrange(self): |
|
# util.randrange does not provide long-term stability: we might |
|
# change the algorithm in the future. |
|
for i in range(1000): |
|
entropy = util.PRNG("seed-%d" % i) |
|
for order in (2**8-2, 2**8-1, 2**8, |
|
2**16-1, 2**16+1, |
|
): |
|
# that oddball 2**16+1 takes half our runtime |
|
n = util.randrange(order, entropy=entropy) |
|
self.failUnless(1 <= n < order, (1, n, order)) |
|
|
|
def OFF_test_prove_uniformity(self): |
|
order = 2**8-2 |
|
counts = dict([(i, 0) for i in range(1, order)]) |
|
assert 0 not in counts |
|
assert order not in counts |
|
for i in range(1000000): |
|
seed = "seed-%d" % i |
|
n = util.randrange_from_seed__trytryagain(seed, order) |
|
counts[n] += 1 |
|
# this technique should use the full range |
|
self.failUnless(counts[order-1]) |
|
for i in range(1, order): |
|
print "%3d: %s" % (i, "*"*(counts[i]//100)) |
|
|
|
|
|
def __main__(): |
|
unittest.main() |
|
if __name__ == "__main__": |
|
__main__()
|
|
|