예제 #1
0
        private void Sign(TransactionSigningContext ctx, TxIn input, ICoin coin, int n)
        {
            if (coin is StealthCoin)
            {
                var stealthCoin = (StealthCoin)coin;
                var scanKey     = FindKey(ctx, stealthCoin.Address.ScanPubKey);
                if (scanKey == null)
                {
                    throw new KeyNotFoundException("Scan key for decrypting StealthCoin not found");
                }
                var spendKeys = stealthCoin.Address.SpendPubKeys.Select(p => FindKey(ctx, p)).Where(p => p != null).ToArray();
                ctx.AdditionalKeys.AddRange(stealthCoin.Uncover(spendKeys, scanKey));
            }

            if (PayToScriptHashTemplate.Instance.CheckScriptPubKey(coin.ScriptPubKey))
            {
                var scriptCoin = (IScriptCoin)coin;
                var original   = input.ScriptSig;
                input.ScriptSig = CreateScriptSig(ctx, input, n, scriptCoin.Redeem);
                if (original != input.ScriptSig)
                {
                    input.ScriptSig = input.ScriptSig + Op.GetPushOp(scriptCoin.Redeem.ToBytes(true));
                }
            }
            else
            {
                input.ScriptSig = CreateScriptSig(ctx, input, n, coin.ScriptPubKey);
            }
        }
예제 #2
0
        public Transaction SignTransactionInPlace(Transaction transaction, SigHash sigHash)
        {
            TransactionSigningContext ctx = new TransactionSigningContext(this, transaction);

            ctx.SigHash = sigHash;
            foreach (var input in transaction.Inputs.AsIndexedInputs())
            {
                var coin = FindSignableCoin(input.TxIn);
                if (coin != null)
                {
                    Sign(ctx, coin, input);
                }
            }
            return(transaction);
        }
예제 #3
0
        public Transaction SignTransactionInPlace(Transaction transaction, SigHash sigHash)
        {
            TransactionSigningContext ctx = new TransactionSigningContext(this, transaction);

            ctx.SigHash = sigHash;
            for (int i = 0; i < transaction.Inputs.Count; i++)
            {
                var txIn = transaction.Inputs[i];
                var coin = FindSignableCoin(txIn);
                if (coin != null)
                {
                    Sign(ctx, txIn, coin, i);
                }
            }
            return(transaction);
        }
예제 #4
0
 private Key FindKey(TransactionSigningContext ctx, PubKey pubKey)
 {
     return(_Keys
            .Concat(ctx.AdditionalKeys)
            .FirstOrDefault(k => k.PubKey == pubKey));
 }
예제 #5
0
 private Key FindKey(TransactionSigningContext ctx, TxDestination id)
 {
     return(_Keys
            .Concat(ctx.AdditionalKeys)
            .FirstOrDefault(k => k.PubKey.Hash == id));
 }
예제 #6
0
        private Script CreateScriptSig(TransactionSigningContext ctx, TxIn input, int n, Script scriptPubKey)
        {
            var originalScriptSig = input.ScriptSig;

            input.ScriptSig = scriptPubKey;

            var pubKeyHashParams = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);

            if (pubKeyHashParams != null)
            {
                var key = FindKey(ctx, pubKeyHashParams);
                if (key == null)
                {
                    return(originalScriptSig);
                }
                var hash = input.ScriptSig.SignatureHash(ctx.Transaction, n, ctx.SigHash);
                var sig  = key.Sign(hash);
                return(PayToPubkeyHashTemplate.Instance.GenerateScriptSig(new TransactionSignature(sig, ctx.SigHash), key.PubKey));
            }

            var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);

            if (multiSigParams != null)
            {
                var alreadySigned = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(originalScriptSig);
                if (alreadySigned == null && !Script.IsNullOrEmpty(originalScriptSig))                //Maybe a P2SH
                {
                    var ops = originalScriptSig.ToOps().ToList();
                    ops.RemoveAt(ops.Count - 1);
                    alreadySigned = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(new Script(ops));
                }
                List <TransactionSignature> signatures = new List <TransactionSignature>();
                if (alreadySigned != null)
                {
                    signatures.AddRange(alreadySigned);
                }
                var keys =
                    multiSigParams
                    .PubKeys
                    .Select(p => FindKey(ctx, p))
                    .ToArray();

                int sigCount = signatures.Where(s => s != TransactionSignature.Empty && s != null).Count();
                for (int i = 0; i < keys.Length; i++)
                {
                    if (sigCount == multiSigParams.SignatureCount)
                    {
                        break;
                    }

                    if (i >= signatures.Count)
                    {
                        signatures.Add(null);
                    }
                    if (keys[i] != null)
                    {
                        var hash = input.ScriptSig.SignatureHash(ctx.Transaction, n, ctx.SigHash);
                        var sig  = keys[i].Sign(hash);
                        signatures[i] = new TransactionSignature(sig, ctx.SigHash);
                        sigCount++;
                    }
                }

                IEnumerable <TransactionSignature> sigs = signatures;
                if (sigCount == multiSigParams.SignatureCount)
                {
                    sigs = sigs.Where(s => s != TransactionSignature.Empty && s != null);
                }

                return(PayToMultiSigTemplate.Instance.GenerateScriptSig(sigs));
            }

            var pubKeyParams = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);

            if (pubKeyParams != null)
            {
                var key = FindKey(ctx, pubKeyParams);
                if (key == null)
                {
                    return(originalScriptSig);
                }
                var hash = input.ScriptSig.SignatureHash(ctx.Transaction, n, ctx.SigHash);
                var sig  = key.Sign(hash);
                return(PayToPubkeyTemplate.Instance.GenerateScriptSig(new TransactionSignature(sig, ctx.SigHash)));
            }

            throw new NotSupportedException("Unsupported scriptPubKey");
        }
