Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
"""
Zilliqa schnorr signature support
"""
import secrets
from hashlib import sha256
from typing import Optional
from fastecdsa import keys
from fastecdsa import point
from fastecdsa import curve
CURVE = curve.secp256k1
CURVE_BITS = 256
ENCODED_SIZE = CURVE_BITS // 8
SECP256K1_TAG_PUBKEY_EVEN = b"\x02"
SECP256K1_TAG_PUBKEY_ODD = b"\x03"
SECP256K1_TAG_PUBKEY_UNCOMPRESSED = b"\x04"
def gen_private_key() -> int:
return keys.gen_private_key(CURVE)
def get_public_key(private_key: int) -> point.Point:
return keys.get_public_key(private_key, CURVE)
def pub_key_to_point(pub_key: str) -> Point:
'''
Given a public key, return a Point object
(Used to verify signatures)
'''
xs, ys = pub_key.split('x')
return Point(int(xs, 16), int(ys, 16), curve=curve.P256)
def is_sig_valid(signature: str, pub_key: str, msg: str) -> bool:
'''
Given a signature, public key, and a message,
check if the signature is valid
'''
r, s = signature.split('x')
p = pub_key_to_point(pub_key)
return ecdsa.verify((int(r, 16), int(s, 16)), msg, p)
def get_public_key(self) -> PublicKey:
public_key_impl = keys.get_public_key(self.impl, self.curve)
return ECCPublicKey(public_key_impl, self.curve)
def sign_with_k(bytes_msg: bytes,
bytes_private: bytes,
k: int) -> Optional[bytes]:
private_key = int.from_bytes(bytes_private, "big")
order = CURVE.q
Q = CURVE.G * k
bytes_Q_x = encode_public(Q.x, Q.y)
pub_key = keys.get_public_key(private_key, CURVE)
bytes_pub_x = encode_public(pub_key.x, pub_key.y)
hasher = sha256()
hasher.update(bytes_Q_x + bytes_pub_x + bytes_msg)
r = hasher.digest()
r = int.from_bytes(r, "big") % order
s = (k - r * private_key) % order
if r == 0 or s == 0:
return None
return encode_signature(r, s)
def derive_secp256k1_master_keys(self):
"""
Uses the XRPL's convoluted key derivation process to get the
secp256k1 master keypair for this seed value.
Saves the values to the object for later reference.
"""
root_sec_i = secp256k1_secret_key_from(self.bytes)
root_pub_point = keys.get_public_key(root_sec_i, curve.secp256k1)
root_pub_b = compress_secp256k1_public(root_pub_point)
fam_b = bytes(4) # Account families are unused; just 4 bytes of zeroes
inter_pk_i = secp256k1_secret_key_from( b''.join([root_pub_b, fam_b]) )
inter_pub_point = keys.get_public_key(inter_pk_i, curve.secp256k1)
# Secret keys are ints, so just add them mod the secp256k1 group order
master_sec_i = (root_sec_i + inter_pk_i) % curve.secp256k1.q
# Public keys are points, so the fastecdsa lib handles adding them
master_pub_point = root_pub_point + inter_pub_point
self._secp256k1_sec = master_sec_i.to_bytes(32, byteorder="big", signed=False)
self._secp256k1_pub = compress_secp256k1_public(master_pub_point)
self._secp256k1_root_pub = root_pub_b
# Saving the full key to make it easier to sign things later
self._secp256k1_full = master_pub_point
def ec_point(m):
"""
Method for elliptic curve multiplication on the secp256k1 curve. Multiply Generator point G with m
:param m: A point on the elliptic curve
:type m: int
:return Point: Point multiplied by generator G
"""
m = int(m)
if USE_FASTECDSA:
return fastecdsa_keys.get_public_key(m, fastecdsa_secp256k1)
else:
point = secp256k1_generator
point *= m
return point
def get_pubkey_hex( privatekey_hex ):
"""
Get the uncompressed hex form of a private key
"""
if len(privatekey_hex) > 64:
assert privatekey_hex[-2:] == '01'
privatekey_hex = privatekey_hex[:64]
# get hex public key
privatekey_int = int(privatekey_hex, 16)
pubkey_parts = fastecdsa.keys.get_public_key( privatekey_int, curve=fastecdsa.curve.secp256k1 )
pubkey_hex = "04{:064x}{:064x}".format(pubkey_parts[0], pubkey_parts[1])
return pubkey_hex
def derive_secp256k1_master_keys(self):
"""
Uses the XRPL's convoluted key derivation process to get the
secp256k1 master keypair for this seed value.
Saves the values to the object for later reference.
"""
root_sec_i = secp256k1_secret_key_from(self.bytes)
root_pub_point = keys.get_public_key(root_sec_i, curve.secp256k1)
root_pub_b = compress_secp256k1_public(root_pub_point)
fam_b = bytes(4) # Account families are unused; just 4 bytes of zeroes
inter_pk_i = secp256k1_secret_key_from( b''.join([root_pub_b, fam_b]) )
inter_pub_point = keys.get_public_key(inter_pk_i, curve.secp256k1)
# Secret keys are ints, so just add them mod the secp256k1 group order
master_sec_i = (root_sec_i + inter_pk_i) % curve.secp256k1.q
# Public keys are points, so the fastecdsa lib handles adding them
master_pub_point = root_pub_point + inter_pub_point
self._secp256k1_sec = master_sec_i.to_bytes(32, byteorder="big", signed=False)
self._secp256k1_pub = compress_secp256k1_public(master_pub_point)
self._secp256k1_root_pub = root_pub_b
# Saving the full key to make it easier to sign things later
self._secp256k1_full = master_pub_point
def get_pub_key(priv_key: str) -> str:
'''
Returns the public key associated with
the private key. 'x' is used to split
up the x and y coordinates of the public
key
'''
pub_key = keys.get_public_key(int(priv_key, 16), curve.P256)
return '{:x}'.format(pub_key.x) + 'x' + '{:x}'.format(pub_key.y)