Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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())
Ejemplo n.º 4
0
    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())
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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())
Ejemplo n.º 8
0
    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())