예제 #1
0
        public ServerCommitment[] SignHashes(SignaturesRequest sigRequest)
        {
            if (sigRequest == null)
            {
                throw new ArgumentNullException(nameof(sigRequest));
            }
            if (sigRequest.Hashes.Length != Parameters.GetTotalTransactionsCount())
            {
                throw new ArgumentException("Incorrect number of hashes, expected " + sigRequest.Hashes.Length);
            }
            AssertState(PromiseServerStates.WaitingHashes);
            List <ServerCommitment>   promises            = new List <ServerCommitment>();
            List <EncryptedSignature> encryptedSignatures = new List <EncryptedSignature>();

            foreach (var hash in sigRequest.Hashes)
            {
                var            ecdsa    = InternalState.EscrowKey.Sign(hash);
                var            ecdsaDER = ecdsa.ToDER();
                var            key      = new XORKey(Parameters.ServerKey);
                var            promise  = key.XOR(ecdsaDER);
                PuzzleSolution solution = new PuzzleSolution(key.ToBytes());
                var            puzzle   = Parameters.ServerKey.GeneratePuzzle(ref solution);
                promises.Add(new ServerCommitment(puzzle.PuzzleValue, promise));
                encryptedSignatures.Add(new EncryptedSignature(ecdsa, hash, solution));
            }
            InternalState.Status = PromiseServerStates.WaitingRevelation;
            InternalState.EncryptedSignatures = encryptedSignatures.ToArray();
            InternalState.FakeIndexesHash     = sigRequest.FakeIndexesHash;
            return(promises.ToArray());
        }
예제 #2
0
        public SignaturesRequest CreateSignatureRequest(Script cashoutDestination, FeeRate feeRate)
        {
            if (cashoutDestination == null)
            {
                throw new ArgumentNullException(nameof(cashoutDestination));
            }
            if (feeRate == null)
            {
                throw new ArgumentNullException(nameof(feeRate));
            }
            AssertState(PromiseClientStates.WaitingSignatureRequest);

            Transaction cashout = new Transaction();

            cashout.AddInput(new TxIn(InternalState.EscrowedCoin.Outpoint, Script.Empty));
            cashout.AddOutput(new TxOut(Money.Zero, cashoutDestination));
            var fee = feeRate.GetFee(cashout.GetVirtualSize());

            cashout.Outputs[0].Value = InternalState.EscrowedCoin.Amount - fee;


            List <HashBase> hashes   = new List <HashBase>();
            LockTime        lockTime = new LockTime(0);

            for (int i = 0; i < Parameters.RealTransactionCount; i++)
            {
                RealHash h = new RealHash(cashout, InternalState.EscrowedCoin);
                h.LockTime = lockTime;
                lockTime++;
                hashes.Add(h);
            }

            for (int i = 0; i < Parameters.FakeTransactionCount; i++)
            {
                FakeHash h = new FakeHash(Parameters);
                h.Salt = new uint256(RandomUtils.GetBytes(32));
                hashes.Add(h);
            }

            _Hashes = hashes.ToArray();
            NBitcoin.Utils.Shuffle(_Hashes, RandomUtils.GetInt32());
            for (int i = 0; i < _Hashes.Length; i++)
            {
                _Hashes[i].Index = i;
            }
            var     fakeIndices = _Hashes.OfType <FakeHash>().Select(h => h.Index).ToArray();
            uint256 indexSalt   = null;
            var     request     = new SignaturesRequest
            {
                Hashes          = _Hashes.Select(h => h.GetHash()).ToArray(),
                FakeIndexesHash = PromiseUtils.HashIndexes(ref indexSalt, fakeIndices),
            };

            InternalState.IndexSalt   = indexSalt;
            InternalState.Cashout     = cashout.Clone();
            InternalState.Status      = PromiseClientStates.WaitingCommitments;
            InternalState.FakeIndexes = fakeIndices;
            return(request);
        }
