def _ValidateAndCkdPub(self, index: Bip32KeyIndex) -> Bip32Base: """ Check the key index validity and create a child key of the specified index using public derivation. Args: index (Bip32KeyIndex object): Key index Returns: Bip32Base object: Bip32 object constructed with the child parameters Raises: Bip32KeyError: If the index results in an invalid key """ # Check if supported if not self.IsPublicDerivationSupported(): raise Bip32KeyError("Public child derivation is not supported") # Hardened index is not supported for public derivation if index.IsHardened(): raise Bip32KeyError( "Public child derivation cannot be used to create a hardened child key" ) return self._CkdPub(index)
def __GetPartsFromBytes(ser_key_bytes: bytes, is_public: bool) -> Tuple[bytes, Bip32KeyData]: """ Get back key parts from serialized key bytes. Args: ser_key_bytes (bytes): Serialized key bytes is_public (bool) : True if the key is public, false otherwise Returns: tuple[bytes, Bip32KeyData]: key bytes (index 0) and key data (index 1) Raises: Bip32KeyError: If the private key first byte is not zero """ # Compute indexes depth_idx = Bip32KeyNetVersions.Length() fprint_idx = depth_idx + Bip32Depth.Length() key_index_idx = fprint_idx + Bip32FingerPrint.Length() chain_code_idx = key_index_idx + Bip32KeyIndex.Length() key_idx = chain_code_idx + Bip32ChainCode.Length() # Get parts depth = ser_key_bytes[depth_idx] fprint_bytes = ser_key_bytes[fprint_idx:key_index_idx] key_index_bytes = ser_key_bytes[key_index_idx:chain_code_idx] chain_code_bytes = ser_key_bytes[chain_code_idx:key_idx] key_bytes = ser_key_bytes[key_idx:] key_data = Bip32KeyData(Bip32Depth(depth), Bip32KeyIndex.FromBytes(key_index_bytes), Bip32ChainCode(chain_code_bytes), Bip32FingerPrint(fprint_bytes)) # If private key, the first byte shall be zero and shall be removed if not is_public: if key_bytes[0] != 0: raise Bip32KeyError( f"Invalid extended private key (wrong secret: {key_bytes[0]})" ) key_bytes = key_bytes[1:] return key_bytes, key_data
def __GetIndex(index: Union[int, Bip32KeyIndex]) -> Bip32KeyIndex: """ Get index object. Args: index (int or Bip32KeyIndex): Index Returns: Bip32KeyIndex object: Bip32KeyIndex object """ return Bip32KeyIndex(index) if isinstance(index, int) else index
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 AddElem(self, elem: Union[int, Bip32KeyIndex]) -> Bip32Path: """ Return a new path object with the specified element added. Args: elem (str or Bip32KeyIndex): Path element Returns: Bip32Path object: Bip32Path object Raises: Bip32PathError: If the path element is not valid """ if isinstance(elem, int): elem = Bip32KeyIndex(elem) return Bip32Path(self.m_elems + [elem], self.m_is_absolute)
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 __init__(self, elems: Sequence[Union[int, Bip32KeyIndex]], is_absolute: bool) -> None: """ Construct class. Args: elems (list) : Path elements is_absolute (bool): True if path is an absolute one, false otherwise """ try: self.m_elems = [ Bip32KeyIndex(elem) if isinstance(elem, int) else elem for elem in elems ] except ValueError as ex: raise Bip32PathError( "The path contains some invalid key indexes") from ex self.m_is_absolute = is_absolute
def _ValidateAndCkdPriv(self, index: Bip32KeyIndex) -> Bip32Base: """ Check the key index validity and create a child key of the specified index using private derivation. Args: index (Bip32KeyIndex object): Key index Returns: Bip32Base object: Bip32 object constructed with the child parameters Raises: Bip32KeyError: If the index results in an invalid key """ # Check if supported if not index.IsHardened( ) and not self.IsPrivateUnhardenedDerivationSupported(): raise Bip32KeyError( "Private child derivation with not-hardened index is not supported" ) return self._CkdPriv(index)
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())