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);
        }
Esempio n. 2
0
        public byte[] XOR(byte[] data)
        {
            byte[] keyBytes  = ToBytes();
            var    keyHash   = PromiseUtils.SHA512(keyBytes, 0, keyBytes.Length);
            var    encrypted = new byte[data.Length];

            for (int i = 0; i < encrypted.Length; i++)
            {
                encrypted[i] = (byte)(data[i] ^ keyHash[i % keyHash.Length]);
            }
            return(encrypted);
        }
        public ServerCommitmentsProof CheckRevelation(ClientRevelation revelation)
        {
            if (revelation == null)
            {
                throw new ArgumentNullException(nameof(revelation));
            }
            if (revelation.Salts.Length != Parameters.FakeTransactionCount ||
                revelation.FakeIndexes.Length != Parameters.FakeTransactionCount)
            {
                throw new ArgumentNullException("The revelation should contains " + Parameters.FakeTransactionCount +
                                                " indexes and salts");
            }
            AssertState(PromiseServerStates.WaitingRevelation);

            var indexSalt = revelation.IndexesSalt;

            if (InternalState.FakeIndexesHash != PromiseUtils.HashIndexes(ref indexSalt, revelation.FakeIndexes))
            {
                throw new PuzzleException("Invalid index salt");
            }

            List <PuzzleSolution> solutions = new List <PuzzleSolution>();

            for (int i = 0; i < Parameters.FakeTransactionCount; i++)
            {
                var salt             = revelation.Salts[i];
                var encrypted        = InternalState.EncryptedSignatures[revelation.FakeIndexes[i]];
                var actualSignedHash = Parameters.CreateFakeHash(salt);
                if (actualSignedHash != encrypted.SignedHash)
                {
                    throw new PuzzleException("Incorrect salt provided");
                }
                solutions.Add(encrypted.PuzzleSolution);
            }

            // We can throw away the fake puzzles
            InternalState.EncryptedSignatures = InternalState.EncryptedSignatures
                                                .Where((e, i) => !revelation.FakeIndexes.Contains(i)).ToArray();

            Quotient[] quotients = new Quotient[Parameters.RealTransactionCount - 1];
            for (int i = 0; i < InternalState.EncryptedSignatures.Length - 1; i++)
            {
                var a = InternalState.EncryptedSignatures[i].PuzzleSolution._Value;
                var b = InternalState.EncryptedSignatures[i + 1].PuzzleSolution._Value;
                quotients[i] = new Quotient(b.Multiply(a.ModInverse(Parameters.ServerKey._Key.Modulus))
                                            .Mod(Parameters.ServerKey._Key.Modulus));
            }

            InternalState.FakeIndexesHash = null;
            InternalState.Status          = PromiseServerStates.Completed;
            return(new ServerCommitmentsProof(solutions.ToArray(), quotients));
        }
Esempio n. 4
0
        public static byte[] XOR(byte[] data1, byte[] data2)
        {
            /*
             * Given how the "key" that XOR generates is not the same as the one
             * used in XOR anymore (check step 5), we can't use the "ToBytes()" function since
             * it assumes that the "key" in the XOR step has a size less than N (or "KeySize").
             * So I can either remove the call to the padding function in "ToBytes()" and use
             * the normal XOR function above, or use this independent function and not change
             * anything.
             *
             * If the second choice is better, then this function should move to "Utils" and
             * XOR is no longer needed in PromiseClientSession\PromiseServerSession since the
             * key can be generated directly using "Utils.GenerateEncryptableInteger()".
             */
            var keyHash   = PromiseUtils.SHA512(data1, 0, data1.Length);
            var encrypted = new byte[data2.Length];

            for (int i = 0; i < encrypted.Length; i++)
            {
                encrypted[i] = (byte)(data2[i] ^ keyHash[i % keyHash.Length]);
            }
            return(encrypted);
        }
        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);
        }
Esempio n. 6
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);
        }
