예제 #1
0
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)
예제 #2
0
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
예제 #3
0
    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)
        }
예제 #4
0
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]
예제 #5
0
 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
예제 #6
0
 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
예제 #7
0
    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
예제 #9
0
    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)
예제 #10
0
 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)
예제 #11
0
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
예제 #12
0
    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)
예제 #14
0
 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()
예제 #15
0
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
예제 #16
0
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)
예제 #18
0
    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
예제 #19
0
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()
예제 #20
0
 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)
예제 #21
0
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)
예제 #22
0
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
예제 #23
0
    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)))
예제 #24
0
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}")
예제 #25
0
    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
예제 #26
0
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
예제 #27
0
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
예제 #28
0
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)
예제 #29
0
    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
예제 #30
0
    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