예제 #3
0
        public ServerCommitment[][] SignHashes(SignaturesRequest sigRequest)
        {
            // Almost done, just need to confirm a typo and a function.
            // Step 5

            if (sigRequest == null)
            {
                throw new ArgumentNullException(nameof(sigRequest));
            }

            var hashesCount = sigRequest.Hashes.Select(a => a.Length).Sum();

            if (hashesCount != Parameters.GetTotalTransactionsCount())
            {
                throw new ArgumentException($"Incorrect number of hashes, expected {Parameters.GetTotalTransactionsCount()}");
            }

            AssertState(PromiseServerStates.WaitingHashes);
            // 2D array of pairs of puzzles and promises (z_i, c_i).
            var promises = new ServerCommitment[Parameters.PaymentsCount][];
            // 2D array of encrypted signatures with their solutions.
            var encryptedSignatures = new EncryptedSignature[Parameters.PaymentsCount][];
            // 1-D array is used to store the epsilons for each column to be used when Hashing.
            var previousSolutions = new byte[Parameters.GetTotalTransactionsCountPerLevel()][];

            previousSolutions = previousSolutions.Select(a => new byte[0]).ToArray(); // Initialize to empty array of bytes
            for (int i = 0; i < Parameters.PaymentsCount; i++)
            {
                promises[i]            = new ServerCommitment[sigRequest.Hashes[i].Length]; // Initialization
                encryptedSignatures[i] = new EncryptedSignature[promises[i].Length];        // Initialization
                for (int j = 0; j < promises[i].Length; j++)
                {
                    var hash = sigRequest.Hashes[i][j];
                    // Sign the hash value
                    var ecdsa = InternalState.EscrowKey.Sign(hash);
                    // Convert Signature to Bytes.
                    var ecdsaDER = ecdsa.ToDER();
                    // This can be replaced by "Utils.GenerateEncryptableInteger(Key)" if padding when XORing is not important.
                    var key = (new XORKey(Parameters.ServerKey)).ToBytes(); // This just generates a random epsilon.
                    // Append the new epsilon to the list of epsilons we have for that column to create "epsilon_{i-1,j}|| . . . , epsilon_{0,j}".
                    previousSolutions[j] = Utils.Combine(key, previousSolutions[j]);
                    // Create the padded solution with the following format "i||j||epsilon_{i,j}||epsilon_{i-1,j}|| . . . , epsilon_{0,j}"
                    var paddedSolutions = new PuzzleSolution(Utils.Combine(NBitcoin.Utils.ToBytes((uint)i, true), NBitcoin.Utils.ToBytes((uint)j, true), previousSolutions[j]));
                    // Hash and XOR the padded solution with the signature we have.
                    var            promise  = XORKey.XOR(paddedSolutions._Value.ToByteArrayUnsigned(), ecdsaDER); // This function needs to be approved "XOR".
                    PuzzleSolution solution = new PuzzleSolution(key);                                            // Epsilon
                    // Encrypt the epsilon value using RSA
                    var puzzle = Parameters.ServerKey.GeneratePuzzle(ref solution);
                    promises[i][j]            = new ServerCommitment(puzzle.PuzzleValue, promise);
                    encryptedSignatures[i][j] = new EncryptedSignature(ecdsa, hash, solution);
                }
            }

            InternalState.Status = PromiseServerStates.WaitingRevelation;
            InternalState.EncryptedSignatures = encryptedSignatures;
            InternalState.FakeIndexesHash     = sigRequest.FakeIndexesHash;
            return(promises);
        }
        public SignaturesRequest CreateSignatureRequest(Script cashoutDestination, FeeRate feeRate)
        {
            if (cashoutDestination == null)
            {
                throw new ArgumentNullException(nameof(cashoutDestination));
            }
            if (feeRate == null)
            {
                throw new ArgumentNullException(nameof(feeRate));
            }
            AssertState(PromiseClientStates.WaitingSignatureRequest);

            Transaction cashout = new Transaction();

            cashout.AddInput(new TxIn(InternalState.EscrowedCoin.Outpoint));
            cashout.Inputs[0].ScriptSig = new Script(
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                );
            cashout.Inputs[0].Witnessify();
            cashout.AddOutput(new TxOut(InternalState.EscrowedCoin.Amount, cashoutDestination));
            cashout.Outputs[0].Value -= feeRate.GetFee(cashout.GetVirtualSize());


            List <HashBase> hashes = new List <HashBase>();

            for (int i = 0; i < Parameters.RealTransactionCount; i++)
            {
                RealHash h = new RealHash(cashout, InternalState.EscrowedCoin);
                h.FeeVariation = Money.Satoshis(i);
                hashes.Add(h);
            }

            for (int i = 0; i < Parameters.FakeTransactionCount; i++)
            {
                FakeHash h = new FakeHash(Parameters);
                h.Salt = new uint256(RandomUtils.GetBytes(32));
                hashes.Add(h);
            }

            _Hashes = hashes.ToArray();
            NBitcoin.Utils.Shuffle(_Hashes, RandomUtils.GetInt32());
            for (int i = 0; i < _Hashes.Length; i++)
            {
                _Hashes[i].Index = i;
            }

            var     fakeIndices = _Hashes.OfType <FakeHash>().Select(h => h.Index).ToArray();
            uint256 indexSalt   = null;
            var     request     = new SignaturesRequest
            {
                Hashes          = _Hashes.Select(h => h.GetHash()).ToArray(),
                FakeIndexesHash = PromiseUtils.HashIndexes(ref indexSalt, fakeIndices),
            };

            InternalState.IndexSalt   = indexSalt;
            InternalState.Cashout     = cashout.Clone();
            InternalState.Status      = PromiseClientStates.WaitingCommitments;
            InternalState.FakeIndexes = fakeIndices;
            return(request);
        }
