def __ValidateAndGetGenericKey( pub_key: Union[bytes, IPublicKey], pub_key_cls: Type[IPublicKey]) -> IPublicKey: """ Validate and get a generic public key. Args: pub_key (bytes or IPublicKey object): Public key bytes or object pub_key_cls (IPublicKey) : Public key class type Returns: IPublicKey object: IPublicKey object Raises: TypeError: If the public key is not of the correct class type ValueError: If the public key is not valid """ if isinstance(pub_key, bytes): pub_key = pub_key_cls.FromBytes(pub_key) elif not isinstance(pub_key, pub_key_cls): curve = EllipticCurveGetter.FromType(pub_key_cls.CurveType()) raise TypeError(f"A {curve.Name()} public key is required" f"(expected: {pub_key_cls}, got: {type(pub_key)}") return pub_key
def __init__( self, priv_key: Optional[Union[bytes, IPrivateKey]], pub_key: Optional[Union[bytes, IPublicKey]], key_data: Bip32KeyData, curve_type: EllipticCurveTypes, key_net_ver: Bip32KeyNetVersions = Bip32Const.MAIN_NET_KEY_NET_VERSIONS ) -> None: """ Construct class. Args: priv_key (bytes or IPrivateKey) : Private key (None for a public-only object) pub_key (bytes or IPublicKey) : Public key (only needed for a public-only object) If priv_key is not None, it'll be discarded key_data (Bip32KeyData object) : Key data curve_type (EllipticCurveTypes) : Elliptic curve type key_net_ver (Bip32KeyNetVersions object, optional): Bip32KeyNetVersions object (Bip32 main net by default) Raises: Bip32KeyError: If the constructed key is not valid """ curve = EllipticCurveGetter.FromType(curve_type) # Check that key type matches the Bip curve, if a key object is provided if priv_key is not None: if not isinstance(priv_key, bytes) and not isinstance( priv_key, curve.PrivateKeyClass()): raise Bip32KeyError( f"Invalid private key class, a {curve.Name()} key is required" ) if pub_key is not None: if not isinstance(pub_key, bytes) and not isinstance( pub_key, curve.PublicKeyClass()): raise Bip32KeyError( f"Invalid public key class, a {curve.Name()} key is required" ) # Private key object if priv_key is not None: self.m_priv_key = Bip32PrivateKey.FromBytesOrKeyObject( priv_key, key_data, key_net_ver, curve_type) self.m_pub_key = self.m_priv_key.PublicKey() # Public-only object else: assert isinstance( pub_key, (bytes, IPublicKey )), "Public key shall be specified for public-only objects" self.m_priv_key = None self.m_pub_key = Bip32PublicKey.FromBytesOrKeyObject( pub_key, key_data, key_net_ver, curve_type)
def _CkdPub(self, index: Bip32KeyIndex) -> Bip32Base: """ Create a child key of the specified index using public derivation. Args: index (Bip32KeyIndex object): Key index Returns: Bip32Base object: Bip32Base object Raises: Bip32KeyError: If the index results in an invalid key """ # Get elliptic curve curve = EllipticCurveGetter.FromType(self.CurveType()) # Get index bytes index_bytes = index.ToBytes(endianness="little") # Compute Z and chain code z_bytes = CryptoUtils.HmacSha512( self.ChainCode().ToBytes(), b"\x02" + self.m_pub_key.RawCompressed().ToBytes()[1:] + index_bytes) chain_code_bytes = Bip32BaseUtils.HmacSha512Halves( self.ChainCode().ToBytes(), b"\x03" + self.m_pub_key.RawCompressed().ToBytes()[1:] + index_bytes)[1] # ZL is the left 28-byte part of Z zl_int = BytesUtils.ToInteger(z_bytes[:28], endianness="little") # Compute the new public key point: PKEY + 8ZL * G pub_key_point = self.m_pub_key.Point() + ( (zl_int * 8) * curve.Generator()) # If the public key is the identity point (0, 1) discard the child if pub_key_point.X() == 0 and pub_key_point.Y() == 1: raise Bip32KeyError( "Computed public child key is not valid, very unlucky index") return Bip32Ed25519Kholaw( priv_key=None, pub_key=Ed25519KholawPublicKey.FromPoint(pub_key_point), key_data=Bip32KeyData(chain_code=chain_code_bytes, depth=self.Depth().Increase(), index=index, parent_fprint=self.m_pub_key.FingerPrint()), curve_type=self.CurveType(), key_net_ver=self.KeyNetVersions())
def _CkdPrivEcdsa(cls, bip32_obj: Bip32Base, index: Bip32KeyIndex) -> Bip32Base: """ Create a child key of the specified index using private derivation. Args: bip32_obj (Bip32Base object): Bip32Base object index (Bip32KeyIndex object): Key index Returns: Bip32Base object: Bip32Base object Raises: Bip32KeyError: If the index results in an invalid key """ assert bip32_obj.m_priv_key is not None # Get elliptic curve curve = EllipticCurveGetter.FromType(bip32_obj.CurveType()) # Data for HMAC if index.IsHardened(): data_bytes = b"\x00" + bip32_obj.m_priv_key.Raw().ToBytes() + bytes(index) else: data_bytes = bip32_obj.m_pub_key.RawCompressed().ToBytes() + bytes(index) # Compute HMAC halves i_l, i_r = Bip32BaseUtils.HmacSha512Halves(bip32_obj.ChainCode().ToBytes(), data_bytes) # Construct new key secret from i_l and current private key i_l_int = BytesUtils.ToInteger(i_l) key_int = BytesUtils.ToInteger(bip32_obj.m_priv_key.Raw().ToBytes()) new_key_int = (i_l_int + key_int) % curve.Order() # Convert to string and pad with zeros new_priv_key_bytes = IntegerUtils.ToBytes(new_key_int).rjust(curve.PrivateKeyClass().Length(), b"\x00") # Construct and return a new Bip32 object return cls(priv_key=new_priv_key_bytes, pub_key=None, key_data=Bip32KeyData(chain_code=i_r, depth=bip32_obj.Depth().Increase(), index=index, parent_fprint=bip32_obj.m_pub_key.FingerPrint()), curve_type=bip32_obj.CurveType(), key_net_ver=bip32_obj.KeyNetVersions())
def __KeyFromBytes(key_bytes: bytes, curve_type: EllipticCurveTypes) -> IPrivateKey: """ Construct key from bytes. Args: key_bytes (bytes) : Key bytes curve_type (EllipticCurveTypes): Elliptic curve type Returns: IPrivateKey object: IPrivateKey object Raises: Bip32KeyError: If the key constructed from the bytes is not valid """ try: curve = EllipticCurveGetter.FromType(curve_type) return curve.PrivateKeyClass().FromBytes(key_bytes) except ValueError as ex: raise Bip32KeyError("Invalid private key") from ex
def _FromSeed(cls, seed_bytes: bytes, key_net_ver: Bip32KeyNetVersions) -> Bip32Base: """ Create a Bip32 object from the specified seed (e.g. BIP39 seed). Args: seed_bytes (bytes) : Seed bytes key_net_ver (Bip32KeyNetVersions object): Bip32KeyNetVersions object Returns: Bip32Base object: Bip32Base object Raises: ValueError: If the seed is too short Bip32KeyError: If the seed is not suitable for master key generation """ curve_type = cls.CurveType() priv_key_cls = EllipticCurveGetter.FromType( curve_type).PrivateKeyClass() # Compute HMAC, retry if the resulting private key is not valid hmac = b"" hmac_data = seed_bytes success = False while not success: hmac = CryptoUtils.HmacSha512(cls._MasterKeyHmacKey(), hmac_data) # If private key is not valid, the new HMAC data is the current HMAC success = priv_key_cls.IsValidBytes( hmac[:Bip32BaseConst.HMAC_HALF_BYTE_LEN]) if not success: hmac_data = hmac # Create BIP32 by splitting the HMAC into two 32-byte sequences return cls(priv_key=hmac[:Bip32BaseConst.HMAC_HALF_BYTE_LEN], pub_key=None, key_data=Bip32KeyData( chain_code=hmac[Bip32BaseConst.HMAC_HALF_BYTE_LEN:]), curve_type=curve_type, key_net_ver=key_net_ver)
def _CkdPubEcdsa(cls, bip32_obj: Bip32Base, index: Bip32KeyIndex) -> Bip32Base: """ Create a child key of the specified index using public derivation. Args: bip32_obj (Bip32Base object): Bip32Base object index (Bip32KeyIndex object): Key index Returns: Bip32Base object: Bip32Base object Raises: Bip32KeyError: If the index results in an invalid key """ curve = EllipticCurveGetter.FromType(bip32_obj.CurveType()) # Data for HMAC, same of __CkdPriv() for public child key data_bytes = bip32_obj.m_pub_key.RawCompressed().ToBytes() + bytes(index) # Get HMAC of data i_l, i_r = Bip32BaseUtils.HmacSha512Halves(bip32_obj.ChainCode().ToBytes(), data_bytes) # Try to construct a new public key from the curve point: pub_key_point + G*i_l try: new_point = bip32_obj.m_pub_key.Point() + (curve.Generator() * BytesUtils.ToInteger(i_l)) pub_key = curve.PublicKeyClass().FromPoint(new_point) except ValueError as ex: raise Bip32KeyError("Computed public child key is not valid, very unlucky index") from ex # Construct and return a new Bip32 object return cls(priv_key=None, pub_key=pub_key, key_data=Bip32KeyData(chain_code=i_r, depth=bip32_obj.Depth().Increase(), index=index, parent_fprint=bip32_obj.m_pub_key.FingerPrint()), curve_type=bip32_obj.CurveType(), key_net_ver=bip32_obj.KeyNetVersions())
def _CkdPriv(self, index: Bip32KeyIndex) -> Bip32Base: """ Create a child key of the specified index using private derivation. Args: index (Bip32KeyIndex object): Key index Returns: Bip32Base object: Bip32Base object Raises: Bip32KeyError: If the index results in an invalid key """ assert self.m_priv_key is not None # Get elliptic curve curve = EllipticCurveGetter.FromType(self.CurveType()) # Get index bytes index_bytes = index.ToBytes(endianness="little") # Compute Z and chain code if index.IsHardened(): z_bytes = CryptoUtils.HmacSha512( self.ChainCode().ToBytes(), b"\x00" + self.m_priv_key.Raw().ToBytes() + index_bytes) chain_code_bytes = Bip32BaseUtils.HmacSha512Halves( self.ChainCode().ToBytes(), b"\x01" + self.m_priv_key.Raw().ToBytes() + index_bytes)[1] else: z_bytes = CryptoUtils.HmacSha512( self.ChainCode().ToBytes(), b"\x02" + self.m_pub_key.RawCompressed().ToBytes()[1:] + index_bytes) chain_code_bytes = Bip32BaseUtils.HmacSha512Halves( self.ChainCode().ToBytes(), b"\x03" + self.m_pub_key.RawCompressed().ToBytes()[1:] + index_bytes)[1] # ZL is the left 28-byte part of Z zl_int = BytesUtils.ToInteger(z_bytes[:28], endianness="little") # ZR is the right 32-byte part of Z zr_int = BytesUtils.ToInteger(z_bytes[32:], endianness="little") # Compute kL kl_int = (zl_int * 8) + BytesUtils.ToInteger( self.m_priv_key.Raw().ToBytes()[:32], endianness="little") if kl_int % curve.Order() == 0: raise Bip32KeyError( "Computed private child key is not valid, very unlucky index") # Compute kR kr_int = (zr_int + BytesUtils.ToInteger(self.m_priv_key.Raw().ToBytes()[32:], endianness="little")) % 2**256 # Compute private key priv_key = Ed25519KholawPrivateKey.FromBytes( IntegerUtils.ToBytes(kl_int, Ed25519KholawPrivateKey.Length() // 2, endianness="little") + IntegerUtils.ToBytes(kr_int, Ed25519KholawPrivateKey.Length() // 2, endianness="little")) return Bip32Ed25519Kholaw( priv_key=priv_key, pub_key=None, key_data=Bip32KeyData(chain_code=chain_code_bytes, depth=self.Depth().Increase(), index=index, parent_fprint=self.m_pub_key.FingerPrint()), curve_type=self.CurveType(), key_net_ver=self.KeyNetVersions())