Esempio n. 7
0
        public ServerCommitmentsProof CheckRevelation(ClientRevelation revelation, Script cashoutDestination, FeeRate feeRate)
        {
            /*
             * Steps 7, 9
             * Almost ready, just need to figure out:
             * - The CashOutFormat for the validation of RealSet.
             * - How to get the cashoutDestination and the feeRate,
             *   for now I pass them in like in "CreateSignatureRequest"
             *   from ClientSession.
             */

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

            var saltCount = revelation.Salts.Select(a => a.Length).Sum();

            if (saltCount != Parameters.GetTotalFakeTransactionsCount() || revelation.FakeIndexes.Length != Parameters.FakeTransactionCountPerLevel)
            {
                throw new ArgumentNullException($"The revelation should contains {Parameters.GetTotalFakeTransactionsCount()} salts and {Parameters.FakeTransactionCountPerLevel} indices");
            }

            var variationCount = revelation.FeeVariations.Select(a => a.Length).Sum();

            if (variationCount != Parameters.GetTotalRealTransactionsCount())
            {
                throw new ArgumentNullException($"The revelation should contains {Parameters.GetTotalRealTransactionsCount()} fee variations");
            }

            AssertState(PromiseServerStates.WaitingRevelation);

            var indexSalt = revelation.IndexesSalt;

            if (InternalState.FakeIndexesHash != PromiseUtils.HashIndexes(ref indexSalt, revelation.FakeIndexes))
            {
                throw new PuzzleException("Invalid index salt");
            }

            Transaction cashout = new Transaction();

            // TODO: Figure out the cashout format for j Bitcoins
            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());


            var solutions   = new PuzzleSolution[Parameters.PaymentsCount][];
            var RealIndexes = Enumerable.Range(0, Parameters.GetTotalTransactionsCountPerLevel()).Where(a => !revelation.FakeIndexes.Contains(a)).ToArray();

            for (int i = 0; i < solutions.Length; i++)
            {
                // Checking valid Transactions
                for (int j = 0; j < Parameters.RealTransactionCountPerLevel; j++)
                {
                    var feeVariation = revelation.FeeVariations[i][j];
                    var encrypted    = InternalState.EncryptedSignatures[i][RealIndexes[j]];
                    // Check if this function approved!
                    var actualSignedHash = Parameters.CreateRealHash(cashout, InternalState.EscrowedCoin, feeVariation);
                    if (actualSignedHash != encrypted.SignedHash)
                    {
                        throw new PuzzleException("Incorrect feeVariation provided");
                    }
                }
                // Checking Fake Transactions
                solutions[i] = new PuzzleSolution[Parameters.FakeTransactionCountPerLevel]; // Initialization
                for (int j = 0; j < solutions[i].Length; j++)
                {
                    var salt             = revelation.Salts[i][j];
                    var encrypted        = InternalState.EncryptedSignatures[i][revelation.FakeIndexes[j]];
                    var actualSignedHash = Parameters.CreateFakeHash(salt);
                    if (actualSignedHash != encrypted.SignedHash)
                    {
                        throw new PuzzleException("Incorrect salt provided");
                    }
                    solutions[i][j] = encrypted.PuzzleSolution;
                }
            }

            // We can throw away the fake puzzles
            InternalState.EncryptedSignatures = InternalState.EncryptedSignatures.Select(a => a.Where((e, i) => !revelation.FakeIndexes.Contains(i)).ToArray()).ToArray();

            // Step 9
            var quotients = new Quotient[Parameters.PaymentsCount][];

            for (int i = 0; i < quotients.Length; i++)
            {
                quotients[i] = new Quotient[Parameters.RealTransactionCountPerLevel - 1];
                for (int j = 0; j < quotients[i].Length; j++)
                {
                    var a = InternalState.EncryptedSignatures[i][j].PuzzleSolution._Value;
                    var b = InternalState.EncryptedSignatures[i][j + 1].PuzzleSolution._Value;
                    quotients[i][j] = new Quotient(b.Multiply(a.ModInverse(Parameters.ServerKey._Key.Modulus)).Mod(Parameters.ServerKey._Key.Modulus));
                }
            }

            InternalState.FakeIndexesHash = null;
            InternalState.Status          = PromiseServerStates.Completed;
            return(new ServerCommitmentsProof(solutions.ToArray(), quotients));
        }