Exemple #1
0
		public StealthPayment(BitcoinStealthAddress address, Key ephemKey, StealthMetadata metadata)
		{
			Metadata = metadata;
			ScriptPubKey = CreatePaymentScript(address.SignatureCount, address.SpendPubKeys, ephemKey, address.ScanPubKey);

			if(address.SignatureCount > 1)
			{
				Redeem = ScriptPubKey;
				ScriptPubKey = ScriptPubKey.Hash.ScriptPubKey;
			}
			SetStealthKeys();
		}
Exemple #2
0
        public StealthPayment(BitcoinStealthAddress address, Key ephemKey, StealthMetadata metadata)
        {
            Metadata     = metadata;
            ScriptPubKey = CreatePaymentScript(address.SignatureCount, address.SpendPubKeys, ephemKey, address.ScanPubKey);

            if (address.SignatureCount > 1)
            {
                Redeem       = ScriptPubKey;
                ScriptPubKey = ScriptPubKey.Hash.ScriptPubKey;
            }
            SetStealthKeys();
        }
        public static StealthPayment[] GetPayments(Transaction transaction, BitcoinStealthAddress address, Key scan)
        {
            var result = new List <StealthPayment>();

            for (var i = 0; i < transaction.Outputs.Count - 1; i++)
            {
                var metadata = StealthMetadata.TryParse(transaction.Outputs[i].ScriptPubKey);
                if (metadata != null && (address == null || address.Prefix.Match(metadata.BitField)))
                {
                    var    scriptPubKey         = transaction.Outputs[i + 1].ScriptPubKey;
                    var    scriptId             = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
                    var    expectedScriptPubKey = address == null ? scriptPubKey : null;
                    Script redeem = null;

                    if (scriptId != null)
                    {
                        if (address == null)
                        {
                            throw new ArgumentNullException("address");
                        }
                        redeem = CreatePaymentScript(address, metadata.EphemKey, scan);
                        expectedScriptPubKey = redeem.Hash.ScriptPubKey;
                        if (expectedScriptPubKey != scriptPubKey)
                        {
                            continue;
                        }
                    }

                    var payment = new StealthPayment(scriptPubKey, redeem, metadata);
                    if (scan != null)
                    {
                        if (address != null && payment.StealthKeys.Length != address.SpendPubKeys.Length)
                        {
                            continue;
                        }

                        if (expectedScriptPubKey == null)
                        {
                            expectedScriptPubKey = CreatePaymentScript(address, metadata.EphemKey, scan);
                        }

                        if (expectedScriptPubKey != scriptPubKey)
                        {
                            continue;
                        }
                    }

                    result.Add(payment);
                }
            }

            return(result.ToArray());
        }
		public void CanCreatePayment()
		{
			var tests = new[]
			{
				new CanCreatePaymentData
				{
					//sx stealth-newkey
					StealthAddress = "vJmtjxSDxNPXL4RNapp9ARdqKz3uJyf1EDGjr1Fgqs9c8mYsVH82h8wvnA4i5rtJ57mr3kor1EVJrd4e5upACJd588xe52yXtzumxj",

					ScanSecret = "3e49e7257cb31db997edb1cf8299af0f37e2663e2260e4b8033e49d39a6d02f2",
					ScanPubKey = "025e58a31122b38c86abc119b9379fe247410aee87a533f9c07b189aef6c3c1f52",

					SpendSecret = "aa3db0cfb3edc94de4d10f873f8190843f2a17484f6021a95a7742302c744748",
					SpendPubKey = "03616562c98e7d7b74be409a787cec3a912122f3fb331a9bee9b0b73ce7b9f50af",

					//sx newkey | sx wif-to-secret
					EphemSecret = "9e63abaf8dcd5ea3919e6de0b6c544e00bf51bf92496113a01d6e369944dc091",
					EphemPubKey = "03403d306ec35238384c7e340393335f9bc9bb4a2e574eb4e419452c4ea19f14b0",

					//sx steatlh-uncover-secret [EphemPubKey] [ScanSecret] [SpendSecret] 
					StealthSecret = "4e422fb1e5e1db6c1f6ab32a7706d368ceb385e7fab098e633c5c5949c3b97cd",
					//sx stealth-initiate [EphemSecret] [ScanPubKey] [SpendPubKey] (for sender)
					//or 
					//sx stealth-uncover [EphemPubKey] [ScanSecret] [SpendPubKey]  (for receiver)
					StealthPubKey = "02726112ad39cb6bf848b1b1ef30b88e35286bf99f746c2be575f96c0e02a9357c",
				},

				//Need padding for to find the stealth secret
				new CanCreatePaymentData{
					StealthAddress = "vJmyTEybwCKz7W8y6vP62jo7RoyfLneiANcPLBBNYwn98EXzQRStMKqKGRiZhqscuQ6WKy2J3U3zfx72V3b2J6YvxxBcxUj4XMDsw7",
					ScanSecret = "2f517d81cf30e47dbf4809321275bbfd92192af81a6141a17aa53e40bd28fe36",
					ScanPubKey = "039d91ae0eebea6dc500fb57b704abce3d3fa700cc762a52bc5dcaee27770a8402",
					SpendSecret = "71e33219884fc27011f8da9adcc730f0c2e940759bdb1b615764492bce04fcea",
					SpendPubKey = "021a3d5b40ec83fc58b5a23207eb9c99b741d8f0e9f8b80f04f49cec915b540c40",
					EphemSecret = "578ffe42c0fbfb324a31f41dbbcd8b1f910ce2f4d803444a83b18ae9f8ccd97e",
					EphemPubKey = "03c190be0a1c6e50577b3dd637b1fff9344de31c2544ff3d815535c0515711150f",
					StealthSecret = "006d138b4bcef0f09c8784c0cc68f2be4497a1a822d8d7b0519c5c0378b5cb45",
					StealthPubKey = "0223a99278a5279ea93718503a42377067e72960eb808d8bff6defdd95d4feff76"
				}
			};

			foreach(var test in tests)
			{
				var scan = AssertKeys(test.ScanSecret, test.ScanPubKey);
				var spend = AssertKeys(test.SpendSecret, test.SpendPubKey);
				var ephem = AssertKeys(test.EphemSecret, test.EphemPubKey);
				var stealth = AssertKeys(test.StealthSecret, test.StealthPubKey);

				var address = spend.PubKey.CreateStealthAddress(scan.PubKey, Network.Main);
				Assert.Equal(test.StealthAddress, address.ToString());
				//Try roundtrip
				address = new BitcoinStealthAddress(address.ToBytes(), Network.Main);
				Assert.Equal(test.StealthAddress, address.ToString());

				var payment = address.CreatePayment(ephem);
				var generatedKey = spend.Uncover(scan, payment.Metadata.EphemKey);
				if(stealth != null)
				{
					Assert.Equal(stealth.PubKey.Hash, payment.StealthKeys[0].ID);
					Assert.Equal(stealth.ToBytes(), generatedKey.ToBytes());
				}
				var uncoveredSender = spend.PubKey.UncoverSender(ephem, scan.PubKey);
				var uncovertedReceiver = spend.PubKey.UncoverReceiver(scan, ephem.PubKey);

				AssertEx.CollectionEquals(uncoveredSender.ToBytes(), uncovertedReceiver.ToBytes());
				AssertEx.CollectionEquals(generatedKey.PubKey.ToBytes(), uncovertedReceiver.ToBytes());

				var transaction = new Transaction();
				payment.AddToTransaction(transaction, 100);
			}
		}
		public void CanParseStealthAddress()
		{
			var tests = new[] 
			{ 
				//Test vector created with sx
				//sx stealth-newkey -> ScanSecret,SpendSecret,StealthAddress
				//sx stealth-show-addr StealthAddress -> ScanPubKey,SpendPubKey,RequiredSignature...
				new
				{
					ScanSecret = "9ac9fdee7c2c19611bcbed8959e1c61d00cdc27cf17bb50a1f4d29db7f953632",
					SpendSecrets = new[]{
											"4e2fa767cc241c3fa4c512d572b2758a3960a06d374f2c819fe409b161d72ad4"
										},
					StealthAddress = "vJmsmwE8cVt9ytJxBuY2jayh8RAfvpG42CyNVYpeVZAkHaiwASobUEzskpXMwbH1TZNBLoxWWYem5WuZewTL8xz3upJ75zKcdVmTfg",
					ScanPubKey = "021ce89be99a229d123e8bc13ffbcb66722d6200bbeb1d90ddddbf97df82ed2672",
					SpendPubKeys = new[]
										{ 
											"03c197525241d3d70bbf33bb2b54d41e6b9595a92a2c6b7bf7157727c017f0154a"
										},
					RequiredSignature = 1,
					Options = 0,
					PrefixLength = 0,
					PrefixValue = "",
				}
			};
			foreach(var test in tests)
			{
				var scanSecret = new Key(TestUtils.ParseHex(test.ScanSecret));
				AssertEx.CollectionEquals(scanSecret.PubKey.ToBytes(), TestUtils.ParseHex(test.ScanPubKey));

				var stealth = new BitcoinStealthAddress(test.StealthAddress, Network.Main);
				Assert.Equal(test.RequiredSignature, stealth.SignatureCount);
				Assert.Equal(test.PrefixLength, stealth.Prefix.BitCount);
				AssertEx.CollectionEquals(stealth.Prefix.GetRawForm(), TestUtils.ParseHex(test.PrefixValue));
				Assert.Equal(test.Options, stealth.Options);

				AssertEx.CollectionEquals(stealth.ScanPubKey.ToBytes(),
											  TestUtils.ParseHex(test.ScanPubKey));
				for(int i = 0 ; i < test.SpendPubKeys.Length ; i++)
				{
					AssertEx.CollectionEquals(stealth.SpendPubKeys[i].ToBytes(),
											  TestUtils.ParseHex(test.SpendPubKeys[i]));

					var spendSecret = new Key(TestUtils.ParseHex(test.SpendSecrets[i]));
					AssertEx.CollectionEquals(stealth.SpendPubKeys[i].ToBytes(), TestUtils.ParseHex(test.SpendPubKeys[i]));
				}
			}
		}
