public PromiseClientSession ReceiveTumblerEscrowedCoin(ScriptCoin escrowedCoin)
        {
            AssertState(TumblerClientSessionStates.WaitingTumblerEscrow);
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(escrowedCoin);

            if (escrow == null)
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (!escrowedCoin.IsP2SH || escrowedCoin.RedeemType != RedeemType.WitnessV0)
            {
                throw new PuzzleException("invalid-escrow");
            }
            var expectedEscrow = GetTumblerEscrowParameters(escrow.Initiator);

            if (escrow != expectedEscrow)
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (escrowedCoin.Amount != Parameters.Denomination)
            {
                throw new PuzzleException("invalid-amount");
            }


            InternalState.Status = TumblerClientSessionStates.PromisePhase;
            var session = new PromiseClientSession(Parameters.CreatePromiseParamaters());

            session.SetChannelId(InternalState.ChannelId);
            session.ConfigureEscrowedCoin(escrowedCoin, InternalState.TumblerEscrowKey);
            InternalState.TumblerEscrowKey = null;
            return(session);
        }
        public PromiseClientSession ReceiveTumblerEscrowedCoin(ScriptCoin escrowedCoin)
        {
            AssertState(TumblerClientSessionStates.WaitingTumblerEscrow);
            var escrow         = EscrowScriptPubKeyParameters.GetFromCoin(escrowedCoin);
            var expectedEscrow = new EscrowScriptPubKeyParameters()
            {
                Initiator = escrow?.Initiator,
                Receiver  = InternalState.TumblerEscrowKey.PubKey,
                LockTime  = GetCycle().GetTumblerLockTime()
            };

            if (escrow == null || escrow != expectedEscrow)
            {
                throw new PuzzleException("invalid-escrow");
            }
            if (escrowedCoin.Amount != Parameters.Denomination)
            {
                throw new PuzzleException("invalid-amount");
            }


            InternalState.Status = TumblerClientSessionStates.PromisePhase;
            var session = new PromiseClientSession(Parameters.CreatePromiseParamaters());

            session.SetChannelId(InternalState.ChannelId);
            session.ConfigureEscrowedCoin(escrowedCoin, InternalState.TumblerEscrowKey);
            InternalState.TumblerEscrowKey = null;
            return(session);
        }
Beispiel #3
0
        public TrustedBroadcastRequest CreateOfferRedeemTransaction(FeeRate feeRate)
        {
            Transaction tx = new Transaction();

            tx.LockTime = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin).LockTime;
            tx.Inputs.Add(new TxIn());
            tx.Inputs[0].Sequence = 0;
            tx.Outputs.Add(new TxOut(InternalState.OfferCoin.Amount, InternalState.RedeemDestination));
            tx.Inputs[0].ScriptSig = new Script(
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(InternalState.OfferCoin.Redeem.ToBytes()));
            tx.Inputs[0].Witnessify();
            var virtualSize = tx.HasWitness ? tx.GetVirtualSize(_Network.Consensus.Options.WitnessScaleFactor) : tx.GetSerializedSize();

            tx.Outputs[0].Value -= feeRate.GetFee(virtualSize);

            var redeemTransaction = new TrustedBroadcastRequest
            {
                Key = InternalState.EscrowKey,
                PreviousScriptPubKey = InternalState.OfferCoin.ScriptPubKey,
                Transaction          = tx
            };

            return(redeemTransaction);
        }
            public override uint256 GetHash()
            {
                var escrow = EscrowScriptPubKeyParameters.GetFromCoin(_Escrow);
                var coin   = _Escrow.Clone();

                coin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
                return(GetTransaction().GetSignatureHash(coin, SigHash.All));
            }
Beispiel #5
0
        private OfferScriptPubKeyParameters CreateOfferScriptParameters()
        {
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin);

            return(new OfferScriptPubKeyParameters
            {
                Hashes = InternalState.SolvedPuzzles.Select(p => p.SolutionKey.GetHash()).ToArray(),
                FulfillKey = InternalState.FulfillKey.PubKey,
                Expiration = escrow.LockTime,
                RedeemKey = escrow.Initiator
            });
        }
Beispiel #6
0
        public TransactionSignature SignEscape()
        {
            AssertState(SolverClientStates.Completed);
            var dummy = new Transaction();

            dummy.Inputs.Add(new TxIn(InternalState.EscrowedCoin.Outpoint));
            dummy.Outputs.Add(new TxOut());

            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin);
            var coin   = InternalState.EscrowedCoin.Clone();

            coin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
            return(dummy.SignInput(InternalState.EscrowKey, coin, SigHash.None | SigHash.AnyoneCanPay));
        }
Beispiel #7
0
        private PubKey AssertValidSignature(TransactionSignature clientSignature, Transaction offer)
        {
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin);
            var coin   = InternalState.EscrowedCoin.Clone();

            coin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
            var signedHash = offer.Inputs.AsIndexedInputs().First().GetSignatureHash(coin, clientSignature.SigHash);
            var clientKey  = InternalState.GetClientEscrowPubKey();

            if (!clientKey.Verify(signedHash, clientSignature.Signature))
            {
                throw new PuzzleException("invalid-client-signature");
            }
            return(clientKey);
        }
