mirror of
https://github.com/bitcoin/bips.git
synced 2026-02-23 15:38:22 +00:00
Settle on notation: is_square(y), has_square_y(P)
This commit is contained in:
@@ -11,6 +11,9 @@ def tagged_hash(tag, msg):
|
||||
tag_hash = hashlib.sha256(tag.encode()).digest()
|
||||
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
|
||||
|
||||
def is_infinity(P):
|
||||
return P is None
|
||||
|
||||
def x(P):
|
||||
return P[0]
|
||||
|
||||
@@ -59,11 +62,11 @@ def int_from_bytes(b):
|
||||
def hash_sha256(b):
|
||||
return hashlib.sha256(b).digest()
|
||||
|
||||
def jacobi(x):
|
||||
return pow(x, (p - 1) // 2, p)
|
||||
def is_square(x):
|
||||
return pow(x, (p - 1) // 2, p) == 1
|
||||
|
||||
def is_quad(x):
|
||||
return jacobi(x) == 1
|
||||
def has_square_y(P):
|
||||
return not is_infinity(P) and is_square(y(P))
|
||||
|
||||
def pubkey_gen(seckey):
|
||||
x = int_from_bytes(seckey)
|
||||
@@ -79,12 +82,12 @@ def schnorr_sign(msg, seckey0):
|
||||
if not (1 <= seckey0 <= n - 1):
|
||||
raise ValueError('The secret key must be an integer in the range 1..n-1.')
|
||||
P = point_mul(G, seckey0)
|
||||
seckey = seckey0 if is_quad(y(P)) else n - seckey0
|
||||
seckey = seckey0 if has_square_y(P) else n - seckey0
|
||||
k0 = int_from_bytes(tagged_hash("BIPSchnorrDerive", bytes_from_int(seckey) + msg)) % n
|
||||
if k0 == 0:
|
||||
raise RuntimeError('Failure. This happens only with negligible probability.')
|
||||
R = point_mul(G, k0)
|
||||
k = n - k0 if not is_quad(y(R)) else k0
|
||||
k = n - k0 if not has_square_y(R) else k0
|
||||
e = int_from_bytes(tagged_hash("BIPSchnorr", bytes_from_point(R) + bytes_from_point(P) + msg)) % n
|
||||
return bytes_from_point(R) + bytes_from_int((k + e * seckey) % n)
|
||||
|
||||
@@ -104,7 +107,7 @@ def schnorr_verify(msg, pubkey, sig):
|
||||
return False
|
||||
e = int_from_bytes(tagged_hash("BIPSchnorr", sig[0:32] + pubkey + msg)) % n
|
||||
R = point_add(point_mul(G, s), point_mul(P, n - e))
|
||||
if R is None or not is_quad(y(R)) or x(R) != r:
|
||||
if R is None or not has_square_y(R) or x(R) != r:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ def vector2():
|
||||
msg = bytes_from_int(0x5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C)
|
||||
sig = schnorr_sign(msg, seckey)
|
||||
|
||||
# This singature vector would not verify if the implementer checked the
|
||||
# jacobi symbol of the X coordinate of R instead of the Y coordinate.
|
||||
# This signature vector would not verify if the implementer checked the
|
||||
# squareness of the X coordinate of R instead of the Y coordinate.
|
||||
R = point_from_bytes(sig[0:32])
|
||||
assert(jacobi(R[0]) != 1)
|
||||
assert(not is_square(R[0]))
|
||||
|
||||
return (bytes_from_int(seckey), pubkey_gen(seckey), msg, sig, "TRUE", None)
|
||||
|
||||
@@ -43,15 +43,14 @@ def vector3():
|
||||
sig = schnorr_sign(msg, seckey)
|
||||
return (bytes_from_int(seckey), pubkey_gen(seckey), msg, sig, "TRUE", "test fails if msg is reduced modulo p or n")
|
||||
|
||||
# Signs with a given nonce. Results in an invalid signature if y(kG) is not a
|
||||
# quadratic residue.
|
||||
# Signs with a given nonce. Results in an invalid signature if y(kG) is not a square
|
||||
def schnorr_sign_fixed_nonce(msg, seckey0, k):
|
||||
if len(msg) != 32:
|
||||
raise ValueError('The message must be a 32-byte array.')
|
||||
if not (1 <= seckey0 <= n - 1):
|
||||
raise ValueError('The secret key must be an integer in the range 1..n-1.')
|
||||
P = point_mul(G, seckey0)
|
||||
seckey = seckey0 if (jacobi(P[1]) == 1) else n - seckey0
|
||||
seckey = seckey0 if has_square_y(P) else n - seckey0
|
||||
R = point_mul(G, k)
|
||||
e = int_from_bytes(tagged_hash("BIPSchnorr", bytes_from_point(R) + bytes_from_point(P) + msg)) % n
|
||||
return bytes_from_point(R) + bytes_from_int((k + e * seckey) % n)
|
||||
@@ -84,9 +83,9 @@ def vector6():
|
||||
k = 3
|
||||
sig = schnorr_sign_fixed_nonce(msg, seckey, k)
|
||||
|
||||
# Y coordinate of R is not a quadratic residue
|
||||
# Y coordinate of R is not a square
|
||||
R = point_mul(G, k)
|
||||
assert(jacobi(R[1]) != 1)
|
||||
assert(not has_square_y(R))
|
||||
|
||||
return (None, pubkey_gen(seckey), msg, sig, "FALSE", "incorrect R residuosity")
|
||||
|
||||
@@ -121,7 +120,7 @@ def vector9():
|
||||
sig = schnorr_sign_fixed_nonce(msg, seckey, k)
|
||||
bytes_from_point.__code__ = bytes_from_point_tmp
|
||||
|
||||
return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 0")
|
||||
return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if has_square_y(inf) is defined as true and x(inf) as 0")
|
||||
|
||||
def bytes_from_point_inf1(P):
|
||||
if P == None:
|
||||
@@ -140,7 +139,7 @@ def vector10():
|
||||
sig = schnorr_sign_fixed_nonce(msg, seckey, k)
|
||||
bytes_from_point.__code__ = bytes_from_point_tmp
|
||||
|
||||
return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 1")
|
||||
return (None, pubkey_gen(seckey), msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if has_square_y(inf) is defined as true and x(inf) as 1")
|
||||
|
||||
# It's cryptographically impossible to create a test vector that fails if run
|
||||
# in an implementation which merely misses the check that sig[0:32] is an X
|
||||
|
||||
Reference in New Issue
Block a user