示例#1
0
 /// <summary>
 /// Constructor. Creates a new extended key with a random 64 byte seed.
 /// </summary>
 public ExtKey()
 {
     byte[] seed = RandomUtils.GetBytes(64);
     SetMaster(seed);
 }
示例#2
0
        public EncryptedKeyResult GenerateEncryptedSecret(bool isCompressed = true, byte[] seedb = null)
        {
            //Set flagbyte.
            byte flagByte = 0;

            //Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key
            flagByte |= isCompressed ? (byte)0x20 : (byte)0x00;
            flagByte |= this.LotSequence != null ? (byte)0x04 : (byte)0x00;

            //Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb.
            seedb = seedb ?? RandomUtils.GetBytes(24);

            byte[] factorb = Hashes.Hash256(seedb).ToBytes();

            //ECMultiply passpoint by factorb.
            X9ECParameters curve     = ECKey.Secp256k1;
            ECPoint        passpoint = curve.Curve.DecodePoint(this.Passpoint);
            ECPoint        pubPoint  = passpoint.Multiply(new BigInteger(1, factorb));

            //Use the resulting EC point as a public key
            var pubKey = new PubKey(pubPoint.GetEncoded());

            //and hash it into a Bitcoin address using either compressed or uncompressed public key
            //This is the generated Bitcoin address, call it generatedaddress.
            pubKey = isCompressed ? pubKey.Compress() : pubKey.Decompress();

            //call it generatedaddress.
            BitcoinPubKeyAddress generatedaddress = pubKey.GetAddress(this.Network);

            //Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash.
            byte[] addresshash = BitcoinEncryptedSecretEC.HashAddress(generatedaddress);

            //Derive a second key from passpoint using scrypt
            //salt is addresshash + ownerentropy
            byte[] derived = BitcoinEncryptedSecretEC.CalculateDecryptionKey(this.Passpoint, addresshash, this.OwnerEntropy);

            //Now we will encrypt seedb.
            byte[] encrypted = BitcoinEncryptedSecret.EncryptSeed
                                   (seedb,
                                   derived);

            //0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 which totals 39 bytes
            byte[] bytes =
                new[] { flagByte }
            .Concat(addresshash)
            .Concat(this.OwnerEntropy)
            .Concat(encrypted.Take(8).ToArray())
            .Concat(encrypted.Skip(16).ToArray())
            .ToArray();

            var encryptedSecret = new BitcoinEncryptedSecretEC(bytes, this.Network);

            return(new EncryptedKeyResult(encryptedSecret, generatedaddress, seedb, () =>
            {
                //ECMultiply factorb by G, call the result pointb. The result is 33 bytes.
                byte[] pointb = new Key(factorb).PubKey.ToBytes();
                //The first byte is 0x02 or 0x03. XOR it by (derivedhalf2[31] & 0x01), call the resulting byte pointbprefix.
                byte pointbprefix = (byte)(pointb[0] ^ (byte)(derived[63] & 0x01));
                byte[] pointbx = BitcoinEncryptedSecret.EncryptKey(pointb.Skip(1).ToArray(), derived);
                byte[] encryptedpointb = new byte[] { pointbprefix }.Concat(pointbx).ToArray();

                byte[] confirmBytes = this.Network.GetVersionBytes(Base58Type.CONFIRMATION_CODE, true)
                                      .Concat(new[] { flagByte })
                                      .Concat(addresshash)
                                      .Concat(this.OwnerEntropy)
                                      .Concat(encryptedpointb)
                                      .ToArray();

                return new BitcoinConfirmationCode(Encoders.Base58Check.EncodeData(confirmBytes), this.Network);
            }));
        }
示例#3
0
        /// <summary>
        /// Generate a mnemonic
        /// </summary>
        /// <param name="wordList"></param>
        /// <param name="entropy"></param>
        public Mnemonic(Wordlist wordList, byte[] entropy = null)
        {
            wordList  = wordList ?? Wordlist.English;
            _WordList = wordList;
            if (entropy == null)
            {
                entropy = RandomUtils.GetBytes(32);
            }
            byte[] allChecksumBytes = Hashes.SHA256(entropy);               //sha256 the entropy bytes to get all the checksum bits

            int      numberOfChecksumBits      = (entropy.Length * 8) / 32; //number of bits to take from the checksum bits, varies on entropy size as per spec
            BitArray entropyConcatChecksumBits = new BitArray((entropy.Length * 8) + numberOfChecksumBits);

            allChecksumBytes = SwapEndianBytes(allChecksumBytes);             //yet another endianess change of some different bytes to match the test vectors.....

            entropy = SwapEndianBytes(entropy);

            int index = 0;

            foreach (bool b in new BitArray(entropy))
            {
                entropyConcatChecksumBits.Set(index, b);
                index++;
            }

            /*sooooo I'm doing below for future proofing....I know right now we are using up to 256 bits entropy in real world implementation and therefore max 8 bits (1 byte) of checksum....buuuut I figgure it's easy enough
             * to accomodate more entropy by chaining more checksum bytes so maximum 256 * 32 = 8192 theoretical maximum entropy (plus CS).*/
            List <byte> checksumBytesToUse = new List <byte>();

            double byteCount = Math.Ceiling((double)numberOfChecksumBits / 8);

            for (int i = 0; i < byteCount; i++)
            {
                checksumBytesToUse.Add(allChecksumBytes[i]);
            }

            BitArray ba = new BitArray(checksumBytesToUse.ToArray());

            //add checksum bits
            for (int i = 0; i < numberOfChecksumBits; i++)
            {
                entropyConcatChecksumBits.Set(index, ba.Get(i));
                index++;
            }


            List <int> wordIndexList = new List <int>();

            //yea....loop in a loop....what of it!!! Outer loop is segregating bits into 11 bit groups and the inner loop is processing the 11 bits before sending them to be encoded as an int.
            for (int i = 0; i < entropyConcatChecksumBits.Length; i = i + 11)
            {
                BitArray toInt = new BitArray(11);
                for (int i2 = 0; i2 < 11 && i < entropyConcatChecksumBits.Length; i2++)
                {
                    toInt.Set(i2, entropyConcatChecksumBits.Get(i + i2));
                }

                wordIndexList.Add(ToInt(toInt));                 //adding encoded int to word index
            }

            _Indices = wordIndexList.ToArray();
            _Words   = new string[_Indices.Length];

            StringBuilder builder = new StringBuilder();

            for (int i = 0; i < _Indices.Length; i++)
            {
                var word = _WordList.GetWordAtIndex(_Indices[i]);
                _Words[i] = word;
                builder.Append(word);
                if (i + 1 < _Indices.Length)
                {
                    builder.Append(_WordList.Space);
                }
            }
            _Mnemonic = builder.ToString();
        }