Skip to content

Commit 33308e7

Browse files
committed
Merge BIPs 340-342
2 parents 6a80232 + 97ef678 commit 33308e7

File tree

10 files changed

+1162
-0
lines changed

10 files changed

+1162
-0
lines changed

README.mediawiki

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,27 @@ Those proposing changes should consider that ultimately consent may rest with th
931931
| Gleb Naumenko, Pieter Wuille
932932
| Standard
933933
| Draft
934+
|-
935+
| [[bip-0340.mediawiki|340]]
936+
|
937+
| Schnorr Signatures for secp256k1
938+
| Pieter Wuille, Jonas Nick, Tim Ruffing
939+
| Standard
940+
| Draft
941+
|-
942+
| [[bip-0341.mediawiki|341]]
943+
| Consensus (soft fork)
944+
| Taproot: SegWit version 1 spending rules
945+
| Pieter Wuille, Jonas Nick, Anthony Towns
946+
| Standard
947+
| Draft
948+
|-
949+
| [[bip-0342.mediawiki|342]]
950+
| Consensus (soft fork)
951+
| Validation of Taproot Scripts
952+
| Pieter Wuille, Jonas Nick, Anthony Towns
953+
| Standard
954+
| Draft
934955
|}
935956

936957
<!-- IMPORTANT! See the instructions at the top of this page, do NOT JUST add BIPs here! -->

bip-0340.mediawiki

Lines changed: 263 additions & 0 deletions
Large diffs are not rendered by default.