예제 #7
0
			public TransactionBuilderKeyRepository(TransactionBuilder txBuilder, TransactionSigningContext ctx)
			{
				_Ctx = ctx;
				_TxBuilder = txBuilder;
			}
예제 #8
0
		private Key FindKey(TransactionSigningContext ctx, Script scriptPubKey)
		{
			var key = _Keys
				.Concat(ctx.AdditionalKeys)
				.FirstOrDefault(k => k.PubKey.ScriptPubKey == scriptPubKey ||  //P2PK
									k.PubKey.Hash.ScriptPubKey == scriptPubKey || //P2PKH
									k.PubKey.ScriptPubKey.Hash.ScriptPubKey == scriptPubKey || //P2PK P2SH
									k.PubKey.Hash.ScriptPubKey.Hash.ScriptPubKey == scriptPubKey); //P2PKH P2SH
			if(key == null && KeyFinder != null)
			{
				key = KeyFinder(scriptPubKey);
			}
			return key;
		}
예제 #9
0
		private Script CreateScriptSig(TransactionSigningContext ctx, ICoin coin, IndexedTxIn txIn)
		{
			var scriptPubKey = coin.GetScriptCode();
			var keyRepo = new TransactionBuilderKeyRepository(this, ctx);
			var signer = new TransactionBuilderSigner(coin, ctx.SigHash, txIn);
			foreach(var extension in Extensions)
			{
				if(extension.CanGenerateScriptSig(scriptPubKey))
				{
					return extension.GenerateScriptSig(scriptPubKey, keyRepo, signer);
				}
			}
			throw new NotSupportedException("Unsupported scriptPubKey");
		}
예제 #10
0
		private void Sign(TransactionSigningContext ctx, ICoin coin, IndexedTxIn txIn)
		{
			var input = txIn.TxIn;
			if(coin is StealthCoin)
			{
				var stealthCoin = (StealthCoin)coin;
				var scanKey = FindKey(ctx, stealthCoin.Address.ScanPubKey.ScriptPubKey);
				if(scanKey == null)
					throw new KeyNotFoundException("Scan key for decrypting StealthCoin not found");
				var spendKeys = stealthCoin.Address.SpendPubKeys.Select(p => FindKey(ctx, p.ScriptPubKey)).Where(p => p != null).ToArray();
				ctx.AdditionalKeys.AddRange(stealthCoin.Uncover(spendKeys, scanKey));
				var normalCoin = new Coin(coin.Outpoint, coin.TxOut);
				if(stealthCoin.Redeem != null)
					normalCoin = normalCoin.ToScriptCoin(stealthCoin.Redeem);
				coin = normalCoin;
			}
			var scriptSig = CreateScriptSig(ctx, coin, txIn);
			if(scriptSig == null)
				return;
			ScriptCoin scriptCoin = coin as ScriptCoin;

			Script signatures = null;
			if(coin.GetHashVersion() == HashVersion.Witness)
			{
				signatures = txIn.WitScript;
				if(scriptCoin != null)
				{
					if(scriptCoin.IsP2SH)
						txIn.ScriptSig = Script.Empty;
					if(scriptCoin.RedeemType == RedeemType.WitnessV0)
						signatures = RemoveRedeem(signatures);
				}
			}
			else
			{
				signatures = txIn.ScriptSig;
				if(scriptCoin != null && scriptCoin.RedeemType == RedeemType.P2SH)
					signatures = RemoveRedeem(signatures);
			}


			signatures = CombineScriptSigs(coin, scriptSig, signatures);

			if(coin.GetHashVersion() == HashVersion.Witness)
			{
				txIn.WitScript = signatures;
				if(scriptCoin != null)
				{
					if(scriptCoin.IsP2SH)
						txIn.ScriptSig = new Script(Op.GetPushOp(scriptCoin.GetP2SHRedeem().ToBytes(true)));
					if(scriptCoin.RedeemType == RedeemType.WitnessV0)
						txIn.WitScript = txIn.WitScript + new WitScript(Op.GetPushOp(scriptCoin.Redeem.ToBytes(true)));
				}
			}
			else
			{
				txIn.ScriptSig = signatures;
				if(scriptCoin != null && scriptCoin.RedeemType == RedeemType.P2SH)
				{
					txIn.ScriptSig = input.ScriptSig + Op.GetPushOp(scriptCoin.GetP2SHRedeem().ToBytes(true));
				}
			}
		}
예제 #11
0
		public Transaction SignTransactionInPlace(Transaction transaction, SigHash sigHash)
		{
			TransactionSigningContext ctx = new TransactionSigningContext(this, transaction);
			ctx.SigHash = sigHash;
			foreach(var input in transaction.Inputs.AsIndexedInputs())
			{
				var coin = FindSignableCoin(input);
				if(coin != null)
				{
					Sign(ctx, coin, input);
				}
			}
			return transaction;
		}