Beispiel #8
0
        public uint256 CreateRealHash(Transaction tx, ScriptCoin _Escrow, Money feeVariation)
        {
            /*
             * Not sure if this is best way to do this, but had to add this for step 7
             * when verifying valid Hashes, the server will have to make real hashes, but
             * it doesn't have access to RealHash class. So I created this function that
             * takes care of that
             */
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(_Escrow);
            var coin   = _Escrow.Clone();

            coin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
            var Transaction = tx.Clone();

            Transaction.Outputs[0].Value -= feeVariation;
            return(Transaction.GetSignatureHash(coin, SigHash.All));
        }
        private bool IsValidSignature(PuzzleSolution solution, HashBase hash, out ECDSASignature signature)
        {
            signature = null;
            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin);

            try
            {
                var key = new XORKey(solution);
                signature = new ECDSASignature(key.XOR(hash.Commitment.Promise));
                var ok = escrow.Initiator.Verify(hash.GetHash(), signature);
                if (!ok)
                {
                    signature = null;
                }
                return(ok);
            }
            catch
            {
            }
            return(false);
        }
Beispiel #10
0
        public TransactionSignature SignOffer(OfferInformation offerInformation)
        {
            if (offerInformation == null)
            {
                throw new ArgumentNullException(nameof(offerInformation));
            }
            AssertState(SolverClientStates.WaitingOffer);

            var offerScript = new OfferScriptPubKeyParameters
            {
                Hashes     = _PuzzleElements.OfType <RealPuzzle>().Select(p => p.Commitment.KeyHash).ToArray(),
                FulfillKey = offerInformation.FulfillKey,
                Expiration = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin).LockTime,
                RedeemKey  = InternalState.EscrowKey.PubKey
            }.ToScript();

            var escrowCoin = InternalState.EscrowedCoin;
            var txOut      = new TxOut(escrowCoin.Amount - offerInformation.Fee, offerScript.WitHash.ScriptPubKey.Hash);
            var offerCoin  = new Coin(escrowCoin.Outpoint, txOut).ToScriptCoin(offerScript);


            Transaction tx = new Transaction();

            tx.Inputs.Add(new TxIn(escrowCoin.Outpoint));
            tx.Outputs.Add(offerCoin.TxOut);

            var escrow = EscrowScriptPubKeyParameters.GetFromCoin(escrowCoin);

            escrowCoin = escrowCoin.Clone();
            escrowCoin.OverrideScriptCode(escrow.GetInitiatorScriptCode());
            var signature = tx.Inputs.AsIndexedInputs().First().Sign(InternalState.EscrowKey, escrowCoin, SigHash.All);

            InternalState.OfferCoin = offerCoin;
            InternalState.Status    = SolverClientStates.WaitingPuzzleSolutions;
            return(signature);
        }
Beispiel #11
0
 public PubKey GetClientEscrowPubKey()
 {
     return(EscrowScriptPubKeyParameters.GetFromCoin(EscrowedCoin).Initiator);
 }
Beispiel #12
0
        public OfferInformation CheckBlindedFactors(BlindFactor[] blindFactors, FeeRate feeRate)
        {
            if (blindFactors == null)
            {
                throw new ArgumentNullException(nameof(blindFactors));
            }
            if (blindFactors.Length != Parameters.RealPuzzleCount)
            {
                throw new ArgumentException("Expecting " + Parameters.RealPuzzleCount + " blind factors");
            }
            AssertState(SolverServerStates.WaitingBlindFactor);
            Puzzle unblindedPuzzle = null;
            int    y = 0;

            for (int i = 0; i < Parameters.RealPuzzleCount; i++)
            {
                var solvedPuzzle = InternalState.SolvedPuzzles[i];
                var unblinded    = new Puzzle(Parameters.ServerKey, solvedPuzzle.Puzzle).Unblind(blindFactors[i]);
                if (unblindedPuzzle == null)
                {
                    unblindedPuzzle = unblinded;
                }
                else if (unblinded != unblindedPuzzle)
                {
                    throw new PuzzleException("Invalid blind factor");
                }
                y++;
            }

            InternalState.FulfillKey = new Key();

            Transaction dummy = new Transaction();

            dummy.AddInput(new TxIn(InternalState.EscrowedCoin.Outpoint));
            dummy.Inputs[0].ScriptSig = new Script(
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                );
            dummy.Inputs[0].Witnessify();
            dummy.AddOutput(new TxOut(InternalState.EscrowedCoin.Amount, new Key().ScriptPubKey.Hash));

            var offerTransactionFee = feeRate.GetFee(dummy.GetVirtualSize());


            var escrow            = InternalState.EscrowedCoin;
            var escrowInformation = EscrowScriptPubKeyParameters.GetFromCoin(InternalState.EscrowedCoin);
            var redeem            = new OfferScriptPubKeyParameters
            {
                Hashes     = InternalState.SolvedPuzzles.Select(p => p.SolutionKey.GetHash()).ToArray(),
                FulfillKey = InternalState.FulfillKey.PubKey,
                Expiration = escrowInformation.LockTime,
                RedeemKey  = escrowInformation.Initiator
            }.ToScript();
            var txOut = new TxOut(escrow.Amount - offerTransactionFee, redeem.WitHash.ScriptPubKey.Hash);

            InternalState.OfferCoin = new Coin(escrow.Outpoint, txOut).ToScriptCoin(redeem);
            InternalState.Status    = SolverServerStates.WaitingFulfillment;
            return(new OfferInformation
            {
                FulfillKey = InternalState.FulfillKey.PubKey,
                Fee = offerTransactionFee
            });
        }
 private static CorrelationId GetCorrelation(SolverServerSession session)
 {
     return(EscrowScriptPubKeyParameters.GetFromCoin(session.EscrowedCoin).GetCorrelation());
 }