Example #1
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);
            }));
        }
        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 |= 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);

            var factorb = Hashes.DoubleSHA256(seedb).ToBytes();

            //ECMultiply passpoint by factorb.
#if HAS_SPAN
            if (!NBitcoinContext.Instance.TryCreatePubKey(Passpoint, out var eckey) || eckey is null)
            {
                throw new InvalidOperationException("Invalid Passpoint");
            }
            var pubKey = new PubKey(eckey.TweakMul(factorb), isCompressed);
#else
            var curve     = ECKey.Secp256k1;
            var passpoint = curve.Curve.DecodePoint(Passpoint);
            var 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();
#endif

            //call it generatedaddress.
            var generatedaddress = pubKey.GetAddress(ScriptPubKeyType.Legacy, Network);

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

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

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

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

            var encryptedSecret = new BitcoinEncryptedSecretEC(bytes, Network);

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

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

                return new BitcoinConfirmationCode(Network.NetworkStringParser.GetBase58CheckEncoder().EncodeData(confirmBytes), Network);
            }));
        }
		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 |= 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);

			var factorb = Hashes.Hash256(seedb).ToBytes();

			//ECMultiply passpoint by factorb.
			var curve = ECKey.Secp256k1;
			var passpoint = curve.Curve.DecodePoint(Passpoint);
			var 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.
			var generatedaddress = pubKey.GetAddress(Network);

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

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

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

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

			var encryptedSecret = new BitcoinEncryptedSecretEC(bytes, Network);

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

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

				return new BitcoinConfirmationCode(Encoders.Base58Check.EncodeData(confirmBytes), Network);
			});
		}
        public bool Check(string passphrase, BitcoinAddress expectedAddress)
        {
            //Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint
            byte[] passfactor = BitcoinEncryptedSecretEC.CalculatePassFactor(passphrase, LotSequence, OwnerEntropy);
            //Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy
            byte[] passpoint = BitcoinEncryptedSecretEC.CalculatePassPoint(passfactor);
            byte[] derived = BitcoinEncryptedSecretEC.CalculateDecryptionKey(passpoint, AddressHash, OwnerEntropy);

            //Decrypt encryptedpointb to yield pointb
            var pointbprefix = EncryptedPointB[0];
            pointbprefix = (byte)(pointbprefix ^ (byte)(derived[63] & (byte)0x01));

            //Optional since ArithmeticException will catch it, but it saves some times
            if(pointbprefix != 0x02 && pointbprefix != 0x03)
                return false;
            var pointb = BitcoinEncryptedSecret.DecryptKey(EncryptedPointB.Skip(1).ToArray(), derived);
            pointb = new byte[] { pointbprefix }.Concat(pointb).ToArray();

            //4.ECMultiply pointb by passfactor. Use the resulting EC point as a public key
            var curve = ECKey.CreateCurve();
            ECPoint pointbec = null;
            try
            {
                pointbec = curve.Curve.DecodePoint(pointb);
            }
            catch(ArithmeticException)
            {
                return false;
            }
            PubKey pubkey = new PubKey(pointbec.Multiply(new BigInteger(1, passfactor)).GetEncoded());

            //and hash it into address using either compressed or uncompressed public key methodology as specifid in flagbyte.
            pubkey = IsCompressed ? pubkey.Compress() : pubkey.Decompress();

            var actualhash = BitcoinEncryptedSecretEC.HashAddress(pubkey.GetAddress(Network));
            var expectedhash = BitcoinEncryptedSecretEC.HashAddress(expectedAddress);

            return Utils.ArrayEqual(actualhash, expectedhash);
        }
 private static byte[] GenerateBytes(PubKey scanKey, PubKey[] pubKeys, BitField bitField, int signatureCount)
 {
     MemoryStream ms = new MemoryStream();
     ms.WriteByte(0); //Options
     ms.Write(scanKey.Compress().ToBytes(), 0, 33);
     ms.WriteByte((byte)pubKeys.Length);
     foreach(var key in pubKeys)
     {
         ms.Write(key.Compress().ToBytes(), 0, 33);
     }
     ms.WriteByte((byte)signatureCount);
     if(bitField == null)
         ms.Write(new byte[] { 0 }, 0, 1);
     else
     {
         ms.WriteByte((byte)bitField.BitCount);
         var raw = bitField.GetRawForm();
         ms.Write(raw, 0, raw.Length);
     }
     return ms.ToArray();
 }