Exemple #6
0
		public void CanBuildStealthTransaction()
		{
			var stealthKeys = Enumerable.Range(0, 3).Select(_ => new Key()).ToArray();
			var scanKey = new Key();

			var darkSatoshi = new BitcoinStealthAddress(scanKey.PubKey, stealthKeys.Select(k => k.PubKey).ToArray(), 2, new BitField(3, 5), Network.Main);

			var bob = new Key();
			var coins = new Coin[] { 
				new Coin() 
				{ 
					Outpoint = RandOutpoint(),
					TxOut = new TxOut("1.00",bob.PubKey.Hash)
				} };

			//Bob sends money to satoshi
			TransactionBuilder builder = new TransactionBuilder();
			builder.StandardTransactionPolicy = EasyPolicy;
			var tx =
				builder
				.AddCoins(coins)
				.AddKeys(bob)
				.Send(darkSatoshi, "1.00")
				.BuildTransaction(true);
			Assert.True(builder.Verify(tx));

			//Satoshi scans a StealthCoin in the transaction with his scan key
			var stealthCoin = StealthCoin.Find(tx, darkSatoshi, scanKey);
			Assert.NotNull(stealthCoin);

			//Satoshi sends back the money to Bob
			builder = new TransactionBuilder();
			builder.StandardTransactionPolicy = EasyPolicy;
			tx =
				builder
					.AddCoins(stealthCoin)
					.AddKeys(stealthKeys)
					.AddKeys(scanKey)
					.Send(bob.PubKey.Hash, "1.00")
					.BuildTransaction(true);

			Assert.True(builder.Verify(tx)); //Signed !


			//Same scenario, Satoshi wants to send money back to Bob
			//However, his keys are spread on two machines
			//He partially signs on the 1st machine
			builder = new TransactionBuilder();
			builder.StandardTransactionPolicy = EasyPolicy;
			tx =
				builder
					.AddCoins(stealthCoin)
					.AddKeys(stealthKeys.Skip(2).ToArray()) //Only one Stealth Key
					.AddKeys(scanKey)
					.Send(bob.PubKey.Hash, "1.00")
					.BuildTransaction(true);

			Assert.False(builder.Verify(tx)); //Not fully signed

			//Then he partially signs on the 2nd machine
			builder = new TransactionBuilder();
			builder.StandardTransactionPolicy = EasyPolicy;
			tx =
				builder
					.AddCoins(stealthCoin)
					.AddKeys(stealthKeys[0]) //Other key
					.AddKeys(scanKey)
					.SignTransaction(tx);

			Assert.True(builder.Verify(tx)); //Fully signed !
		}