예제 #5
0
        public SignaturesRequest CreateSignatureRequest(Script cashoutDestination, FeeRate feeRate)
        {
            // Steps 2-4
            // Almost done, just need to figure out the Transaction CashOut things.

            if (cashoutDestination == null)
            {
                throw new ArgumentNullException(nameof(cashoutDestination));
            }
            if (feeRate == null)
            {
                throw new ArgumentNullException(nameof(feeRate));
            }

            AssertState(PromiseClientStates.WaitingSignatureRequest);

            Transaction cashout = new Transaction();

            // TODO: Figure out the cashout format to give j Bitcoins to Bob and Q-J to the Tumbler
            cashout.AddInput(new TxIn(InternalState.EscrowedCoin.Outpoint));
            cashout.Inputs[0].ScriptSig = new Script(
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(TrustedBroadcastRequest.PlaceholderSignature),
                Op.GetPushOp(InternalState.EscrowedCoin.Redeem.ToBytes())
                );
            cashout.AddOutput(new TxOut(InternalState.EscrowedCoin.Amount, cashoutDestination));
            cashout.Outputs[0].Value -= feeRate.GetFee(cashout.GetVirtualSize());

            // If each payment level requires a different cashOut, then this
            // should be moved to the first loop.

            HashBase[][] hashes = new HashBase[_Parameters.PaymentsCount][]; //2D
            for (int i = 0; i < _Parameters.PaymentsCount; i++)
            {
                hashes[i] = new HashBase[_Parameters.GetTotalTransactionsCountPerLevel()];
                for (int j = 0; j < Parameters.RealTransactionCountPerLevel; j++)
                {
                    RealHash h = new RealHash(cashout, InternalState.EscrowedCoin)
                    {
                        FeeVariation = Money.Satoshis(i)
                    };
                    hashes[i][j] = h;
                }
                for (int j = Parameters.RealTransactionCountPerLevel; j < hashes[i].Length; j++)
                {
                    FakeHash h = new FakeHash(Parameters)
                    {
                        Salt = new uint256(RandomUtils.GetBytes(32))
                    };
                    hashes[i][j] = h;
                }
            }
            _Hashes = hashes;

            // Under the assumption that given the same seed the Shuffle will be deterministic.
            // TODO: Verify this in Debugging or a unit test.
            var shuffleSeed = RandomUtils.GetInt32();

            for (int i = 0; i < _Parameters.PaymentsCount; i++)
            {
                NBitcoin.Utils.Shuffle(_Hashes[i], shuffleSeed);
            }

            for (int i = 0; i < _Parameters.PaymentsCount; i++)
            {
                for (int j = 0; j < _Hashes[i].Length; j++)
                {
                    _Hashes[i][j].Index = j;
                }
            }

            var     fakeIndices = _Hashes.First().OfType <FakeHash>().Select(h => h.Index).ToArray();
            uint256 indexSalt   = null;
            var     request     = new SignaturesRequest
            {
                // This looks cool, but double check the use of Select in debugging.
                Hashes          = _Hashes.Select(h => (h.Select(k => k.GetHash()).ToArray())).ToArray(),
                FakeIndexesHash = PromiseUtils.HashIndexes(ref indexSalt, fakeIndices),
            };

            InternalState.IndexSalt   = indexSalt;
            InternalState.Cashout     = cashout.Clone();
            InternalState.Status      = PromiseClientStates.WaitingCommitments;
            InternalState.FakeColumns = fakeIndices;
            return(request);
        }