1
1
# Copyright (c) 2019 Pieter Wuille
2
-
2
+ # Distributed under the MIT software license, see the accompanying
3
+ # file COPYING or http://www.opensource.org/licenses/mit-license.php.
3
4
"""Test-only secp256k1 elliptic curve implementation
4
5
5
6
WARNING: This code is slow, uses bad randomness, does not properly protect
6
7
keys, and is trivially vulnerable to side channel attacks. Do not use for
7
- anything but tests.
8
- """
9
-
8
+ anything but tests."""
10
9
import random
11
10
12
11
def modinv (a , n ):
13
12
"""Compute the modular inverse of a modulo n
14
13
15
- See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers
14
+ See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers.
16
15
"""
17
16
t1 , t2 = 0 , 1
18
17
r1 , r2 = n , a
@@ -30,8 +29,9 @@ def jacobi_symbol(n, k):
30
29
"""Compute the Jacobi symbol of n modulo k
31
30
32
31
See http://en.wikipedia.org/wiki/Jacobi_symbol
33
- """
34
- assert k > 0 and k & 1
32
+
33
+ For our application k is always prime, so this is the same as the Legendre symbol."""
34
+ assert k > 0 and k & 1 , "jacobi symbol is only defined for positive odd k"
35
35
n %= k
36
36
t = 0
37
37
while n != 0 :
@@ -47,11 +47,18 @@ def jacobi_symbol(n, k):
47
47
return 0
48
48
49
49
def modsqrt (a , p ):
50
- """Compute the square root of a modulo p
50
+ """Compute the square root of a modulo p when p % 4 = 3.
51
51
52
- For p = 3 mod 4, if a square root exists, it is equal to a**((p+1)/4) mod p.
52
+ The Tonelli-Shanks algorithm can be used. See https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm
53
+
54
+ Limiting this function to only work for p % 4 = 3 means we don't need to
55
+ iterate through the loop. The highest n such that p - 1 = 2^n Q with Q odd
56
+ is n = 1. Therefore Q = (p-1)/2 and sqrt = a^((Q+1)/2) = a^((p+1)/4)
57
+
58
+ secp256k1's is defined over field of size 2**256 - 2**32 - 977, which is 3 mod 4.
53
59
"""
54
- assert (p % 4 == 3 ) # Only p = 3 mod 4 is implemented
60
+ if p % 4 != 3 :
61
+ raise NotImplementedError ("modsqrt only implemented for p % 4 = 3" )
55
62
sqrt = pow (a , (p + 1 )// 4 , p )
56
63
if pow (sqrt , 2 , p ) == a % p :
57
64
return sqrt
@@ -65,7 +72,9 @@ def __init__(self, p, a, b):
65
72
self .b = b % p
66
73
67
74
def affine (self , p1 ):
68
- """Convert a Jacobian point tuple p1 to affine form, or None if at infinity."""
75
+ """Convert a Jacobian point tuple p1 to affine form, or None if at infinity.
76
+
77
+ An affine point is represented as the Jacobian (x, y, 1)"""
69
78
x1 , y1 , z1 = p1
70
79
if z1 == 0 :
71
80
return None
@@ -101,7 +110,9 @@ def lift_x(self, x):
101
110
return (x , y , 1 )
102
111
103
112
def double (self , p1 ):
104
- """Double a Jacobian tuple p1"""
113
+ """Double a Jacobian tuple p1
114
+
115
+ See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Doubling"""
105
116
x1 , y1 , z1 = p1
106
117
if z1 == 0 :
107
118
return (0 , 1 , 0 )
@@ -119,10 +130,13 @@ def double(self, p1):
119
130
return (x2 , y2 , z2 )
120
131
121
132
def add_mixed (self , p1 , p2 ):
122
- """Add a Jacobian tuple p1 and an affine tuple p2"""
133
+ """Add a Jacobian tuple p1 and an affine tuple p2
134
+
135
+ See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Addition (with affine point)"""
123
136
x1 , y1 , z1 = p1
124
137
x2 , y2 , z2 = p2
125
138
assert (z2 == 1 )
139
+ # Adding to the point at infinity is a no-op
126
140
if z1 == 0 :
127
141
return p2
128
142
z1_2 = (z1 ** 2 ) % self .p
@@ -131,7 +145,9 @@ def add_mixed(self, p1, p2):
131
145
s2 = (y2 * z1_3 ) % self .p
132
146
if x1 == u2 :
133
147
if (y1 != s2 ):
148
+ # p1 and p2 are inverses. Return the point at infinity.
134
149
return (0 , 1 , 0 )
150
+ # p1 == p2. The formulas below fail when the two points are equal.
135
151
return self .double (p1 )
136
152
h = u2 - x1
137
153
r = s2 - y1
@@ -144,13 +160,17 @@ def add_mixed(self, p1, p2):
144
160
return (x3 , y3 , z3 )
145
161
146
162
def add (self , p1 , p2 ):
147
- """Add two Jacobian tuples p1 and p2"""
163
+ """Add two Jacobian tuples p1 and p2
164
+
165
+ See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Addition"""
148
166
x1 , y1 , z1 = p1
149
167
x2 , y2 , z2 = p2
168
+ # Adding the point at infinity is a no-op
150
169
if z1 == 0 :
151
170
return p2
152
171
if z2 == 0 :
153
172
return p1
173
+ # Adding an Affine to a Jacobian is more efficient since we save field multiplications and squarings when z = 1
154
174
if z1 == 1 :
155
175
return self .add_mixed (p2 , p1 )
156
176
if z2 == 1 :
@@ -165,7 +185,9 @@ def add(self, p1, p2):
165
185
s2 = (y2 * z1_3 ) % self .p
166
186
if u1 == u2 :
167
187
if (s1 != s2 ):
188
+ # p1 and p2 are inverses. Return the point at infinity.
168
189
return (0 , 1 , 0 )
190
+ # p1 == p2. The formulas below fail when the two points are equal.
169
191
return self .double (p1 )
170
192
h = u2 - u1
171
193
r = s2 - s1
@@ -214,6 +236,8 @@ def set(self, data):
214
236
x = int .from_bytes (data [1 :33 ], 'big' )
215
237
if SECP256K1 .is_x_coord (x ):
216
238
p = SECP256K1 .lift_x (x )
239
+ # if the oddness of the y co-ord isn't correct, find the other
240
+ # valid y
217
241
if (p [1 ] & 1 ) != (data [0 ] & 1 ):
218
242
p = SECP256K1 .negate (p )
219
243
self .p = p
@@ -243,8 +267,14 @@ def get_bytes(self):
243
267
return bytes ([0x04 ]) + p [0 ].to_bytes (32 , 'big' ) + p [1 ].to_bytes (32 , 'big' )
244
268
245
269
def verify_ecdsa (self , sig , msg , low_s = True ):
246
- """Verify a strictly DER-encoded ECDSA signature against this pubkey."""
270
+ """Verify a strictly DER-encoded ECDSA signature against this pubkey.
271
+
272
+ See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
273
+ ECDSA verifier algorithm"""
247
274
assert (self .valid )
275
+
276
+ # Extract r and s from the DER formatted signature. Return false for
277
+ # any DER encoding errors.
248
278
if (sig [1 ] + 2 != len (sig )):
249
279
return False
250
280
if (len (sig ) < 4 ):
@@ -275,11 +305,15 @@ def verify_ecdsa(self, sig, msg, low_s=True):
275
305
if (slen > 1 and (sig [6 + rlen ] == 0 ) and not (sig [7 + rlen ] & 0x80 )):
276
306
return False
277
307
s = int .from_bytes (sig [6 + rlen :6 + rlen + slen ], 'big' )
308
+
309
+ # Verify that r and s are within the group order
278
310
if r < 1 or s < 1 or r >= SECP256K1_ORDER or s >= SECP256K1_ORDER :
279
311
return False
280
312
if low_s and s >= SECP256K1_ORDER_HALF :
281
313
return False
282
314
z = int .from_bytes (msg , 'big' )
315
+
316
+ # Run verifier algorithm on r, s
283
317
w = modinv (s , SECP256K1_ORDER )
284
318
u1 = z * w % SECP256K1_ORDER
285
319
u2 = r * w % SECP256K1_ORDER
@@ -331,7 +365,10 @@ def get_pubkey(self):
331
365
return ret
332
366
333
367
def sign_ecdsa (self , msg , low_s = True ):
334
- """Construct a DER-encoded ECDSA signature with this key."""
368
+ """Construct a DER-encoded ECDSA signature with this key.
369
+
370
+ See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
371
+ ECDSA signer algorithm."""
335
372
assert (self .valid )
336
373
z = int .from_bytes (msg , 'big' )
337
374
# Note: no RFC6979, but a simple random nonce (some tests rely on distinct transactions for the same operation)
@@ -341,6 +378,9 @@ def sign_ecdsa(self, msg, low_s=True):
341
378
s = (modinv (k , SECP256K1_ORDER ) * (z + self .secret * r )) % SECP256K1_ORDER
342
379
if low_s and s > SECP256K1_ORDER_HALF :
343
380
s = SECP256K1_ORDER - s
381
+ # Represent in DER format. The byte representations of r and s have
382
+ # length rounded up (255 bits becomes 32 bytes and 256 bits becomes 33
383
+ # bytes).
344
384
rb = r .to_bytes ((r .bit_length () + 8 ) // 8 , 'big' )
345
385
sb = s .to_bytes ((s .bit_length () + 8 ) // 8 , 'big' )
346
386
return b'\x30 ' + bytes ([4 + len (rb ) + len (sb ), 2 , len (rb )]) + rb + bytes ([2 , len (sb )]) + sb
0 commit comments