Ejemplo n.º 1
0
        /// <summary>
        /// Obtains a child extended key, relative from this key, at the given child key/index.
        /// </summary>
        /// <param name="index">The child key/index to obtain the extended key for, relative from this extended key.</param>
        /// <returns>Returns a extended key for the provided child key/index, relative from this extended key.</returns>
        public ExtendedKey GetChildKey(uint index)
        {
            // Obtain our key and chain code for our child.
            (EthereumEcdsa childKey, byte[] childChainCode) = GetChildKeyInternal(index);

            // Initialize a new extended private key using this current key at the given child key.
            ExtendedKey extendedChildKey = new ExtendedKey(childKey, childChainCode, Depth + 1, index, GetChildFingerprint());

            // Return the extended child key.
            return(extendedChildKey);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Obtains a child extended key, relative from this key, at the given key path.
        /// </summary>
        /// <param name="keyPath">The path of the child extended key to derive, relative from this extended key.</param>
        /// <returns>Returns an extended key for a child relative from this key, at the provided key path.</returns>
        public ExtendedKey GetChildKey(KeyPath keyPath)
        {
            // Declare our current private key.
            ExtendedKey current = this;

            // Loop for each index in the key path.
            foreach (uint index in keyPath.Indices)
            {
                current = current.GetChildKey(index);
            }

            // Return our private key
            return(current);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Determines if the provided key is a child key to this current key.
        /// </summary>
        /// <param name="childKey">The key to determine is a child key or not.</param>
        /// <returns>Returns true if the provided key is a child to this key.</returns>
        public bool IsChild(ExtendedKey childKey)
        {
            // Verify depth
            if (childKey.Depth != Depth + 1)
            {
                return(false);
            }

            // If the child's fingerprint is null, it is not a child.
            if (childKey.Fingerprint == null)
            {
                return(false);
            }

            // Verify the fingerprint equals
            byte[] expectedChildFingerprint = GetChildFingerprint();
            return(expectedChildFingerprint.SequenceEqual(childKey.Fingerprint));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Obtains the parent private key if provided the parent public key. This key must be a private key.
        /// </summary>
        /// <param name="parentPublicKey">The public key of the parent of this extended key.</param>
        /// <returns>Returns the private key of the parent of this extended key.</returns>
        public ExtendedKey GetParentPrivateKey(ExtendedKey parentPublicKey)
        {
            // Verify this key is a private key
            if (KeyType != EthereumEcdsaKeyType.Private)
            {
                // This key is not a private key.
                throw new ArgumentNullException("Could not obtain parent private key. Can only obtain the parent private key of a private key. This key is a public key.");
            }
            else if (parentPublicKey == null)
            {
                // The public key is null.
                throw new ArgumentNullException("Could not obtain parent private key. Provided parent public key argument is null.");
            }
            else if (parentPublicKey.KeyType == EthereumEcdsaKeyType.Private)
            {
                // The public key was not a public key.
                throw new ArgumentException("Could not obtain parent private key. Provided parent public key argument is not a public key.");
            }
            else if (Hardened)
            {
                throw new ArgumentException("Could not obtain parent private key if this key is a hardened key.");
            }
            else if (Depth == 0)
            {
                throw new ArgumentException("Could not obtain parent private key for this key because this key is a top level key.");
            }
            else if (!parentPublicKey.IsChild(this))
            {
                // The provided parent public key is not a parent.
                throw new ArgumentException("Could not obtain parent private key for this key because the provided parent public key argument is not a parent to this key.");
            }

            // Obtain the hash used to derive this current key, from the parent.
            byte[] hash = parentPublicKey.ComputeChildHash(ChildIndex, parentPublicKey.InternalKey.ToPublicKeyArray(true, false));

            // Set the child key data as the first 32 bytes of "hash"
            byte[] childKeyData = new byte[EthereumEcdsa.PRIVATE_KEY_SIZE];
            Array.Copy(hash, 0, childKeyData, 0, childKeyData.Length);

            // Initialize the child chain code
            byte[] childChainCode = new byte[CHAIN_CODE_SIZE];

            // We derive the child chain code as the data immediately following key data.
            Array.Copy(hash, 32, childChainCode, 0, childChainCode.Length);

            // Verify the chain code is equal
            if (!ChainCode.SequenceEqual(childChainCode))
            {
                throw new ArgumentException("Derived chain code from the parent at this key's child index that did not match this key's chain code.");
            }

            // Convert the key data to an integer
            BigInteger childKeyInt = BigIntegerConverter.GetBigInteger(childKeyData, false, childChainCode.Length);

            // Convert this private key to an integer
            byte[]     thisKeyData = InternalKey.ToPrivateKeyArray();
            BigInteger thisKeyInt  = BigIntegerConverter.GetBigInteger(thisKeyData, false, thisKeyData.Length);

            // Compute our parent key
            BigInteger parentPrivateKeyInt = ((thisKeyInt - childKeyInt) + Secp256k1Curve.N) % Secp256k1Curve.N;

            // Obtain our new key from this
            byte[] computedParentKeyData = BigIntegerConverter.GetBytes(parentPrivateKeyInt, EthereumEcdsa.PRIVATE_KEY_SIZE);

            // Obtain the parent private key
            EthereumEcdsa parentPrivateKey = EthereumEcdsa.Create(computedParentKeyData, EthereumEcdsaKeyType.Private);

            // Create the parent extended private key
            return(new ExtendedKey(parentPrivateKey, parentPublicKey.ChainCode, parentPublicKey.Depth, parentPublicKey.ChildIndex, parentPublicKey.Fingerprint));
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Determines if the provided key is a parent key to this current key.
 /// </summary>
 /// <param name="parentKey">The key to determine is a parent key or not.</param>
 /// <returns>Returns true if the provided key is the parent to this key.</returns>
 public bool IsParent(ExtendedKey parentKey)
 {
     // Determine if this is a child of the parent key.
     return(parentKey.IsChild(this));
 }