def privkey_to_pubkey_inner(priv, usehex): '''Take 32/33 byte raw private key as input. If 32 bytes, return compressed (33 byte) raw public key. If 33 bytes, read the final byte as compression flag, and return compressed/uncompressed public key as appropriate.''' compressed, priv = read_privkey(priv) #secp256k1 checks for validity of key value. if sys.version_info >= (3, 0): newpriv = secp256k1.PrivateKey(secret=native_bytes(priv)) else: newpriv = secp256k1.PrivateKey(secret=bytes_to_native_str(priv)) return newpriv.public_key.format(compressed)
def getG(compressed=True): """Returns the public key binary representation of secp256k1 G """ priv = b"\x00" * 31 + b"\x01" G = secp256k1.PrivateKey(priv).public_key.format(compressed) return G
def signHash(self, msg_hash_bytes: bytes): if len(msg_hash_bytes) != 32: raise ValueError("The message hash must be exactly 32-bytes") key = self._raw_key signature_bytes = coincurve.PrivateKey(key).sign_recoverable( msg_hash_bytes, hasher=None, ) if len(signature_bytes) != 65: raise ValueError( "Unexpected signature format. Must be length 65 byte string") r = signature_bytes[0:32] s = signature_bytes[32:64] v = signature_bytes[64:65] v = ord(v) v = to_eth_v(v) v = bytes([v]) eth_signature_bytes = r + s + v return { 'messageHash': msg_hash_bytes, 'signature': HexBytes(eth_signature_bytes) }
def get_random_compact_signature(): sk = cc.PrivateKey(get_random_sk_bytes()) message = get_random_bytes(32) # The recoverable signature is a compact signature with trailing recovery # byte. The trailing byte is removed since it is not expected by the constructor return sk.sign_recoverable(message)[:-1]
def __init__(self, private_key=None): if private_key is not None: self.__private_key__ = coincurve.PrivateKey.from_hex(private_key) else: print("Creating new key pair") self.__private_key__ = coincurve.PrivateKey() self.__public_key__ = self.__private_key__.public_key
def __init__(self, private_key=None): if private_key is not None: self.__private_key__ = coincurve.PrivateKey.from_hex(private_key) else: logger.info("No private key provided. Generating new key pair.") self.__private_key__ = coincurve.PrivateKey() self.__public_key__ = self.__private_key__.public_key
def Init(self, request, context): node = Node() node.hsm_secret = request.hsm_secret.data # on chain wallet hkdf = HKDF(key=node.hsm_secret) r = hkdf.extract_key(info='bip32 seed'.encode(), length=32) logger.debug("bip32_key seed: %s" % r.hex()) node.bip32_key = BIP32.from_seed(r, network=self.network) # node pubkey, node msg sign r = hkdf.extract_key(info='nodeid'.encode(), length=32) node.node_privkey = r node.node_pk = r logger.info("new node privkey %s" % r.hex()) node_pk = coincurve.PrivateKey(secret=r) node.pubkey = node_pk.public_key.format() node.nodeid = binascii.hexlify(node.pubkey) logger.info("new node id %s" % node.nodeid) # channel secret_base node.secret_base = hkdf.extract_key(info='peer seed'.encode(), length=32) logger.debug("new channel secret base %s" % node.secret_base.hex()) if not self.nodes.get(node.pubkey) or request.coldstart: self.nodes[node.pubkey] = node reply = remotesigner_pb2.InitReply() reply.node_id.data = node.pubkey return reply
def ecdsa_raw_sign(msg, priv, rawmsg=False, formsg=False): '''Take the binary message msg and sign it with the private key priv. If rawmsg is True, no sha256 hash is applied to msg before signing. In this case, msg must be a precalculated hash (256 bit). If rawmsg is False, the secp256k1 lib will hash the message as part of the ECDSA-SHA256 signing algo. Return value: the calculated signature.''' if rawmsg and len(msg) != 32: raise Exception("Invalid hash input to ECDSA raw sign.") compressed, p = read_privkey(priv) newpriv = secp256k1.PrivateKey(p) if formsg: sig = newpriv.sign_recoverable(msg) return sig else: if rawmsg: sig = newpriv.sign(msg, hasher=None) else: sig = newpriv.sign(msg) return sig
def raw_per_commit_secret(self, n: int) -> coincurve.PrivateKey: # BOLT #3: # The first secret used: # - MUST be index 281474976710655, # - and from there, the index is decremented. if n > 281474976710655: raise ValueError("48 bits is all you get!") index = 281474976710655 - n # BOLT #3: # generate_from_seed(seed, I): # P = seed # for B in 47 down to 0: # if B set in I: # flip(B) in P # P = SHA256(P) # return P # ``` # FIXME: This is the updated wording from PR #779 # Where "flip(B)" alternates the (B mod 8)'th bit of the (B div 8)'th # byte of the value. So, "flip(0) in e3b0..." is "e2b0...", and # "flip(10) in "e3b0..." is "e3b4". P = bytearray(self.shachain_seed) for B in range(47, -1, -1): if ((1 << B) & index) != 0: P[B // 8] ^= (1 << (B % 8)) P = bytearray(hashlib.sha256(P).digest()) return coincurve.PrivateKey(P)
def generate_keys(self, *, keys_path: str, timeout=MINIMAL_STANDALONE_TIMEOUT) -> Keys: pk = coincurve.PrivateKey() path = Client.__save_key(keys_path, pk) address = Client.__key_to_address(pk) return Keys(path, address)
def ecsign(rawhash, key): if coincurve and hasattr(coincurve, 'PrivateKey'): pk = coincurve.PrivateKey(key) signature = pk.sign_recoverable(rawhash, hasher=None) # v = safe_ord(signature[64]) + 27 r = signature[0:32] s = signature[32:64] return r, s
def __init__(self, rawkey) -> None: if not isinstance(rawkey, bytes): raise TypeError(f"rawkey must be bytes, {type(rawkey)} received") elif len(rawkey) != 32: raise ValueError(f"rawkey must be 32-byte long. {len(rawkey)} received") self.rawkey = rawkey self.key = coincurve.PrivateKey(rawkey)
def privkey_to_pubkey(priv): '''Take 32/33 byte raw private key as input. If 32 bytes, return compressed (33 byte) raw public key. If 33 bytes, read the final byte as compression flag, and return compressed/uncompressed public key as appropriate.''' compressed, priv = read_privkey(priv) #secp256k1 checks for validity of key value. newpriv = secp256k1.PrivateKey(secret=priv) return newpriv.public_key.format(compressed)
def __init__(self, peers, api_client, private_key=None): if private_key is not None: self.__private_key__ = coincurve.PrivateKey.from_hex( private_key.decode()) else: logger.info("No private key provided. Generating new key pair.") self.__private_key__ = coincurve.PrivateKey() self.__public_key__ = self.__private_key__.public_key super(Client, self).__init__(peers, api_client) self.check_peers()
def ecsign(rawhash, key): if coincurve and hasattr(coincurve, 'PrivateKey'): pk = coincurve.PrivateKey(key) signature = pk.sign_recoverable(rawhash, hasher=None) v = safe_ord(signature[64]) + 27 r = big_endian_to_int(signature[0:32]) s = big_endian_to_int(signature[32:64]) else: v, r, s = ecdsa_raw_sign(rawhash, key) return v, r, s
def new_ecsign(rawhash, key): if coincurve and hasattr(coincurve, 'PrivateKey'): pk = coincurve.PrivateKey(key) signature = pk.sign_recoverable(rawhash, hasher=None) v = safe_ord(signature[64]) + 27 r = signature[0:32] s = signature[32:64] sig = r + s + unhexlify(hex(v)[2:]) return sig
def ecdh(privkey, pubkey): """ Take a privkey in raw byte serialization, and a pubkey serialized in compressed, binary format (33 bytes), and output the shared secret as a 32 byte hash digest output. The exact calculation is: shared_secret = SHA256(privkey * pubkey) .. where * is elliptic curve scalar multiplication. See https://github.com/bitcoin/bitcoin/blob/master/src/secp256k1/src/modules/ecdh/main_impl.h for implementation details. """ secp_privkey = secp256k1.PrivateKey(privkey) return secp_privkey.ecdh(pubkey)
def SignChannelAnnouncement(self, request, context): """BOLT #7 - channel_announcement """ node_id = request.node_id.data node = self.nodes.get(node_id) logger.debug("SignChannelAnnouncement node:%s" % node_id) channel_nonce = request.channel_nonce.data channel = node.channels.get(channel_nonce) msg = request.channel_announcement node_key = coincurve.PrivateKey(secret=node.node_privkey) node_signature = node_key.sign(message=msg, hasher=sha256d) bitcoin_key = coincurve.PrivateKey(secret=channel.funding_privkey) bitcoin_signature = bitcoin_key.sign(message=msg, hasher=sha256d) reply = remotesigner_pb2.SignChannelAnnouncementReply() reply.node_signature.data = node_signature reply.bitcoin_signature.data = bitcoin_signature return reply
def derive_public_key(per_commitment_point, base_point): k = sha256(per_commitment_point + base_point).digest() pub1 = coincurve.PrivateKey(secret=k).public_key pub2 = coincurve.PublicKey(data=base_point) pub = pub2.combine([pub1]) #pub1 = secp256k1.PrivateKey(privkey=k, raw=True).pubkey #pub2 = secp256k1.PublicKey(base_point, raw=True) #pub = pub2.combine([pub1.public_key]) return pub.format()
def child(self, i: int, hardened: bool = False) -> PrivateKey: if hardened: i += HARDENED_CHILD_ID if i >= HARDENED_CHILD_ID: ll, lr = hmac_derive(self.chain, self.format() + i.to_bytes(4, 'big')) else: ll, lr = hmac_derive( self.chain, self.key.public_key.format() + i.to_bytes(4, 'big')) secret = (int.from_bytes(ll, 'big') + self.key.to_int()) % SECP256K1_N return PrivateKey(cc.PrivateKey(secret.to_bytes(32, 'big')), lr, self._fingerprint(), self.depth + 1, i)
def ecdsa_sign(rawhash, key): # type: (bytes, bytes) -> EcdsaSignature if coincurve and hasattr(coincurve, 'PrivateKey'): pk = coincurve.PrivateKey(key) signature = pk.sign_recoverable(rawhash, hasher=None) v = safe_ord(signature[64]) + 27 r = signature[0:32] s = signature[32:64] else: v, r, s = ecdsa_raw_sign(rawhash, key) r = u256be(r) s = u256be(s) return EcdsaSignature(v, r, s)
def create_key_pair(private_key: bytes = None, compressed: bool = False) -> Tuple[bytes, bytes]: """ :param private_key: :param compressed: The format of a public key to create :return: (private_key, uncompressed public_key) """ private_key_object = coincurve.PrivateKey(private_key) private_key: bytes = private_key_object.secret public_key: bytes = private_key_object.public_key.format(compressed) return private_key, public_key
def __init__(self, master_key: BIP32, utxos: List[scanner.Utxo], address: str, amount_in_sat: int): """ Craft and sign a transaction that spends all the UTXOs and sends the requested funds to a specific address. """ output_script = scripts.build_output_script_from_address(address) if output_script is None: raise ValueError( 'The address is invalid or the format isn\'t recognized.') if amount_in_sat < NON_SEGWIT_DUST: raise ValueError('Not enough funds to create a sweep transaction.') self.outputs = [(amount_in_sat, output_script)] self.inputs = [] for index in range(len(utxos)): utxo = utxos[index] # Build the inputs for signing: they should all have empty scripts, save for the input that we are signing, # which should have the output script of a P2PKH output. pubkey = master_key.get_pubkey_from_path(utxo.path.to_list()) script = scripts.ScriptType.LEGACY.build_output_script(pubkey) inputs = [(u, script if u == utxo else b'', []) for u in utxos] if utxo.script_type == scripts.ScriptType.LEGACY: # If this is a legacy input, then the transaction digest is just the wire format serialization. tx = _serialize_tx(inputs, self.outputs, include_witness=False) else: # If this is a segwit input (native or not), then the transaction digest is the one defined in BIP143. tx = _serialize_tx_for_segwit_signing(index, inputs, self.outputs) # To produce the final message digest we need to append the sig-hash type, and double sha256 the message. tx.extend(SIGHASH_ALL.to_bytes(4, 'little')) hash = scripts.sha256(scripts.sha256(bytes(tx))) privkey = master_key.get_privkey_from_path(utxo.path.to_list()) signature = coincurve.PrivateKey(privkey).sign(hash, hasher=None) extended_signature = bytearray(signature) extended_signature.append(SIGHASH_ALL) extended_signature = bytes(extended_signature) self.inputs.append( (utxo, utxo.script_type.build_input_script(pubkey, extended_signature), utxo.script_type.build_witness(pubkey, extended_signature)))
def cmd_create_nodekey(args): """Create a geth node key""" labels = labels_from_args(args) key = coincurve.PrivateKey().to_hex() enodeaddr = key.public_key.format(compressed=False)[1:].hex() print(f"enodeaddr: {enodeaddr}") for name, data in [ (args.name + "key", key), (args.name + "enode", enodeaddr)]: s, v = create_secret(args, name, data, **labels) print(f"secret: {s.name}, version: {v.name}")
def SignNodeAnnouncement(self, request, context): """BOLT #7 - node_announcement """ node_id = request.node_id.data node = self.nodes.get(node_id) logger.debug("SignNodeAnnouncement node:%s" % node_id) msg = request.node_announcement node_key = coincurve.PrivateKey(secret=node.node_privkey) signature = node_key.sign(message=msg, hasher=sha256d) reply = remotesigner_pb2.NodeSignatureReply() reply.signature.data = signature return reply
def ecdsa_raw_sign(msg, priv, usehex, rawpriv=True, rawmsg=False, usenonce=None, formsg=False): '''Take the binary message msg and sign it with the private key priv. By default priv is just a 32 byte string, if rawpriv is false it is assumed to be hex encoded (note only works if usehex=False). If rawmsg is True, no sha256 hash is applied to msg before signing. In this case, msg must be a precalculated hash (256 bit). If rawmsg is False, the secp256k1 lib will hash the message as part of the ECDSA-SHA256 signing algo. If usenonce is not None, its value is passed to the secp256k1 library sign() function as the ndata value, which is then used in conjunction with a custom nonce generating function, such that the nonce used in the ECDSA sign algorithm is exactly that value (ndata there, usenonce here). 32 bytes. Return value: the calculated signature.''' if rawmsg and len(msg) != 32: raise Exception("Invalid hash input to ECDSA raw sign.") if rawpriv: compressed, p = read_privkey(priv) newpriv = secp256k1.PrivateKey(p) else: newpriv = secp256k1.PrivateKey.from_hex(priv) if formsg: sig = newpriv.sign_recoverable(msg) return sig #Donations, thus custom nonce, currently disabled, hence not covered. elif usenonce: #pragma: no cover raise NotImplementedError #if len(usenonce) != 32: # raise ValueError("Invalid nonce passed to ecdsa_sign: " + str( # usenonce)) #nf = ffi.addressof(_noncefunc.lib, "nonce_function_rand") #ndata = ffi.new("char [32]", usenonce) #usenonce = (nf, ndata) #sig = newpriv.ecdsa_sign(msg, raw=rawmsg, custom_nonce=usenonce) else: #partial fix for secp256k1-transient not including customnonce; #partial because donations will crash on windows in the "if". if rawmsg: sig = newpriv.sign(msg, hasher=None) else: sig = newpriv.sign(msg) return sig
def add_privkeys(priv1, priv2, usehex): '''Add privkey 1 to privkey 2. Input keys must be in binary either compressed or not. Returned key will have the same compression state. Error if compression state of both input keys is not the same.''' y, z = [read_privkey(x) for x in [priv1, priv2]] if y[0] != z[0]: raise Exception("cannot add privkeys, mixed compression formats") else: compressed = y[0] newpriv1, newpriv2 = (y[1], z[1]) p1 = secp256k1.PrivateKey(newpriv1) res = p1.add(newpriv2).secret if compressed: res += b'\x01' return res
def sign(message_hash: bytes, private_key: bytes, recoverable: bool) -> bytes: """ Generates on the ECDSA-SHA256 signature in bytes from data. It refers to a document on https://github.com/ludbb/secp256k1-py. :param message_hash: 32-byte message_hash to sign :param private_key: private key :param recoverable: True means that public_key can be recovered from signature and message_hash :return signature: signature made from input data """ private_key_object = coincurve.PrivateKey(private_key) if recoverable: return private_key_object.sign_recoverable(message_hash, hasher=None) else: return private_key_object.sign(message_hash, hasher=None)
def SignChannelUpdate(self, request, context): """BOLT #7 - channel_update """ node_id = request.node_id.data node = self.nodes.get(node_id) logger.debug("SignChannelUpdate node:%s" % node_id.hex()) msg = request.channel_update logger.debug("SignChannelUpdate msg:%s" % msg.hex()) node_key = coincurve.PrivateKey(secret=node.node_privkey) signature = node_key.sign(message=msg, hasher=sha256d) reply = remotesigner_pb2.NodeSignatureReply() reply.signature.data = signature return reply
def SignDelayedPaymentToUs(self, request, context): """BOLT #5 - Unilateral Close Handling, phase 1 Sign a delayed to-local output - either from the commitment tx or from an HTLC, at force-close time """ node_id = request.node_id.data node = self.nodes.get(node_id) logger.debug("SignDelayedPaymentToUs node:%s" % node_id.hex()) channel_nonce = request.channel_nonce.data channel = node.channels.get(channel_nonce) n = request.n tx = request.tx amount = tx.input_descs[0].prev_output.value_sat redeemscript = tx.input_descs[0].redeem_script reply = remotesigner_pb2.SignatureReply() delayed_payment_basepoint = channel.basepoints.delayed_payment element = shachain_derive(channel.shaelement, START_INDEX - n) per_commitment_point_prv = coincurve.PrivateKey( secret=bytes(element.secret)) local_per_commit_point = per_commitment_point_prv.public_key.format() local_priv_key = derive_priv_key( local_per_commit_point, delayed_payment_basepoint, channel.basepoints.keys.delayed_payment_basepoint_secret) local_key = Key(import_key=local_priv_key, is_private=True) keys = [local_key] tx = Transaction.import_raw(tx.raw_tx_bytes, self.network) tx.inputs[0].script_type = "p2wsh" tx.inputs[0].witness_type = 'segwit' tx.inputs[0].redeemscript = redeemscript tx.inputs[0].value = amount tx.witness_type = 'segwit' tx.sign(keys=keys, tid=0) reply.signature.data = tx.inputs[0].signatures[0].as_der_encoded( ) + b'\x01' return reply