internal IEnumerable <Transaction> GetSignedTransactions(PuzzleSolution solution)
        {
            if (solution == null)
            {
                throw new ArgumentNullException(nameof(solution));
            }
            AssertState(PromiseClientStates.Completed);
            solution = solution.Unblind(Parameters.ServerKey, InternalState.BlindFactor);
            BigInteger cumul  = solution._Value;
            var        hashes = _Hashes.OfType <RealHash>().ToArray();

            for (int i = 0; i < Parameters.RealTransactionCount; i++)
            {
                var hash     = hashes[i];
                var quotient = i == 0 ? BigInteger.One : InternalState.Quotients[i - 1]._Value;
                cumul    = cumul.Multiply(quotient).Mod(Parameters.ServerKey._Key.Modulus);
                solution = new PuzzleSolution(cumul);
                if (!IsValidSignature(solution, hash, out ECDSASignature tumblerSig))
                {
                    continue;
                }
                var transaction = hash.GetTransaction();
                var bobSig      = transaction.SignInput(InternalState.EscrowKey, InternalState.EscrowedCoin);
                transaction.Inputs[0].WitScript = new WitScript(
                    Op.GetPushOp(new TransactionSignature(tumblerSig, SigHash.All).ToBytes()),
                    Op.GetPushOp(bobSig.ToBytes()),
                    Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                    );
                //transaction is already witnessified
                if (transaction.Inputs.AsIndexedInputs().First().VerifyScript(InternalState.EscrowedCoin))
                {
                    yield return(transaction);
                }
            }
        }
