75
75
# this specifies the curve used with ECDSA.
76
76
NID_secp256k1 = 714 # from openssl/obj_mac.h
77
77
78
+ SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
79
+ SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2
80
+
78
81
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
79
82
def _check_result (val , func , args ):
80
83
if val == 0 :
@@ -147,7 +150,7 @@ def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
147
150
r = self .get_raw_ecdh_key (other_pubkey )
148
151
return kdf (r )
149
152
150
- def sign (self , hash ):
153
+ def sign (self , hash , low_s = True ):
151
154
# FIXME: need unit tests for below cases
152
155
if not isinstance (hash , bytes ):
153
156
raise TypeError ('Hash must be bytes instance; got %r' % hash .__class__ )
@@ -159,7 +162,25 @@ def sign(self, hash):
159
162
mb_sig = ctypes .create_string_buffer (sig_size0 .value )
160
163
result = ssl .ECDSA_sign (0 , hash , len (hash ), mb_sig , ctypes .byref (sig_size0 ), self .k )
161
164
assert 1 == result
162
- return mb_sig .raw [:sig_size0 .value ]
165
+ assert mb_sig .raw [0 ] == 0x30
166
+ assert mb_sig .raw [1 ] == sig_size0 .value - 2
167
+ total_size = mb_sig .raw [1 ]
168
+ assert mb_sig .raw [2 ] == 2
169
+ r_size = mb_sig .raw [3 ]
170
+ assert mb_sig .raw [4 + r_size ] == 2
171
+ s_size = mb_sig .raw [5 + r_size ]
172
+ s_value = int .from_bytes (mb_sig .raw [6 + r_size :6 + r_size + s_size ], byteorder = 'big' )
173
+ if (not low_s ) or s_value <= SECP256K1_ORDER_HALF :
174
+ return mb_sig .raw [:sig_size0 .value ]
175
+ else :
176
+ low_s_value = SECP256K1_ORDER - s_value
177
+ low_s_bytes = (low_s_value ).to_bytes (33 , byteorder = 'big' )
178
+ while len (low_s_bytes ) > 1 and low_s_bytes [0 ] == 0 and low_s_bytes [1 ] < 0x80 :
179
+ low_s_bytes = low_s_bytes [1 :]
180
+ new_s_size = len (low_s_bytes )
181
+ new_total_size_byte = (total_size + new_s_size - s_size ).to_bytes (1 ,byteorder = 'big' )
182
+ new_s_size_byte = (new_s_size ).to_bytes (1 ,byteorder = 'big' )
183
+ return b'\x30 ' + new_total_size_byte + mb_sig .raw [2 :5 + r_size ] + new_s_size_byte + low_s_bytes
163
184
164
185
def verify (self , hash , sig ):
165
186
"""Verify a DER signature"""
0 commit comments