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 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); }