def __init__(self, hasher, option="ISO", fmt="DER"): if not option in ("ISO","ISOx","BSI","LIBSECP","Z"): raise ECPyException('ECSchnorr option not supported: %s'%option) if not fmt in list_formats(): raise ECPyException('ECSchnorr format not supported: %s'%fmt) self._hasher = hasher self.fmt = fmt self.maxtries = 100 self.option = option
def _do_sign(self, msg, pv_key, k): if (pv_key.curve == None): raise ECPyException('private key haz no curve') curve = pv_key.curve n = curve.order G = curve.generator size = curve.size >> 3 Q = G * k hasher = self._hasher() if self.option == "ISO": xQ = (Q.x).to_bytes(size, 'big') yQ = (Q.y).to_bytes(size, 'big') hasher.update(xQ + yQ + msg) r = hasher.digest() r = int.from_bytes(r, 'big') s = (k + r * pv_key.d) % n if r == 0 or s == 0: return None elif self.option == "ISOx": xQ = (Q.x).to_bytes(size, 'big') hasher.update(xQ + msg) r = hasher.digest() r = int.from_bytes(r, 'big') s = (k + r * pv_key.d) % n if r == 0 or s == 0: return None elif self.option == "BSI": xQ = Q.x.to_bytes(size, 'big') hasher.update(msg + xQ) r = hasher.digest() r = int.from_bytes(r, 'big') s = (k - r * pv_key.d) % n if r == 0 or s == 0: return None elif self.option == "LIBSECP": if Q.y & 1: k = n - k Q = G * k r = (Q.x % n).to_bytes(size, 'big') hasher.update(r + msg) h = hasher.digest() h = int.from_bytes(h, 'big') r = Q.x % n s = (k - h * pv_key.d) % n return encode_sig(r, s, self.fmt)
def sign_secp256k1(self, msg, pv_key, algo16=b""): """ Specific signature for SECP256K1 curve: https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki Args: msg (bytes) : the message hash to sign pv_key (ecpy.keys.ECPrivateKey): key to use for signing """ if pv_key.curve.name != 'secp256k1': raise ECPyException("specific 'secp256k1' curve signature") n = pv_key.curve.order size = pv_key.curve.size >> 3 # Let P = dG P = pv_key.curve.generator * pv_key.d # Let k = int(hash(bytes(d) || m)) mod data = pv_key.d.to_bytes(size, "big") + msg + algo16[:16] k = int.from_bytes(self._hasher(data).digest(), "big") % n # Fail if k = 0 if k == 0: raise ECPyException("signature failed") return self._do_sign(msg, pv_key, k)
def _do_sign(self, msg, pv_key, k): if (pv_key.curve == None): raise ECPyException('private key haz no curve') curve = pv_key.curve n = curve.order G = curve.generator size = (curve.size+7)//8 Q = G*k hasher = self._hasher() if self.option == "ISO": xQ = (Q.x).to_bytes(size,'big') yQ = (Q.y).to_bytes(size,'big') hasher.update(xQ+yQ+msg) r = hasher.digest() r = int.from_bytes(r,'big') if r % n == 0: return None s = (k+r*pv_key.d)%n if s==0: return None elif self.option == "ISOx": xQ = (Q.x).to_bytes(size,'big') hasher.update(xQ+msg) r = hasher.digest() r = int.from_bytes(r,'big') if r % n == 0: return None s = (k+r*pv_key.d)%n if s==0: return None elif self.option == "BSI": xQ = Q.x.to_bytes(size,'big') hasher.update(msg+xQ) r = hasher.digest() r = int.from_bytes(r,'big') if r%n == 0: return None s = (k-r*pv_key.d)%n if s==0: return None elif self.option == "LIBSECP": if Q.y & 1: k = n-k Q = G*k r = (Q.x%n).to_bytes(size,'big') hasher.update(r+msg) h = hasher.digest() h = int.from_bytes(h,'big') if h > n: return None r = Q.x % n s = (k - h*pv_key.d)%n elif self.option == "Z": if Q.y & 1: xQ = b'\x03'+Q.x.to_bytes(size,'big') else : xQ = b'\x02'+Q.x.to_bytes(size,'big') pu_key = pv_key.get_public_key() if pu_key.W.y & 1: xPub = b'\x03'+pu_key.W.x.to_bytes(size,'big') else : xPub = b'\x02'+pu_key.W.x.to_bytes(size,'big') hasher.update(xQ+xPub+msg) r = hasher.digest() r = int.from_bytes(r,'big') % n if r % n == 0: return None s = (k - r*pv_key.d) %n if s==0: return None return encode_sig(r, s, self.fmt)
def _do_sign(self, msg, pv_key, k): if (pv_key.curve == None): raise ECPyException('private key has no curve') curve = pv_key.curve n = curve.order G = curve.generator size = curve.size >> 3 Q = G * k hasher = self._hasher() if self.option == "ISO": xQ = (Q.x).to_bytes(size, 'big') yQ = (Q.y).to_bytes(size, 'big') hasher.update(xQ + yQ + msg) r = hasher.digest() r = int.from_bytes(r, 'big') s = (k + r * pv_key.d) % n if r == 0 or s == 0: return None elif self.option == "ISOx": xQ = (Q.x).to_bytes(size, 'big') hasher.update(xQ + msg) r = hasher.digest() r = int.from_bytes(r, 'big') s = (k + r * pv_key.d) % n if r == 0 or s == 0: return None elif self.option == "BSI": xQ = Q.x.to_bytes(size, 'big') hasher.update(msg + xQ) r = hasher.digest() r = int.from_bytes(r, 'big') s = (k - r * pv_key.d) % n if r == 0 or s == 0: return None elif self.option == "LIBSECP": if Q.y & 1: k = n - k Q = G * k r = (Q.x % n).to_bytes(size, 'big') hasher.update(r + msg) h = hasher.digest() h = int.from_bytes(h, 'big') r = Q.x % n s = (k - h * pv_key.d) % n elif self.option == "Z": if Q.y & 1: xQ = b'\x03' + Q.x.to_bytes(size, 'big') else: xQ = b'\x02' + Q.x.to_bytes(size, 'big') pu_key = pv_key.get_public_key() if pu_key.W.y & 1: xPub = b'\x03' + pu_key.W.x.to_bytes(size, 'big') else: xPub = b'\x02' + pu_key.W.x.to_bytes(size, 'big') hasher.update(xQ + xPub + msg) r = hasher.digest() r = int.from_bytes(r, 'big') % n s = (k - r * pv_key.d) % n if r == 0 or s == 0: return None # https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki elif self.option == "SECP256K1": # R = Q... # Let k = k' if jacobi(y(R)) = 1, otherwise let k = n - k' k = k if _jacobi(Q.y, pv_key.curve.field) == 1 else n - k # Let P = d'G P = G * pv_key.d # Let e = int(hash(bytes(R) || bytes(P) || m)) mod n e = int.from_bytes( self._hasher(Q.x.to_bytes(size, "big") + P.serialize() + msg).digest(), "big") % n # The signature is bytes(R) || bytes((k + ed) mod n) r = Q.x % n s = (k + e * pv_key.d) % n return encode_sig(r, s, self.fmt, 0 if self.fmt not in ["RAW", "EDDSA"] else size)