예제 #1
0
        public static ExtendedKey Parse(string serialized)
        {
            byte[] data = Base58Encoding.DecodeWithCheckSum(serialized);
            Thrower.Condition <AddressException>(data.Length != 78, "invalid extended key");

            using (var stream = new MemoryStream(data))
            {
                using (var binReader = new BinaryReader(stream))
                {
                    var ext = binReader.ReadBytes(4);
                    Thrower.Condition <AddressException>(!(ext.SequenceEqual(Xprv) || ext.SequenceEqual(Xpub)), "invalid magic number for an extended key");

                    var isPrivate   = ext.SequenceEqual(Xprv);
                    var depth       = binReader.ReadByte();
                    var fingerprint = binReader.ReadBytes(4);
                    var index       = BitHelper.ToUInt32(binReader.ReadBytes(4), false);
                    var chainCode   = binReader.ReadBytes(32);
                    var rawKey      = binReader.ReadBytes(33);

                    BitcoinKey key;
                    if (isPrivate)
                    {
                        key = new BitcoinPrivateKey(rawKey.Skip(1).ToArray());
                    }
                    else
                    {
                        key = new BitcoinPublicKey(rawKey);
                    }

                    return(new ExtendedKey(key, chainCode, depth, fingerprint, index));
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BitcoinPrivateKey"/> class.
        /// Parses the given private key as created by the BitCoin C++ RPC.
        /// </summary>
        /// <param name="coinParameters">
        /// The expected header parameters of the key. If you don't care, provide null.
        /// </param>
        /// <param name="encoded">
        /// The base58 encoded string.
        /// </param>
        public BitcoinPrivateKey(CoinParameters coinParameters, string encoded)
        {
            var decoded = Base58Encoding.DecodeWithCheckSum(encoded);
            var version = decoded.First();

            Thrower.Condition <ArgumentException>(coinParameters.PrivateKeyVersion != version, string.Format("Mismatched version number, trying to cross networks? expected={0} found={1}", coinParameters.PrivateKeyVersion, version));

            var bytes = decoded.Skip(1).ToArray();

            this.Compressed = false;

            if (bytes.Length == 33)
            {
                // private key associated with a compressed public key
                Thrower.Condition <ArgumentException>(bytes.Last() != CompressedBytes.First(), string.Format("Invalid private key"));

                bytes           = bytes.Take(32).ToArray();
                this.Compressed = true;
            }

            // 256 bit keys
            Thrower.Condition <ArgumentException>(bytes.Length != Length, string.Format("Keys are 256 bits, so you must provide {0} bytes, got {1}", Length, bytes.Length));

            this.Bytes = bytes;
        }
예제 #3
0
        private ExtendedKey GenerateKey(uint index)
        {
            Thrower.Condition <AddressException>((index & HardendIndex) != 0 && !this.Master.HasPrivateKey, "A public key can't derivate an hardened child");

            byte[] extended;
            byte[] pub = this.Master.PublicKey.Bytes;
            if ((index & HardendIndex) == 0)
            {
                var sequenceBytes = BitHelper.GetBytes(index, false);
                extended = pub.ToArray().Concat(sequenceBytes).ToArray();
            }
            else
            {
                var priv          = this.Master.PrivateKey.Bytes;
                var sequenceBytes = BitHelper.GetBytes(index, false);
                extended = (new byte[] { 0 }).Concat(priv.ToArray()).Concat(sequenceBytes).ToArray();
            }

            var leftRight = CryptoUtil.ComputeHmac512(this.ChainCode, extended);
            var leftKey   = leftRight.Take(32).ToArray();
            var rightKey  = leftRight.Skip(32).ToArray();

            BigInteger bigIntegerLeft = new BigInteger(1, leftKey);

            Thrower.Condition <AddressException>(bigIntegerLeft.CompareTo(EcKey.EcParams.N) >= 0, "This is rather unlikely, but it did just happen");

            if (this.Master.HasPrivateKey)
            {
                BigInteger key = bigIntegerLeft.Add(new BigInteger(1, this.Master.PrivateKey.Bytes)).Mod(EcKey.EcParams.N);
                Thrower.Condition <AddressException>(key.Equals(BigInteger.Zero), "This is rather unlikely, but it did just happen");

                ////  fix the private key in case it needs padding
                var keyBytes = new EcKey(key).GetPrivKeyBytes();

                return(new ExtendedKey(new BitcoinPrivateKey(keyBytes), rightKey, (byte)(this.Depth + 1), this.GenerateFingerPrint(), index));
            }
            else
            {
                var qdecoded = EcKey.EcParams.Curve.DecodePoint(this.Master.PublicKey.Bytes);
                var key      = new ECPublicKeyParameters("EC", qdecoded, EcKey.EcParams);

                var qkey = EcKey.EcParams.G.Multiply(bigIntegerLeft).Add(key.Q);
                Thrower.Condition <AddressException>(qkey.IsInfinity, "This is rather unlikely, but it did just happen");

                var point = new FpPoint(EcKey.EcParams.Curve, qkey.Normalize().XCoord, qkey.Normalize().YCoord, true);

                return(new ExtendedKey(new BitcoinPublicKey(point.GetEncoded()), rightKey, (byte)(this.Depth + 1), this.GenerateFingerPrint(), index));
            }
        }
예제 #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="BitcoinPrivateKey"/> class.
 /// </summary>
 /// <param name="keyBytes">
 /// The key bytes.
 /// </param>
 public BitcoinPrivateKey(byte[] keyBytes)
     : base(keyBytes)
 {
     // 256 bit keys
     Thrower.Condition <ArgumentException>(keyBytes.Length != Length, string.Format("Keys are 256 bits, so you must provide {0} bytes, got {1}", Length, keyBytes.Length));
 }