bip-0340/reference.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import hashlib
2+
import binascii
3+
4+
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
5+
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
6+
7+
# Points are tuples of X and Y coordinates and the point at infinity is
8+
# represented by the None keyword.
9+
G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
10+
11+
# This implementation can be sped up by storing the midstate after hashing
12+
# tag_hash instead of rehashing it all the time.
13+
def tagged_hash(tag, msg):
14+
tag_hash = hashlib.sha256(tag.encode()).digest()
15+
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
16+
17+
def is_infinity(P):
18+
return P is None
19+
20+
def x(P):
21+
return P[0]
22+
23+
def y(P):
24+
return P[1]
25+
26+
def point_add(P1, P2):
27+
if (P1 is None):
28+
return P2
29+
if (P2 is None):
30+
return P1
31+
if (x(P1) == x(P2) and y(P1) != y(P2)):
32+
return None
33+
if (P1 == P2):
34+
lam = (3 * x(P1) * x(P1) * pow(2 * y(P1), p - 2, p)) % p
35+
else:
36+
lam = ((y(P2) - y(P1)) * pow(x(P2) - x(P1), p - 2, p)) % p
37+
x3 = (lam * lam - x(P1) - x(P2)) % p
38+
return (x3, (lam * (x(P1) - x3) - y(P1)) % p)
39+
40+
def point_mul(P, n):
41+
R = None
42+
for i in range(256):
43+
if ((n >> i) & 1):
44+
R = point_add(R, P)
45+
P = point_add(P, P)
46+
return R
47+
48+
def bytes_from_int(x):
49+
return x.to_bytes(32, byteorder="big")
50+
51+
def bytes_from_point(P):
52+
return bytes_from_int(x(P))
53+
54+
def point_from_bytes(b):
55+
x = int_from_bytes(b)
56+
if x >= p:
57+
return None
58+
y_sq = (pow(x, 3, p) + 7) % p
59+
y = pow(y_sq, (p + 1) // 4, p)
60+
if pow(y, 2, p) != y_sq:
61+
return None
62+
return [x, y]
63+
64+
def int_from_bytes(b):
65+
return int.from_bytes(b, byteorder="big")
66+
67+
def hash_sha256(b):
68+
return hashlib.sha256(b).digest()
69+
70+
def is_square(x):
71+
return pow(x, (p - 1) // 2, p) == 1
72+
73+
def has_square_y(P):
74+
return not is_infinity(P) and is_square(y(P))
75+
76+
def pubkey_gen(seckey):
77+
x = int_from_bytes(seckey)
78+
if not (1 <= x <= n - 1):
79+
raise ValueError('The secret key must be an integer in the range 1..n-1.')
80+
P = point_mul(G, x)
81+
return bytes_from_point(P)
82+
83+
def schnorr_sign(msg, seckey0):
84+
if len(msg) != 32:
85+
raise ValueError('The message must be a 32-byte array.')
86+
seckey0 = int_from_bytes(seckey0)
87+
if not (1 <= seckey0 <= n - 1):
88+
raise ValueError('The secret key must be an integer in the range 1..n-1.')
89+
P = point_mul(G, seckey0)
90+
seckey = seckey0 if has_square_y(P) else n - seckey0
91+
k0 = int_from_bytes(tagged_hash("BIPSchnorrDerive", bytes_from_int(seckey) + msg)) % n
92+
if k0 == 0:
93+
raise RuntimeError('Failure. This happens only with negligible probability.')
94+
R = point_mul(G, k0)
95+
k = n - k0 if not has_square_y(R) else k0
96+
e = int_from_bytes(tagged_hash("BIPSchnorr", bytes_from_point(R) + bytes_from_point(P) + msg)) % n
97+
return bytes_from_point(R) + bytes_from_int((k + e * seckey) % n)
98+
99+
def schnorr_verify(msg, pubkey, sig):
100+
if len(msg) != 32:
101+
raise ValueError('The message must be a 32-byte array.')
102+
if len(pubkey) != 32:
103+
raise ValueError('The public key must be a 32-byte array.')
104+
if len(sig) != 64:
105+
raise ValueError('The signature must be a 64-byte array.')
106+
P = point_from_bytes(pubkey)
107+
if (P is None):
108+
return False
109+
r = int_from_bytes(sig[0:32])
110+
s = int_from_bytes(sig[32:64])
111+
if (r >= p or s >= n):
112+
return False
113+
e = int_from_bytes(tagged_hash("BIPSchnorr", sig[0:32] + pubkey + msg)) % n
114+
R = point_add(point_mul(G, s), point_mul(P, n - e))
115+
if R is None or not has_square_y(R) or x(R) != r:
116+
return False
117+
return True
118+
119+
#
120+
# The following code is only used to verify the test vectors.
121+
#
122+
import csv
123+
124+
def test_vectors():
125+
all_passed = True
126+
with open('test-vectors.csv', newline='') as csvfile:
127+
reader = csv.reader(csvfile)
128+
reader.__next__()
129+
for row in reader:
130+
(index, seckey, pubkey, msg, sig, result, comment) = row
131+
pubkey = bytes.fromhex(pubkey)
132+
msg = bytes.fromhex(msg)
133+
sig = bytes.fromhex(sig)
134+
result = result == 'TRUE'
135+
print('\nTest vector #%-3i: ' % int(index))
136+
if seckey != '':
137+
seckey = bytes.fromhex(seckey)
138+
pubkey_actual = pubkey_gen(seckey)
139+
if pubkey != pubkey_actual:
140+
print(' * Failed key generation.')
141+
print(' Expected key:', pubkey.hex().upper())
142+
print(' Actual key:', pubkey_actual.hex().upper())
143+
sig_actual = schnorr_sign(msg, seckey)
144+
if sig == sig_actual:
145+
print(' * Passed signing test.')
146+
else:
147+
print(' * Failed signing test.')
148+
print(' Expected signature:', sig.hex().upper())
149+
print(' Actual signature:', sig_actual.hex().upper())
150+
all_passed = False
151+
result_actual = schnorr_verify(msg, pubkey, sig)
152+
if result == result_actual:
153+
print(' * Passed verification test.')
154+
else:
155+
print(' * Failed verification test.')
156+
print(' Expected verification result:', result)
157+
print(' Actual verification result:', result_actual)
158+
if comment:
159+
print(' Comment:', comment)
160+
all_passed = False
161+
print()
162+
if all_passed:
163+
print('All test vectors passed.')
164+
else:
165+
print('Some test vectors failed.')
166+
return all_passed
167+
168+
if __name__ == '__main__':
169+
test_vectors()

bip-0340/speedup-batch.png

11.6 KB
Loading

bip-0340/test-vectors.csv

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
index,secret key,public key,message,signature,verification result,comment
2+
0,0000000000000000000000000000000000000000000000000000000000000001,79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0000000000000000000000000000000000000000000000000000000000000000,528F745793E8472C0329742A463F59E58F3A3F1A4AC09C28F6F8514D4D0322A258BD08398F82CF67B812AB2C7717CE566F877C2F8795C846146978E8F04782AE,TRUE,
3+
1,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,667C2F778E0616E611BD0C14B8A600C5884551701A949EF0EBFD72D452D64E844160BCFC3F466ECB8FACD19ADE57D8699D74E7207D78C6AEDC3799B52A8E0598,TRUE,
4+
2,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9,DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8,5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,2D941B38E32624BF0AC7669C0971B990994AF6F9B18426BF4F4E7EC10E6CDF386CF646C6DDAFCFA7F1993EEB2E4D66416AEAD1DDAE2F22D63CAD901412D116C6,TRUE,
5+
3,0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710,25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,8BD2C11604B0A87A443FCC2E5D90E5328F934161B18864FB48CE10CB59B45FB9B5B2A0F129BD88F5BDC05D5C21E5C57176B913002335784F9777A24BD317CD36,TRUE,test fails if msg is reduced modulo p or n
6+
4,,D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63EE374AC7FAE927D334CCB190F6FB8FD27A2DDC639CCEE46D43F113A4035A2C7F,TRUE,
7+
5,,EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,667C2F778E0616E611BD0C14B8A600C5884551701A949EF0EBFD72D452D64E844160BCFC3F466ECB8FACD19ADE57D8699D74E7207D78C6AEDC3799B52A8E0598,FALSE,public key not on the curve
8+
6,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9935554D1AA5F0374E5CDAACB3925035C7C169B27C4426DF0A6B19AF3BAEAB138,FALSE,has_square_y(R) is false
9+
7,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,10AC49A6A2EBF604189C5F40FC75AF2D42D77DE9A2782709B1EB4EAF1CFE9108D7003B703A3499D5E29529D39BA040A44955127140F81A8A89A96F992AC0FE79,FALSE,negated message
10+
8,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,667C2F778E0616E611BD0C14B8A600C5884551701A949EF0EBFD72D452D64E84BE9F4303C0B9913470532E6521A827951D39F5C631CFD98CE39AC4D7A5A83BA9,FALSE,negated s value
11+
9,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,000000000000000000000000000000000000000000000000000000000000000099D2F0EBC2996808208633CD9926BF7EC3DAB73DAAD36E85B3040A698E6D1CE0,FALSE,sG - eP is infinite. Test fails in single verification if has_square_y(inf) is defined as true and x(inf) as 0
12+
10,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,000000000000000000000000000000000000000000000000000000000000000124E81D89F01304695CE943F7D5EBD00EF726A0864B4FF33895B4E86BEADC5456,FALSE,sG - eP is infinite. Test fails in single verification if has_square_y(inf) is defined as true and x(inf) as 1
13+
11,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D4160BCFC3F466ECB8FACD19ADE57D8699D74E7207D78C6AEDC3799B52A8E0598,FALSE,sig[0:32] is not an X coordinate on the curve
14+
12,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F4160BCFC3F466ECB8FACD19ADE57D8699D74E7207D78C6AEDC3799B52A8E0598,FALSE,sig[0:32] is equal to field size
15+
13,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,667C2F778E0616E611BD0C14B8A600C5884551701A949EF0EBFD72D452D64E84FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,sig[32:64] is equal to curve order
16+
14,,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,667C2F778E0616E611BD0C14B8A600C5884551701A949EF0EBFD72D452D64E844160BCFC3F466ECB8FACD19ADE57D8699D74E7207D78C6AEDC3799B52A8E0598,FALSE,public key is not a valid X coordinate because it exceeds the field size

0 commit comments

Comments
 (0)