def __EncryptSeedb(seedb: bytes, derived_half_1: bytes, derived_half_2: bytes) -> Tuple[bytes, bytes]: """ Encrypt seedb in two parts. Args: seedb (bytes) : Seedb derived_half_1 (bytes): First half of derived key derived_half_2 (bytes): Second half of derived key Returns: tuple[bytes, bytes]: Two encrypted parts """ # Use derived_half_2 as AES key aes_enc = AesEcbEncrypter(derived_half_2) aes_enc.AutoPad(False) # Encrypt the first part: seedb[0...15] xor derived_half_1[0...15] encrypted_part_1 = aes_enc.Encrypt(BytesUtils.Xor(seedb[:16], derived_half_1[:16])) # Encrypt the second part: (encrypted_part_1[8...15] + seedb[16...23])) xor derivedhalf1[16...31] encrypted_part_2 = aes_enc.Encrypt(BytesUtils.Xor(encrypted_part_1[8:] + seedb[16:], derived_half_1[16:])) return encrypted_part_1, encrypted_part_2
def __EncryptPrivateKey(priv_key_bytes: bytes, derived_half_1: bytes, derived_half_2: bytes) -> Tuple[bytes, bytes]: """ Encrypt private key in two halves. Args: priv_key_bytes (bytes): Private key derived_half_1 (bytes): First half of derived key derived_half_2 (bytes): Second half of derived key Returns: tuple[bytes, bytes]: Two encrypted halves """ # Use derived_half_2 as AES key aes_enc = AesEcbEncrypter(derived_half_2) aes_enc.AutoPad(False) # Encrypt the first half: priv_key[0...15] xor derived_half_1[0...15] encrypted_half_1 = aes_enc.Encrypt( BytesUtils.Xor(priv_key_bytes[:16], derived_half_1[:16])) # Encrypt the second half: priv_key[16...31] xor derived_half_1[16...31] encrypted_half_2 = aes_enc.Encrypt( BytesUtils.Xor(priv_key_bytes[16:], derived_half_1[16:])) return encrypted_half_1, encrypted_half_2
def __DecryptAndGetFactorb(encrypted_part_1_lower: bytes, encrypted_part_2: bytes, derived_half_1: bytes, derived_half_2: bytes) -> bytes: """ Decrypt and get back factorb. Args: encrypted_part_1_lower (bytes): Lower part of first encrypted part encrypted_part_2 (bytes) : Second encrypted part derived_half_1 (bytes) : First half of derived key derived_half_2 (bytes) : Second half of derived key Returns: bytes: Factorb """ # Use derived_half_2 as AES key aes_dec = AesEcbDecrypter(derived_half_2) aes_dec.AutoUnPad(False) # Decrypt the second part and get back the higher parts of seedb and encrypted half 1 decrypted_part_2 = BytesUtils.Xor(aes_dec.Decrypt(encrypted_part_2), derived_half_1[16:]) encrypted_part_1_higher = decrypted_part_2[:8] seedb_part_2 = decrypted_part_2[8:] # Decrypt the first part to get the lower part of seedb seedb_part_1 = BytesUtils.Xor(aes_dec.Decrypt(encrypted_part_1_lower + encrypted_part_1_higher), derived_half_1[:16]) # Rebuild the complete seedb seedb = seedb_part_1 + seedb_part_2 # Compute factorb from seedb return CryptoUtils.DoubleSha256(seedb)
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 """ # Remove the 0x00 prefix if present because nacl requires 32-byte length if (len(key_bytes) == cls.CompressedLength() and key_bytes[0] == BytesUtils.ToInteger(Ed25519KeysConst.PUB_KEY_PREFIX)): key_bytes = key_bytes[1:] # nacl doesn't check if the point lies on curve try: ed25519_lib.point_decode(key_bytes) except ValueError as ex: raise ValueError("Invalid public key bytes") from ex try: return cls(signing.VerifyKey(key_bytes)) except (exceptions.RuntimeError, exceptions.ValueError) as ex: raise ValueError("Invalid public key bytes") from ex
def __DecryptAndGetPrivKey(encrypted_half_1: bytes, encrypted_half_2: bytes, derived_half_1: bytes, derived_half_2: bytes) -> bytes: """ Decrypt and get back private key. Args: encrypted_half_1 (bytes): First encrypted half encrypted_half_2 (bytes): Second encrypted half derived_half_1 (bytes) : First half of derived key derived_half_2 (bytes) : Second half of derived key Returns: bytes: Decrypted private key """ # Use derived_half_2 as AES key aes_dec = AesEcbDecrypter(derived_half_2) aes_dec.AutoUnPad(False) # Decrypt using AES256Decrypt decrypted_half_1 = aes_dec.Decrypt(encrypted_half_1) decrypted_half_2 = aes_dec.Decrypt(encrypted_half_2) # Get the private key back by XORing bytes return BytesUtils.Xor(decrypted_half_1 + decrypted_half_2, derived_half_1)
def GeneratePrivateKey(int_passphrase: str, pub_key_mode: Bip38PubKeyModes) -> str: """ Generate a random encrypted private key from the intermediate passphrase. Args: int_passphrase (str) : Intermediate passphrase pub_key_mode (Bip38PubKeyModes): Public key mode Returns: str: Encrypted private key Raises: Base58ChecksumError: If base58 checksum is not valid ValueError: If the intermediate code is not valid """ # Decode intermediate passphrase int_passphrase_bytes = Base58Decoder.CheckDecode(int_passphrase) # Check length if len(int_passphrase_bytes) != Bip38EcConst.INT_PASS_ENC_BYTE_LEN: raise ValueError(f"Invalid intermediate code length ({len(int_passphrase_bytes)})") # Get all the parts back magic = int_passphrase_bytes[:8] owner_entropy = int_passphrase_bytes[8:16] passpoint = Secp256k1PublicKey.FromBytes(int_passphrase_bytes[16:]) # Check magic if magic not in (Bip38EcConst.INT_PASS_MAGIC_NO_LOT_SEQ, Bip38EcConst.INT_PASS_MAGIC_WITH_LOT_SEQ): raise ValueError(f"Invalid magic ({BytesUtils.ToHexString(magic)})") # Generate seedb seedb = os.urandom(Bip38EcConst.SEED_B_BYTE_LEN) # Compute factorb from seedb factorb = CryptoUtils.DoubleSha256(seedb) # Compute address hash address_hash = Bip38Addr.AddressHash( Secp256k1PublicKey.FromPoint(passpoint.Point() * BytesUtils.ToInteger(factorb)), pub_key_mode ) # Derive key halves from the passpoint, address hash and owner entropy derived_half_1, derived_half_2 = _Bip38EcUtils.DeriveKeyHalves(passpoint.RawCompressed().ToBytes(), address_hash, owner_entropy) # Encrypt seedb in two parts encrypted_part_1, encrypted_part_2 = Bip38EcKeysGenerator.__EncryptSeedb(seedb, derived_half_1, derived_half_2) # Get flagbyte by setting bits flagbyte = Bip38EcKeysGenerator.__SetFlagbyteBits(magic, pub_key_mode) # Concatenate all parts enc_key_bytes = (Bip38EcConst.ENC_KEY_PREFIX + flagbyte + address_hash + owner_entropy + encrypted_part_1[:8] + encrypted_part_2) # Encode in Base58Check return Base58Encoder.CheckEncode(enc_key_bytes)
def BytesChunkToWords(bytes_chunk: bytes, words_list: MnemonicWordsList, endianness: str) -> List[str]: """ Get words from a bytes chunk. Args: bytes_chunk (bytes) : Bytes chunk words_list (MnemonicWordsList object): Mnemonic list endianness (str) : Bytes endianness Returns: list[str]: 3 word indexes """ n = words_list.Length() int_chunk = BytesUtils.ToInteger(bytes_chunk, endianness=endianness) word1_idx = int_chunk % n word2_idx = ((int_chunk // n) + word1_idx) % n word3_idx = ((int_chunk // n // n) + word2_idx) % n return [ words_list.GetWordAtIdx(w) for w in (word1_idx, word2_idx, word3_idx) ]
def Decode(cls, hrp: str, addr: str) -> bytes: """ Decode from Bech32. Args: hrp (str) : Human readable part addr (str): Address Returns: bytes: Decoded address Raises: ValueError: If the bech32 string is not valid Bech32ChecksumError: If the checksum is not valid """ # Decode string hrp_got, data = cls._DecodeBech32(addr, Bech32Const.SEPARATOR, Bech32Const.CHECKSUM_STR_LEN) # Check HRP if hrp != hrp_got: raise ValueError( f"Invalid format (HRP not valid, expected {hrp}, got {hrp_got})" ) # Convert back from base32 return BytesUtils.FromList(Bech32BaseUtils.ConvertFromBase32(data))
def __ComputePrivateKey(passfactor: bytes, factorb: bytes) -> bytes: """ Compute the private key from passfactor and factorb. Args: passfactor (bytes): Passfactor factorb (bytes) : Factorb Returns: bytes: Private key """ # Private key: (passfactor * factorb) mod N priv_key_int = (BytesUtils.ToInteger(passfactor) * BytesUtils.ToInteger(factorb)) % Secp256k1.Order() return IntegerUtils.ToBytes(priv_key_int, bytes_num=Secp256k1PrivateKey.Length())
def __GetFlagbyteOptions(flagbyte: bytes) -> Tuple[Bip38PubKeyModes, bool]: """ Get the options from the flagbyte. Args: flagbyte (bytes): Flagbyte Returns: tuple[Bip38PubKeyModes, bool]: Public key mode (index 0), has lot/sequence numbers (index 1) """ # Convert flagbyte to integer flagbyte_int = BytesUtils.ToInteger(flagbyte) # Get bit set in flagbyte has_lot_seq = BitUtils.IsBitSet(flagbyte_int, Bip38EcConst.FLAG_BIT_LOT_SEQ) pub_key_mode = (Bip38PubKeyModes.COMPRESSED if BitUtils.IsBitSet(flagbyte_int, Bip38EcConst.FLAG_BIT_COMPRESSED) else Bip38PubKeyModes.UNCOMPRESSED) # Check flagbyte flagbyte_int = BitUtils.ResetBit(flagbyte_int, Bip38EcConst.FLAG_BIT_LOT_SEQ) flagbyte_int = BitUtils.ResetBit(flagbyte_int, Bip38EcConst.FLAG_BIT_COMPRESSED) if flagbyte_int != 0: raise ValueError(f"Invalid flagbyte ({BytesUtils.ToHexString(flagbyte)})") return pub_key_mode, has_lot_seq
def EncodeKey(pub_key: Union[bytes, IPublicKey], **kwargs: Any) -> str: """ Encode a public key to Ethereum address. Args: pub_key (bytes or IPublicKey): Public key bytes or object Other Parameters: skip_chksum_enc (bool, optional): True to skip checksum encoding, false otherwise (default) Returns: str: Address string Raised: ValueError: If the public key is not valid TypeError: If the public key is not secp256k1 """ skip_chksum_enc = kwargs.get("skip_chksum_enc", False) pub_key_obj = AddrKeyValidator.ValidateAndGetSecp256k1Key(pub_key) # First byte of the uncompressed key (i.e. 0x04) is not needed kekkak_hex = BytesUtils.ToHexString( CryptoUtils.Kekkak256(pub_key_obj.RawUncompressed().ToBytes()[1:])) addr = kekkak_hex[EthAddrConst.START_BYTE:] return CoinsConf.Ethereum.Params("addr_prefix") + ( _EthAddrUtils.ChecksumEncode(addr) if not skip_chksum_enc else addr)
def FromEntropy(self, entropy_bytes: bytes) -> Mnemonic: """ Generate mnemonic from the specified entropy bytes. Because of the mnemonic encoding algorithm used by Electrum, the specified entropy will only be a starting point to find a suitable one. Therefore, it's very likely that the actual entropy bytes will be different. To get the actual entropy bytes, just decode the generated mnemonic. Please note that, to successfully generate a mnemonic, the bits of the big endian integer encoded entropy shall be at least 121 (for 12 words) or 253 (for 24 words). Otherwise, a mnemonic generation is not possible and a ValueError exception will be raised. Args: entropy_bytes (bytes): Entropy bytes Returns: Mnemonic object: Generated mnemonic Raises: ValueError: If entropy byte length is not valid or a mnemonic cannot be generated """ # Do not waste time trying if the entropy bit are not enough if ElectrumV2EntropyGenerator.AreEntropyBitsEnough(entropy_bytes): # Same of Electrum: increase the entropy until a valid one is found entropy_int = BytesUtils.ToInteger(entropy_bytes) for i in range(ElectrumV2MnemonicGeneratorConst.MAX_ATTEMPTS): new_entropy_int = entropy_int + i try: return self.m_mnemonic_encoder.Encode(IntegerUtils.ToBytes(new_entropy_int)) except ValueError: continue raise ValueError("Unable to generate a valid mnemonic")
def DecodeAddr(addr: str, **kwargs: Any) -> bytes: """ Decode an Ethereum address to bytes. Args: addr (str): Address string Other Parameters: skip_chksum_enc (bool, optional): True to skip checksum encoding verification, false otherwise (default) Returns: bytes: Public key hash bytes Raises: ValueError: If the address encoding is not valid """ skip_chksum_enc = kwargs.get("skip_chksum_enc", False) # Validate and remove prefix addr_no_prefix = AddrDecUtils.ValidateAndRemovePrefix( addr, CoinsConf.Ethereum.Params("addr_prefix")) # Validate length AddrDecUtils.ValidateLength(addr_no_prefix, EthAddrConst.ADDR_LEN) # Check checksum encoding if not skip_chksum_enc and addr_no_prefix != _EthAddrUtils.ChecksumEncode( addr_no_prefix): raise ValueError("Invalid checksum encode") return BytesUtils.FromHexString(addr_no_prefix)
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 """ # Remove the 0x00 prefix if present if (len(key_bytes) == cls.CompressedLength() and key_bytes[0] == BytesUtils.ToInteger(Ed25519KeysConst.PUB_KEY_PREFIX)): key_bytes = key_bytes[1:] # The library does not raise any exception in case of length error elif len(key_bytes) != cls.CompressedLength() - 1: raise ValueError("Invalid public key bytes") # The library doesn't check if the point lies on curve try: ed25519_lib.point_decode(key_bytes) except ValueError as ex: raise ValueError("Invalid public key bytes") from ex return cls(ed25519_blake2b.VerifyingKey(key_bytes))
def Encode(self, entropy_bytes: bytes) -> Mnemonic: """ Encode bytes to mnemonic phrase. Args: entropy_bytes (bytes): Entropy bytes Returns: Mnemonic object: Encoded mnemonic Raises: ValueError: If bytes length is not valid or a mnemonic cannot be generated """ # Check entropy length entropy_int = BytesUtils.ToInteger(entropy_bytes) if not ElectrumV2EntropyGenerator.AreEntropyBitsEnough(entropy_int): raise ValueError("Entropy bit length is not enough for generating a valid mnemonic") # Encode to words n = self.m_words_list.Length() mnemonic = [] while entropy_int > 0: word_idx = entropy_int % n entropy_int //= n mnemonic.append(self.m_words_list.GetWordAtIdx(word_idx)) # Check if the mnemonic is valid mnemonic_obj = ElectrumV2Mnemonic.FromList(mnemonic) if not ElectrumV2MnemonicUtils.IsValidMnemonic(mnemonic_obj, self.m_mnemonic_type): raise ValueError("Entropy bytes are not suitable for generating a valid mnemonic") return mnemonic_obj
def DecodeAddr(addr: str, **kwargs: Any) -> bytes: """ Decode a Tron address to bytes. Args: addr (str): Address string **kwargs : Not used Returns: bytes: Public key hash bytes Raises: ValueError: If the address encoding is not valid """ try: # Decode from base58 addr_dec = Base58Decoder.CheckDecode(addr) except Base58ChecksumError as ex: raise ValueError("Invalid base58 checksum") from ex else: # Validate length AddrDecUtils.ValidateLength( addr_dec, (EthAddrConst.ADDR_LEN // 2) + len(CoinsConf.Tron.Params("addr_prefix"))) # Validate and remove prefix addr_no_prefix = AddrDecUtils.ValidateAndRemovePrefix( addr_dec, CoinsConf.Tron.Params("addr_prefix")) return EthAddrDecoder.DecodeAddr( CoinsConf.Ethereum.Params("addr_prefix") + BytesUtils.ToHexString(addr_no_prefix), skip_chksum_enc=True)
def DecodeAddr(addr: str, **kwargs: Any) -> bytes: """ Decode a OKEx Chain address to bytes. Args: addr (str): Address string **kwargs : Not used Returns: bytes: Public key hash bytes Raises: ValueError: If the address encoding is not valid """ try: addr_dec_bytes = Bech32Decoder.Decode(CoinsConf.OkexChain.Params("addr_hrp"), addr) except Bech32ChecksumError as ex: raise ValueError("Invalid bech32 checksum") from ex else: return EthAddrDecoder.DecodeAddr( CoinsConf.Ethereum.Params("addr_prefix") + BytesUtils.ToHexString(addr_dec_bytes), skip_chksum_enc=True )
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 Encode(self, entropy_bytes: bytes) -> Mnemonic: """ Encode bytes to mnemonic phrase. Args: entropy_bytes (bytes): Entropy bytes (accepted lengths in bits: 128, 160, 192, 224, 256) Returns: Mnemonic object: Encoded mnemonic Raises: ValueError: If entropy is not valid """ # Check entropy length entropy_byte_len = len(entropy_bytes) if not Bip39EntropyGenerator.IsValidEntropyByteLen(entropy_byte_len): raise ValueError( f"Entropy byte length ({entropy_byte_len}) is not valid") # Convert entropy to binary string entropy_bin_str = BytesUtils.ToBinaryStr(entropy_bytes, entropy_byte_len * 8) # Get entropy hash as binary string entropy_hash_bin_str = BytesUtils.ToBinaryStr( CryptoUtils.Sha256(entropy_bytes), CryptoUtils.Sha256DigestSize() * 8) # Get mnemonic binary string by concatenating entropy and checksum mnemonic_bin_str = entropy_bin_str + entropy_hash_bin_str[:entropy_byte_len // 4] # Get mnemonic from entropy mnemonic = [] for i in range( len(mnemonic_bin_str) // Bip39MnemonicConst.WORD_BIT_LEN): # Get current word index word_bin_str = ( mnemonic_bin_str[i * Bip39MnemonicConst.WORD_BIT_LEN:(i + 1) * Bip39MnemonicConst.WORD_BIT_LEN]) word_idx = IntegerUtils.FromBinaryStr(word_bin_str) # Get word at given index mnemonic.append(self.m_words_list.GetWordAtIdx(word_idx)) return Bip39Mnemonic.FromList(mnemonic)
class P2TRConst: """Class container for P2TR constants.""" # Secp256k1 field size FIELD_SIZE: int = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F # SHA256 of "TapTweak" TAP_TWEAK_SHA256: bytes = BytesUtils.FromHexString( "e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9" ) # Witness version is fixed to one for P2TR WITNESS_VER: int = 1
def ComputeChecksum(payload_bytes: bytes) -> bytes: """ Compute checksum in Stellar format. Args: payload_bytes (bytes): Payload bytes Returns: bytes: Computed checksum """ return BytesUtils.Reverse(CryptoUtils.XModemCrc(payload_bytes))
def ComputeChecksum(pub_key_bytes: bytes) -> bytes: """ Compute checksum in Nano format. Args: pub_key_bytes (bytes): Public key bytes Returns: bytes: Computed checksum """ return BytesUtils.Reverse( CryptoUtils.Blake2b(pub_key_bytes, digest_size=NanoAddrConst.CHECKSUM_BYTE_LEN))
def FromBytes(cls, point_bytes: bytes) -> IPoint: """ Construct class from point bytes. Args: point_bytes (bytes): Point bytes Returns: IPoint: IPoint object """ try: return cls( ellipticcurve.PointJacobi.from_bytes(curve_256, point_bytes)) except keys.MalformedPointError as ex: raise ValueError("Invalid point key bytes") from ex # ECDSA < 0.17 doesn't have from_bytes method for PointJacobi except AttributeError: return cls.FromCoordinates( BytesUtils.ToInteger( point_bytes[:EcdsaKeysConst.POINT_COORD_BYTE_LEN]), BytesUtils.ToInteger( point_bytes[EcdsaKeysConst.POINT_COORD_BYTE_LEN:]))
def FromBytes(cls, index_bytes: bytes) -> Bip32KeyIndex: """ Construct class from bytes. Args: index_bytes (bytes): Key index bytes Returns: Bip32KeyIndex object: Bip32KeyIndex object Raises: ValueError: If the index is not valid """ return cls(BytesUtils.ToInteger(index_bytes))
def TweakPublicKey(pub_key: IPublicKey) -> bytes: """ Tweak a public key as defined by BIP-0086. tweaked_pub_key = lift_x(pub_key.X()) + int(HashTapTweak(bytes(pub_key.X()))) * G Args: pub_key (IPublicKey object): Public key Returns: bytes: X coordinate of the tweaked public key """ h = _P2TRUtils.HashTapTweak(pub_key) out_point = _P2TRUtils.LiftX(pub_key) + (BytesUtils.ToInteger(h) * Secp256k1.Generator()) return IntegerUtils.ToBytes(out_point.X())
def ComputeKeys(self, minor_idx: int, major_idx: int) -> Tuple[MoneroPublicKey, MoneroPublicKey]: """ Compute the public keys of the specified subaddress. Args: minor_idx (int): Minor index (i.e. subaddress index) major_idx (int): Major index (i.e. account index) Returns: tuple[MoneroPublicKey, MoneroPublicKey]: Computed public spend key (index 0) and public view key (index 1) Raises: ValueError: If one of the indexes is not valid """ if minor_idx < 0 or minor_idx > MoneroSubaddressConst.SUBADDR_MAX_IDX: raise ValueError(f"Invalid minor index ({minor_idx})") if major_idx < 0 or major_idx > MoneroSubaddressConst.SUBADDR_MAX_IDX: raise ValueError(f"Invalid major index ({major_idx})") # Subaddress 0,0 is the primary address if minor_idx == 0 and major_idx == 0: return self.m_pub_skey, self.m_pub_vkey # Convert indexes to bytes major_idx_bytes = IntegerUtils.ToBytes(major_idx, bytes_num=MoneroSubaddressConst.SUBADDR_IDX_BYTE_LEN, endianness="little") minor_idx_bytes = IntegerUtils.ToBytes(minor_idx, bytes_num=MoneroSubaddressConst.SUBADDR_IDX_BYTE_LEN, endianness="little") # m = Kekkak256("SubAddr" + master_priv_vkey + major_idx + minor_idx) m = CryptoUtils.Kekkak256(MoneroSubaddressConst.SUBADDR_PREFIX + self.m_priv_vkey.Raw().ToBytes() + major_idx_bytes + minor_idx_bytes) m_int = BytesUtils.ToInteger(m, endianness="little") # Compute subaddress public spend key # D = master_pub_skey + m * B subaddr_pub_skey_point = self.m_pub_skey.KeyObject().Point() + (Ed25519Monero.Generator() * m_int) # Compute subaddress public view key # C = master_priv_vkey * D subaddr_pub_vkey_point = subaddr_pub_skey_point * self.m_priv_vkey.Raw().ToInt("little") return (MoneroPublicKey.FromBytes(subaddr_pub_skey_point.RawEncoded().ToBytes()), MoneroPublicKey.FromBytes(subaddr_pub_vkey_point.RawEncoded().ToBytes()))
def AreEntropyBitsEnough(entropy: Union[bytes, int]) -> bool: """ Get if the entropy bits are enough to generate a valid mnemonic. Args: entropy (bytes or int): Entropy Returns: bool: True if enough, false otherwise """ if isinstance(entropy, bytes): entropy = BytesUtils.ToInteger(entropy) entropy_bit_len = 0 if entropy <= 0 else math.floor( math.log(entropy, 2)) return ElectrumV2EntropyGenerator.IsValidEntropyBitLen(entropy_bit_len)
def ScReduce(data_bytes: bytes) -> bytes: """ Convert the specified bytes to integer and return its lowest 32-bytes modulo ed25519-order. This ensures that the result is a valid ed25519 scalar to be used as Monero private key. Args: data_bytes (bytes): Data bytes Returns: bytes: Lowest 32-bytes modulo ed25519-order """ data_int = BytesUtils.ToInteger(data_bytes, endianness="little") return IntegerUtils.ToBytes(data_int % Ed25519Monero.Order(), bytes_num=32, endianness="little")
def PassPoint(passfactor: bytes) -> bytes: """ Compute the passpoint as specified in BIP38 (with EC multiplication). Args: passfactor (bytes): Passfactor Returns: bytes: Passpoint bytes in compressed format """ # Compute passpoint passpoint = Secp256k1PublicKey.FromPoint(Secp256k1.Generator() * BytesUtils.ToInteger(passfactor)) # Return it as a compressed public key return passpoint.RawCompressed().ToBytes()
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())