def _derive_public_child(pubkey, chaincode, index): """A.k.a CKDpub, in bip-0032. :param pubkey: The parent's (compressed) public key, as bytes :param chaincode: The parent's chaincode, as bytes :param index: The index of the node to derive, as int :return: (child_pubkey, child_chaincode) """ assert isinstance(pubkey, bytes) and isinstance(chaincode, bytes) assert not index & HARDENED_INDEX # payload is the I from the BIP. Index is 32 bits unsigned int, BE. payload = hmac.new(chaincode, pubkey + index.to_bytes(4, "big"), hashlib.sha512).digest() try: tmp_pub = coincurve.PublicKey.from_secret(payload[:32]) except ValueError: raise BIP32DerivationError("Invalid private key at index {}, try the " "next one!".format(index)) parent_pub = coincurve.PublicKey(pubkey) try: child_pub = coincurve.PublicKey.combine_keys([tmp_pub, parent_pub]) except ValueError: raise BIP32DerivationError("Invalid public key at index {}, try the " "next one!".format(index)) return child_pub.format(), payload[32:]
def FromBytes(cls, point_bytes: bytes) -> IPoint: """ Construct class from point bytes. Args: point_bytes (bytes): Point bytes Returns: IPoint: IPoint object """ if len(point_bytes) == EcdsaKeysConst.PUB_KEY_UNCOMPRESSED_BYTE_LEN - 1: return cls(coincurve.PublicKey(EcdsaKeysConst.PUB_KEY_UNCOMPRESSED_PREFIX + point_bytes)) if len(point_bytes) == EcdsaKeysConst.PUB_KEY_COMPRESSED_BYTE_LEN: return cls(coincurve.PublicKey(point_bytes)) raise ValueError("Invalid point bytes")
def diffi_hellman(pub_key, priv_key): logging.info(f"This is the public_key in function {pub_key}") alice_coin_priv = coincurve.PrivateKey.from_hex(priv_key) #bob_coin_priv = coincurve.PrivateKey.from_hex(bob_priv) pub = coincurve.PublicKey(pub_key) logging.info(f"This is the public_key after parsing {pub}") logging.info(f"This is the public_key after parsing {pub.public_key}") return binascii.hexlify(alice_coin_priv.ecdh(pub.public_key))
def verify_signature(signature: bytes, message_hash: bytes, public_key: bytes) -> bool: recoverable: bool = is_signature_recoverable(signature) public_key_object = coincurve.PublicKey(public_key) if recoverable: public_key_object_from_signature = coincurve.PublicKey.from_signature_and_message( signature, message_hash, hasher=None) return public_key_object == public_key_object_from_signature else: public_key_object.verify(signature, message_hash, hasher=None)
def verify_recover_secp256k1_bc(signature, req, hasher=coincurve.utils.sha256, context=GLOBAL_CONTEXT): msg_hash = hasher(req) if hasher is not None else req rec_sig = coincurve.ecdsa.deserialize_recoverable(signature) public_key = coincurve.PublicKey(coincurve.ecdsa.recover(req, rec_sig)) n_sig = coincurve.ecdsa.recoverable_convert(rec_sig) if not lib.secp256k1_ecdsa_verify(context.ctx, n_sig, msg_hash, public_key.public_key): raise RuntimeError("Failed to verify SECP256K1 bitcoin signature")
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 _check_signature(self, siglist): # check identity scheme scheme = self.get('id') if scheme != b'v4': raise SignatureError('unsupported identity scheme "' + scheme + '"') pubkey = self.get('secp256k1') if len(pubkey) != 33: raise SignatureError('invalid public key length') pubkey = coincurve.PublicKey(pubkey) # verify against the public key from k/v data sigdata = sha3.keccak_256(rlp.encode(siglist)).digest() if not pubkey.verify(_signature_to_der(self._sig), sigdata, hasher=None): raise SignatureError('invalid signature')
def __init__(self, innerkey): # We accept either 33-bytes raw keys, or an EC PublicKey as returned # by coincurve if isinstance(innerkey, bytes): if innerkey[0] in [2, 3] and len(innerkey) == 33: innerkey = coincurve.PublicKey(innerkey) else: raise ValueError( "Byte keys must be 33-byte long starting from either 02 or 03" ) elif not isinstance(innerkey, coincurve.keys.PublicKey): raise ValueError( "Key must either be bytes or coincurve.keys.PublicKey") self.key = innerkey
def multiply(s, pub, return_serialized=True): '''Input binary compressed pubkey P(33 bytes) and scalar s(32 bytes), return s*P. The return value is a binary compressed public key, or a PublicKey object if return_serialized is False. Note that the called function does the type checking of the scalar s. ('raw' options passed in) ''' newpub = secp256k1.PublicKey(pub) #see note to "tweak_mul" function in podle.py res = newpub.multiply(s) if not return_serialized: return res return res.format()
def perform_complaint(sgx, t, poly_name, public_key, corrupted_secret_key_contribution): response = sgx.complaint_response(poly_name, 1) share, dh_key = response["share"], response["dh_key"] ecdh_key = coincurve.PublicKey( bytes.fromhex("04" + public_key[2:])).multiply( coincurve.keys.PrivateKey.from_hex(dh_key).secret).format( compressed=False)[1:33] decrypted_key = decrypt(bytes.fromhex(corrupted_secret_key_contribution), ecdh_key) mult_g2 = sgx.mult_g2(decrypted_key) share = share.split(':') assert share == mult_g2 verification_vector_mult = response["verification_vector_mult"] assert len(verification_vector_mult) == t
def FromBytes(cls, key_bytes: bytes) -> IPublicKey: """ Construct class from key bytes. Args: key_bytes (bytes): Key bytes Returns: IPublicKey: IPublicKey object Raises: ValueError: If key bytes are not valid """ try: return cls(coincurve.PublicKey(key_bytes)) except ValueError as ex: raise ValueError("Invalid public key bytes") from ex
def multiply(s, pub, usehex, rawpub=True, return_serialized=True): '''Input binary compressed pubkey P(33 bytes) and scalar s(32 bytes), return s*P. The return value is a binary compressed public key, or a PublicKey object if return_serialized is False. Note that the called function does the type checking of the scalar s. ('raw' options passed in) ''' newpub = secp256k1.PublicKey(pub) #see note to "tweak_mul" function in podle.py if sys.version_info >= (3, 0): res = newpub.multiply(native_bytes(s)) else: res = newpub.multiply(bytes_to_native_str(s)) if not return_serialized: return res return res.format()
def getNUMS(index=0) -> Point: """ Nothing Up My Sleeve Taking secp256k1's G as a seed, either in compressed or uncompressed form, append "index" as a byte, and append a second byte "counter" try to create a new NUMS base point from the sha256 of that bytestring. Loop counter and alternate compressed/uncompressed until finding a valid curve point. The first such point is considered as "the" NUMS base point alternative for this index value. The search process is of course deterministic/repeatable, so it's fine to just store a list of all the correct values for each index, but for transparency left in code for initialization by any user. """ for G in [ B.encode_pubkey(B.G, 'bin_compressed'), B.encode_pubkey(B.G, 'bin') ]: # Using latin-1 since its used in BTC seed = G + chr(index).encode('utf-8') for counter in range(256): seed_c = seed + chr(counter).encode('utf-8') hash_seed = hashlib.sha256(seed_c).digest() # Every x-coord on the curve has two y-values, encoded # in compressed form with 02/03 parity byte. We just # choose the former claimed_point: bytes = chr(2).encode('utf-8') + hash_seed try: # Check to see if its a valid public key C.PublicKey(claimed_point) return B.encode_pubkey(claimed_point, 'decimal') except: continue raise Exception('NUMS generation inconceivable')
def ecies_decrypt(privkey, encrypted): if len(privkey) == 33 and privkey[-1] == 1: privkey = privkey[:32] encrypted = base64.b64decode(encrypted) if len(encrypted) < 85: raise Exception('invalid ciphertext: length') magic = encrypted[:4] if magic != ECIES_MAGIC_BYTES: raise ECIESDecryptionError() ephemeral_pubkey = encrypted[4:37] try: testR = secp256k1.PublicKey(ephemeral_pubkey) except: raise ECIESDecryptionError() ciphertext = encrypted[37:-32] mac = encrypted[-32:] ecdh_key = btc.multiply(privkey, ephemeral_pubkey) key = hashlib.sha512(ecdh_key).digest() iv, key_e, key_m = key[0:16], key[16:32], key[32:] if mac != hmac.new(key_m, encrypted[:-32], hashlib.sha256).digest(): raise ECIESDecryptionError() return aes_decrypt(key_e, ciphertext, iv=iv)
def ecdsa_raw_verify(msg, pub, sig, usehex, rawmsg=False): '''Take the binary message msg and binary signature sig, and verify it against the pubkey pub. If rawmsg is True, no sha256 hash is applied to msg before verifying. 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 verification algo. Return value: True if the signature is valid for this pubkey, False otherwise. Since the arguments may come from external messages their content is not guaranteed, so return False on any parsing exception. ''' try: if rawmsg: assert len(msg) == 32 newpub = secp256k1.PublicKey(pub) if rawmsg: retval = newpub.verify(sig, msg, hasher=None) else: retval = newpub.verify(sig, msg) except: return False return retval
def is_valid_pubkey(pubkey, usehex, require_compressed=False): """ Returns True if the serialized pubkey is a valid secp256k1 pubkey serialization or False if not; returns False for an uncompressed encoding if require_compressed is True. """ # sanity check for public key # see https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.h if require_compressed: valid_uncompressed = False elif len(pubkey) == 65 and pubkey[:1] in (b'\x04', b'\x06', b'\x07'): valid_uncompressed = True else: valid_uncompressed = False if not ((len(pubkey) == 33 and pubkey[:1] in (b'\x02', b'\x03')) or valid_uncompressed): return False # serialization is valid, but we must ensure it corresponds # to a valid EC point: try: dummy = secp256k1.PublicKey(pubkey) except: return False return True
def pub_to_pub(pub: bytes, compressed: bool = True): return coincurve.PublicKey(pub).format(compressed=compressed)
def add_pubkeys(pubkeys, usehex): '''Input a list of binary compressed pubkeys and return their sum as a binary compressed pubkey.''' pubkey_list = [secp256k1.PublicKey(x) for x in pubkeys] r = secp256k1.PublicKey.combine_keys(pubkey_list) return r.format()
def blind_group_element(pubkey, blind: Secret) -> PublicKey: pubkey = coincurve.PublicKey(data=pubkey.to_bytes()) blinded = pubkey.multiply(blind.to_bytes(), update=False) return PublicKey(blinded.format(compressed=True))
def verify(self): return coincurve.PublicKey(self._source).verify( self._signature, self.to_signable())
def podle_PublicKey(P): """Returns a PublicKey object from a binary string """ return secp256k1.PublicKey(P)
def node_addr(self): pubkey = coincurve.PublicKey(self.get('secp256k1')) pubkey = pubkey.format(compressed=False) return sha3.keccak_256(pubkey[1:]).digest()
def decode(cls, b): hrp, data = bech32_decode(b) if not hrp: raise ValueError("Bad bech32 checksum") # BOLT #11: # # A reader MUST fail if it does not understand the `prefix`. if not hrp.startswith('ln'): raise ValueError("Does not start with ln") data = u5_to_bitarray(data) # Final signature 65 bytes, split it off. if len(data) < 65 * 8: raise ValueError("Too short to contain signature") sigdecoded = data[-65 * 8:].tobytes() data = bitstring.ConstBitStream(data[:-65 * 8]) inv = Invoice() inv.pubkey = None m = re.search(r'[^\d]+', hrp[2:]) if m: inv.currency = m.group(0) amountstr = hrp[2 + m.end():] # BOLT #11: # # A reader SHOULD indicate if amount is unspecified, otherwise it MUST # multiply `amount` by the `multiplier` value (if any) to derive the # amount required for payment. if amountstr != '': inv.amount = unshorten_amount(amountstr) inv.date = data.read(35).uint while data.pos != data.len: tag, tagdata, data = pull_tagged(data) # BOLT #11: # # A reader MUST skip over unknown fields, an `f` field with unknown # `version`, or a `p`, `h`, `n` or `r` field which does not have # `data_length` 52, 52, 53 or 82 respectively. data_length = len(tagdata) / 5 if tag == 'r': inv.route_hints = RouteHintSet.from_bytes( trim_to_bytes(tagdata)) continue if data_length != 82: inv.unknown_tags.append((tag, tagdata)) continue tagbytes = trim_to_bytes(tagdata) inv.tags.append(('r', (tagbytes[0:33], tagbytes[33:41], tagdata[41 * 8:49 * 8].intbe, tagdata[49 * 8:51 * 8].intbe))) elif tag == 'f': fallback = parse_fallback(tagdata, inv.currency) if fallback: inv.tags.append(('f', fallback)) else: # Incorrect version. inv.unknown_tags.append((tag, tagdata)) continue elif tag == 'd': inv.tags.append(('d', trim_to_bytes(tagdata).decode('utf-8'))) elif tag == 'h': if data_length != 52: inv.unknown_tags.append((tag, tagdata)) continue inv.tags.append(('h', trim_to_bytes(tagdata))) elif tag == 'x': inv.tags.append(('x', tagdata.uint)) elif tag == 'p': if data_length != 52: inv.unknown_tags.append((tag, tagdata)) continue inv.paymenthash = trim_to_bytes(tagdata) elif tag == 'n': if data_length != 53: inv.unknown_tags.append((tag, tagdata)) continue inv.pubkey = coincurve.PublicKey(trim_to_bytes(tagdata)) elif tag == 'c': inv.min_final_cltv_expiry = tagdata.uint else: inv.unknown_tags.append((tag, tagdata)) # BOLT #11: # # A reader MUST check that the `signature` is valid (see the `n` tagged # field specified below). if inv.pubkey: # Specified by `n` # BOLT #11: # # A reader MUST use the `n` field to validate the signature instead of # performing signature recovery if a valid `n` field is provided. inv.signature = inv.pubkey.ecdsa_deserialize_compact( sigdecoded[0:64]) if not inv.pubkey.ecdsa_verify( bytearray([ord(c) for c in hrp]) + data.tobytes(), inv.signature): raise ValueError('Invalid signature') else: # Recover pubkey from signature. inv.signature = coincurve.ecdsa.deserialize_recoverable( sigdecoded[0:65]) inv.pubkey = coincurve.PublicKey.from_signature_and_message( sigdecoded[0:65], bytearray([ord(c) for c in hrp]) + data.tobytes()) return inv
def ecdh(k, rk): k = coincurve.PrivateKey(secret=k.rawkey) rk = coincurve.PublicKey(data=rk.serializeCompressed()) a = k.ecdh(rk.public_key) return Secret(a)
def verify(self): return coincurve.PublicKey(codecs.decode(self._source, 'hex')).verify( codecs.decode(self._signature, 'hex'), self.to_signable())
def from_bytes(cls, data: bytes) -> "Secp256k1PublicKey": impl = coincurve.PublicKey(data) return cls(impl)
def ecdh(k, rk): k = coincurve.PrivateKey(secret=k) rk = coincurve.PublicKey(data=rk) a = k.ecdh(rk.public_key) return a
def verify(message, pub, signature): pub = cc.PublicKey(pub, context=cc.GLOBAL_CONTEXT) return pub.verify(signature, message, hasher=REGULAR_HASH_FUNCTION)
def verify(self, signature, message, public_key=None): if public_key is not None: return coincurve.PublicKey(public_key).verify(signature, message) return self.__public_key__.verify(signature, message)
def pub_to_pub(pub, compressed=True): return coincurve.PublicKey(pub).format(compressed=compressed)