public PuzzleValue[] GeneratePuzzles() { AssertState(SolverClientStates.WaitingGeneratePuzzles); List <PuzzleSetElement> puzzles = new List <PuzzleSetElement>(); for (int i = 0; i < Parameters.RealPuzzleCount; i++) { BlindFactor blind = null; Puzzle puzzle = new Puzzle(ServerKey, InternalState.Puzzle).Blind(ref blind); puzzles.Add(new RealPuzzle(puzzle, blind)); } for (int i = 0; i < Parameters.FakePuzzleCount; i++) { PuzzleSolution solution = null; Puzzle puzzle = ServerKey.GeneratePuzzle(ref solution); puzzles.Add(new FakePuzzle(puzzle, solution)); } _PuzzleElements = puzzles.ToArray(); NBitcoin.Utils.Shuffle(_PuzzleElements, RandomUtils.GetInt32()); InternalState.FakeIndexes = new int[Parameters.FakePuzzleCount]; int fakeI = 0; for (int i = 0; i < _PuzzleElements.Length; i++) { _PuzzleElements[i].Index = i; if (_PuzzleElements[i] is FakePuzzle) { InternalState.FakeIndexes[fakeI++] = i; } } InternalState.Status = SolverClientStates.WaitingCommitments; return(_PuzzleElements.Select(p => p.Puzzle.PuzzleValue).ToArray()); }
public State GetInternalState() { var state = Serializer.Clone(InternalState); if (_PuzzleElements != null) { var commitments = new ServerCommitment[_PuzzleElements.Length]; var puzzles = new PuzzleValue[_PuzzleElements.Length]; var fakeSolutions = new PuzzleSolution[Parameters.FakePuzzleCount]; var blinds = new BlindFactor[Parameters.RealPuzzleCount]; int fakeI = 0, realI = 0; for (int i = 0; i < _PuzzleElements.Length; i++) { commitments[i] = _PuzzleElements[i].Commitment; puzzles[i] = _PuzzleElements[i].Puzzle.PuzzleValue; var fake = _PuzzleElements[i] as FakePuzzle; if (fake != null) { fakeSolutions[fakeI++] = fake.Solution; } var real = _PuzzleElements[i] as RealPuzzle; if (real != null) { blinds[realI++] = real.BlindFactor; } } state.FakeSolutions = fakeSolutions; state.BlindFactors = blinds; state.Commitments = commitments; state.Puzzles = puzzles; } return(state); }
public void BlindFactorTest() { BlindFactor data = new BlindFactor("aa00000000000000000000000000000000000000000000000000000000000001"); Assert.Equal("aa00000000000000000000000000000000000000000000000000000000000001", data.ToHexString()); BlindFactor data2 = new BlindFactor(data.GetBytes()); Assert.Equal(data.ToHexString(), data2.ToHexString()); }
public void ReceiveUnsignedVoucher(UnsignedVoucherInformation voucher) { AssertState(TumblerClientSessionStates.WaitingVoucher); var puzzle = new Puzzle(Parameters.VoucherKey.PublicKey, voucher.Puzzle); InternalState.UnsignedVoucher = voucher; BlindFactor factor = null; InternalState.BlindedVoucher = puzzle.Blind(ref factor).PuzzleValue; InternalState.BlindedVoucherFactor = factor; InternalState.Status = TumblerClientSessionStates.WaitingTumblerClientTransactionKey; }
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); }
public PuzzleValue CheckCommitmentProof(ServerCommitmentsProof proof) { if (proof == null) { throw new ArgumentNullException(nameof(proof)); } if (proof.FakeSolutions.Length != Parameters.FakeTransactionCount) { throw new ArgumentException("Expecting " + Parameters.FakeTransactionCount + " solutions"); } if (proof.Quotients.Length != Parameters.RealTransactionCount - 1) { throw new ArgumentException("Expecting " + (Parameters.RealTransactionCount - 1) + " quotients"); } AssertState(PromiseClientStates.WaitingCommitmentsProof); var fakeHashes = _Hashes.OfType <FakeHash>().ToArray(); for (int i = 0; i < proof.FakeSolutions.Length; i++) { var fakeHash = fakeHashes[i]; var solution = proof.FakeSolutions[i]; if (solution._Value.CompareTo(Parameters.ServerKey._Key.Modulus) >= 0) { throw new PuzzleException("Solution bigger than modulus"); } if (!new Puzzle(Parameters.ServerKey, fakeHash.Commitment.Puzzle).Verify(solution)) { throw new PuzzleException("Invalid puzzle solution"); } if (!IsValidSignature(solution, fakeHash, out ECDSASignature sig)) { throw new PuzzleException("Invalid ECDSA signature"); } } var realHashes = _Hashes.OfType <RealHash>().ToArray(); for (int i = 1; i < Parameters.RealTransactionCount; i++) { var q = proof.Quotients[i - 1]._Value; var p1 = realHashes[i - 1].Commitment.Puzzle._Value; var p2 = realHashes[i].Commitment.Puzzle._Value; var p22 = p1.Multiply(Parameters.ServerKey.Encrypt(q)).Mod(Parameters.ServerKey._Key.Modulus); if (!p2.Equals(p22)) { throw new PuzzleException("Invalid quotient"); } } _Hashes = _Hashes.OfType <RealHash>().ToArray(); // we do not need the fake one anymore InternalState.FakeIndexes = null; InternalState.Quotients = proof.Quotients; var puzzleToSolve = _Hashes.OfType <RealHash>().First().Commitment.Puzzle; BlindFactor blind = null; var blindedPuzzle = new Puzzle(Parameters.ServerKey, puzzleToSolve).Blind(ref blind); InternalState.BlindFactor = blind; InternalState.Status = PromiseClientStates.Completed; return(blindedPuzzle.PuzzleValue); }
public RealPuzzle(Puzzle puzzle, BlindFactor blindFactory) { Puzzle = puzzle; BlindFactor = blindFactory; }
public PuzzleValue[] CheckCommitmentProof(ServerCommitmentsProof proof) { // steps 8, 10, 12 if (proof == null) { throw new ArgumentNullException(nameof(proof)); } var FakeSolutionsCount = proof.FakeSolutions.Select(a => a.Length).Sum(); // sums the number of FakeSolutions. if (FakeSolutionsCount != Parameters.GetTotalFakeTransactionsCount()) { throw new ArgumentException($"Expecting {Parameters.GetTotalFakeTransactionsCount()} solutions"); } var QuotientsCount = proof.Quotients.Select(a => a.Length).Sum(); // sums the number of Quotients. if (QuotientsCount != (Parameters.GetTotalRealTransactionsCount() - _Parameters.PaymentsCount)) // this is Q * (mu - 1) { throw new ArgumentException($"Expecting {(Parameters.GetTotalRealTransactionsCount() - _Parameters.PaymentsCount)} quotients"); } AssertState(PromiseClientStates.WaitingCommitmentsProof); var previousSolutions = new byte[Parameters.FakeTransactionCountPerLevel][]; previousSolutions = previousSolutions.Select(a => new byte[0]).ToArray(); // Initialize to empty for (int i = 0; i < _Hashes.Length; i++) { var fakeHashes = _Hashes[i].OfType <FakeHash>().ToArray(); for (int j = 0; j < fakeHashes.Length; j++) { // TODO: prove that the solutions are lined up in same order as the hashes. var fakeHash = fakeHashes[j]; var solution = proof.FakeSolutions[i][j]; if (solution._Value.CompareTo(Parameters.ServerKey._Key.Modulus) >= 0) { throw new PuzzleException("Solution bigger than modulus"); } if (!new Puzzle(Parameters.ServerKey, fakeHash.Commitment.Puzzle).Verify(solution)) { throw new PuzzleException("Invalid puzzle solution"); } previousSolutions[j] = Utils.Combine(solution.ToBytes(), previousSolutions[j]); var paddedSolution = new PuzzleSolution(Utils.Combine(NBitcoin.Utils.ToBytes((uint)i, true), NBitcoin.Utils.ToBytes((uint)fakeHash.Index, true), previousSolutions[j])); if (!IsValidSignature(paddedSolution, fakeHash, out ECDSASignature sig)) { throw new PuzzleException("Invalid ECDSA signature"); } } } // Step 10 for (int i = 0; i < _Hashes.Length; i++) { var realHashes = _Hashes[i].OfType <RealHash>().ToArray(); for (int j = 1; j < realHashes.Length; j++) { var q = proof.Quotients[i][j - 1]._Value; var p1 = realHashes[j - 1].Commitment.Puzzle._Value; var p2 = realHashes[j].Commitment.Puzzle._Value; var p22 = p1.Multiply(Parameters.ServerKey.Encrypt(q)).Mod(Parameters.ServerKey._Key.Modulus); if (!p2.Equals(p22)) { throw new PuzzleException("Invalid quotient"); } } } _Hashes = _Hashes.Select(a => a.OfType <RealHash>().ToArray()).ToArray(); // we do not need the fake one anymore InternalState.FakeColumns = null; InternalState.Quotients = proof.Quotients; // Step 12 // Maybe move this step outside such that we can blind and send puzzles one by one. BlindFactor[] blindFactors = new BlindFactor[_Hashes.Length]; PuzzleValue[] blindedPuzzles = new PuzzleValue[_Hashes.Length]; for (int i = 0; i < _Hashes.Length; i++) { var puzzleToSolve = _Hashes[i].OfType <RealHash>().First().Commitment.Puzzle; blindedPuzzles[i] = new Puzzle(Parameters.ServerKey, puzzleToSolve).Blind(ref blindFactors[i]).PuzzleValue; } InternalState.BlindFactors = blindFactors; InternalState.Status = PromiseClientStates.Completed; return(blindedPuzzles); }