Beispiel #2
0
        internal IEnumerable <Transaction> GetSignedTransactions(PuzzleSolution solution)
        {
            if (solution == null)
            {
                throw new ArgumentNullException(nameof(solution));
            }
            AssertState(PromiseClientStates.Completed);
            solution = solution.Unblind(Parameters.ServerKey, InternalState.BlindFactor);
            BigInteger cumul  = solution._Value;
            var        hashes = _Hashes.OfType <RealHash>().ToArray();

            for (int i = 0; i < Parameters.RealTransactionCount; i++)
            {
                var hash     = hashes[i];
                var quotient = i == 0 ? BigInteger.One : InternalState.Quotients[i - 1]._Value;
                cumul    = cumul.Multiply(quotient).Mod(Parameters.ServerKey._Key.Modulus);
                solution = new PuzzleSolution(cumul);
                ECDSASignature signature;
                PubKey         signer;
                if (!IsValidSignature(solution, hash, out signer, out signature))
                {
                    continue;
                }

                var transaction = hash.GetTransaction();
                TransactionBuilder txBuilder = new TransactionBuilder();
                txBuilder.Extensions.Add(new EscrowBuilderExtension());
                txBuilder.AddCoins(InternalState.EscrowedCoin);
                txBuilder.AddKeys(InternalState.EscrowKey);
                txBuilder.AddKnownSignature(signer, signature);
                txBuilder.SignTransactionInPlace(transaction);
                yield return(transaction);
            }
        }
        public void CheckVoucherSolution(PuzzleSolution blindedVoucherSignature)
        {
            AssertState(TumblerClientSessionStates.WaitingSolvedVoucher);
            var solution = blindedVoucherSignature.Unblind(Parameters.VoucherKey.PublicKey, InternalState.BlindedVoucherFactor);

            if (!InternalState.UnsignedVoucher.Puzzle.WithRsaKey(Parameters.VoucherKey.PublicKey).Verify(solution))
            {
                throw new PuzzleException("Incorrect puzzle solution");
            }
            InternalState.BlindedVoucherFactor = null;
            InternalState.SignedVoucher        = new XORKey(solution).XOR(InternalState.UnsignedVoucher.EncryptedSignature);
            InternalState.UnsignedVoucher.EncryptedSignature = new byte[0];
            InternalState.ClientEscrowKey = null;
            InternalState.Status          = TumblerClientSessionStates.WaitingGenerateTumblerTransactionKey;
        }
        public void CanBlind()
        {
            RsaKey key = TestKeys.Default;

            PuzzleSolution solution = null;
            BlindFactor    blind    = null;

            Puzzle puzzle        = key.PubKey.GeneratePuzzle(ref solution);
            Puzzle blindedPuzzle = puzzle.Blind(ref blind);

            Assert.True(puzzle != blindedPuzzle);
            Assert.True(puzzle == blindedPuzzle.Unblind(blind));


            PuzzleSolution blindedSolution = blindedPuzzle.Solve(key);

            Assert.False(puzzle.Verify(blindedSolution));
            Assert.True(puzzle.Verify(blindedSolution.Unblind(key.PubKey, blind)));
        }
        public void CanSolvePuzzle()
        {
            RsaKey         key       = TestKeys.Default;
            PuzzleSolution solution  = null;
            var            puzzle    = key.PubKey.GeneratePuzzle(ref solution);
            PuzzleSolution solution2 = puzzle.Solve(key);

            Assert.True(puzzle.Verify(solution));
            Assert.True(solution == solution2);


            puzzle = key.PubKey.GeneratePuzzle(ref solution);
            BlindFactor    blind           = null;
            Puzzle         blindedPuzzle   = puzzle.Blind(ref blind);
            PuzzleSolution blindedSolution = key.SolvePuzzle(blindedPuzzle);
            var            unblinded       = blindedSolution.Unblind(key.PubKey, blind);

            Assert.True(unblinded == solution);
        }
        internal IEnumerable <Transaction> GetSignedTransactions(PuzzleSolution solution, int paymentNumber)
        {
            /*
             * parameter "paymentNumber" indicates which j payment this is.
             * TODO: In order to solve the puzzle using the "solution", we need the previous solution
             * to get the signatures.
             *
             */
            if (solution == null)
            {
                throw new ArgumentNullException(nameof(solution));
            }
            AssertState(PromiseClientStates.Completed);
            solution = solution.Unblind(Parameters.ServerKey, InternalState.BlindFactors[paymentNumber]);
            BigInteger cumul  = solution._Value;
            var        hashes = _Hashes[paymentNumber].OfType <RealHash>().ToArray();

            for (int i = 0; i < Parameters.RealTransactionCountPerLevel; i++)
            {
                var hash     = hashes[i];
                var quotient = i == 0 ? BigInteger.One : InternalState.Quotients[paymentNumber][i - 1]._Value;
                cumul = cumul.Multiply(quotient).Mod(Parameters.ServerKey._Key.Modulus); // Epsilon_i
                // Need to fix how the solution is recovered given how we need the previous solutions to get the current one.
                solution = new PuzzleSolution(cumul);
                if (!IsValidSignature(solution, hash, out ECDSASignature tumblerSig))
                {
                    continue;
                }
                var transaction = hash.GetTransaction();
                var bobSig      = transaction.SignInput(InternalState.EscrowKey, InternalState.EscrowedCoin);
                transaction.Inputs[0].ScriptSig = new Script(
                    Op.GetPushOp(new TransactionSignature(tumblerSig, SigHash.All).ToBytes()),
                    Op.GetPushOp(bobSig.ToBytes()),
                    Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                    );
                if (transaction.Inputs.AsIndexedInputs().First().VerifyScript(InternalState.EscrowedCoin))
                {
                    yield return(transaction);
                }
            }
        }
        public void CheckSolutions(SolutionKey[] keys)
        {
            if (keys == null)
            {
                throw new ArgumentNullException(nameof(keys));
            }
            if (keys.Length != Parameters.RealPuzzleCount)
            {
                throw new ArgumentException("Expecting " + Parameters.RealPuzzleCount + " keys");
            }
            AssertState(SolverClientStates.WaitingPuzzleSolutions);
            PuzzleSolution solution     = null;
            RealPuzzle     solvedPuzzle = null;
            int            y            = 0;

            foreach (var puzzle in _PuzzleElements.OfType <RealPuzzle>())
            {
                var key        = keys[y++].ToBytes(true);
                var commitment = puzzle.Commitment;

                var hash = new uint160(Hashes.RIPEMD160(key, key.Length));
                if (hash == commitment.KeyHash)
                {
                    var decryptedSolution = new PuzzleSolution(Utils.ChachaDecrypt(commitment.EncryptedSolution, key));
                    if (puzzle.Puzzle.Verify(decryptedSolution))
                    {
                        solution     = decryptedSolution;
                        solvedPuzzle = puzzle;
                        break;
                    }
                }
            }

            if (solution == null)
            {
                throw new PuzzleException("Impossible to find solution to the puzzle");
            }

            InternalState.PuzzleSolution = solution.Unblind(ServerKey, solvedPuzzle.BlindFactor);
            InternalState.Status         = SolverClientStates.Completed;
        }