Skip to content

Commit 95fb82f

Browse files
committed
test_ecdsa: use hypothesis for random sign and verify
make the test with different keys, messages and nonces reproducible use all the curves/generators defined in the test (not only P-192)
1 parent bed03a2 commit 95fb82f

File tree

1 file changed

+54
-36
lines changed

1 file changed

+54
-36
lines changed

src/ecdsa/test_ecdsa.py

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
from __future__ import print_function
2-
import random
2+
import sys
3+
import hypothesis.strategies as st
4+
from hypothesis import given, settings, note
35
from .ecdsa import Private_key, Public_key, Signature, \
4-
curve_192, generator_192, digest_integer, ellipticcurve, point_is_valid
6+
curve_192, generator_192, digest_integer, ellipticcurve, point_is_valid, \
7+
generator_224, generator_256, generator_384, generator_521, \
8+
generator_secp256k1
9+
10+
11+
HYP_SETTINGS = {}
12+
# old hypothesis doesn't have the "deadline" setting
13+
if sys.version_info > (2, 7):
14+
# SEC521p is slow, allow long execution for it
15+
HYP_SETTINGS["deadline"] = 5000
516

617

718
def test_ecdsa():
@@ -293,38 +304,45 @@ def test_pk_recovery(Msg, R, S, Qx, Qy):
293304
S = 0x984c2db99827576c0a41a5da41e07d8cc768bc82f18c9da9
294305
test_signature_validity(Msg, Qx, Qy, R, S, False)
295306

296-
print("Testing the example code:")
297-
298-
# Building a public/private key pair from the NIST Curve P-192:
299-
300-
g = generator_192
301-
n = g.order()
302-
303-
# (random.SystemRandom is supposed to provide
304-
# crypto-quality random numbers, but as Debian recently
305-
# illustrated, a systems programmer can accidentally
306-
# demolish this security, so in serious applications
307-
# further precautions are appropriate.)
308-
309-
randrange = random.SystemRandom().randrange
310-
311-
secret = randrange(1, n)
312-
pubkey = Public_key(g, g * secret)
313-
privkey = Private_key(pubkey, secret)
314307

315-
# Signing a hash value:
316-
317-
hash = randrange(1, n)
318-
signature = privkey.sign(hash, randrange(1, n))
319-
320-
# Verifying a signature for a hash value:
321-
322-
if pubkey.verifies(hash, signature):
323-
print("Demo verification succeeded.")
324-
else:
325-
raise TestFailure("*** Demo verification failed.")
326-
327-
if pubkey.verifies(hash - 1, signature):
328-
raise TestFailure("**** Demo verification failed to reject tampered hash.")
329-
else:
330-
print("Demo verification correctly rejected tampered hash.")
308+
@st.composite
309+
def st_random_gen_key_msg_nonce(draw):
310+
"""Hypothesis strategy for test_sig_verify()."""
311+
name_gen = {
312+
"generator_192": generator_192,
313+
"generator_224": generator_224,
314+
"generator_256": generator_256,
315+
"generator_secp256k1": generator_secp256k1,
316+
"generator_384": generator_384,
317+
"generator_521": generator_521}
318+
name = draw(st.sampled_from(sorted(name_gen.keys())))
319+
note("Generator used: {0}".format(name))
320+
generator = name_gen[name]
321+
order = generator.order()
322+
323+
key = draw(st.integers(min_value=1, max_value=order))
324+
msg = draw(st.integers(min_value=1, max_value=order))
325+
nonce = draw(st.integers(min_value=1, max_value=order+1) |
326+
st.integers(min_value=order>>1, max_value=order))
327+
return generator, key, msg, nonce
328+
329+
330+
SIG_VER_SETTINGS = dict(HYP_SETTINGS)
331+
SIG_VER_SETTINGS["max_examples"] = 10
332+
@settings(**SIG_VER_SETTINGS)
333+
@given(st_random_gen_key_msg_nonce())
334+
def test_sig_verify(args):
335+
"""
336+
Check if signing and verification works for arbitrary messages and
337+
that signatures for other messages are rejected.
338+
"""
339+
generator, sec_mult, msg, nonce = args
340+
341+
pubkey = Public_key(generator, generator * sec_mult)
342+
privkey = Private_key(pubkey, sec_mult)
343+
344+
signature = privkey.sign(msg, nonce)
345+
346+
assert pubkey.verifies(msg, signature)
347+
348+
assert not pubkey.verifies(msg - 1, signature)

0 commit comments

Comments
 (0)