Exemple #7
0
		public static Script CreatePaymentScript(BitcoinStealthAddress address, PubKey ephemKey, Key scan)
		{
			return CreatePaymentScript(address.SignatureCount, address.SpendPubKeys.Select(p => p.UncoverReceiver(scan, ephemKey)).ToArray());
		}
Exemple #8
0
		public static StealthPayment[] GetPayments(Transaction transaction, BitcoinStealthAddress address, Key scan)
		{
			List<StealthPayment> result = new List<StealthPayment>();
			for(int i = 0; i < transaction.Outputs.Count - 1; i++)
			{
				var metadata = StealthMetadata.TryParse(transaction.Outputs[i].ScriptPubKey);
				if(metadata != null && (address == null || address.Prefix.Match(metadata.BitField)))
				{
					var scriptPubKey = transaction.Outputs[i + 1].ScriptPubKey;
					var scriptId = PayToScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
					Script expectedScriptPubKey = address == null ? scriptPubKey : null;
					Script redeem = null;

					if(scriptId != null)
					{
						if(address == null)
							throw new ArgumentNullException("address");
						redeem = CreatePaymentScript(address, metadata.EphemKey, scan);
						expectedScriptPubKey = redeem.Hash.ScriptPubKey;
						if(expectedScriptPubKey != scriptPubKey)
							continue;
					}

					var payment = new StealthPayment(scriptPubKey, redeem, metadata);
					if(scan != null)
					{
						if(address != null && payment.StealthKeys.Length != address.SpendPubKeys.Length)
							continue;

						if(expectedScriptPubKey == null)
						{
							expectedScriptPubKey = CreatePaymentScript(address, metadata.EphemKey, scan);
						}

						if(expectedScriptPubKey != scriptPubKey)
							continue;
					}
					result.Add(payment);
				}
			}
			return result.ToArray();
		}
Exemple #9
0
 public static Script CreatePaymentScript(BitcoinStealthAddress address, PubKey ephemKey, Key scan)
 {
     return(CreatePaymentScript(address.SignatureCount, address.SpendPubKeys.Select(p => p.UncoverReceiver(scan, ephemKey)).ToArray()));
 }