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 State GetInternalState() { State state = Serializer.Clone(InternalState); state.Salts = null; state.FeeVariations = null; state.Commitments = null; if (_Hashes != null) { var commitments = new ServerCommitment[_Hashes.Length][]; var salts = new uint256[_Hashes.Length][]; var feeVariations = new Money[_Hashes.Length][]; for (int i = 0; i < _Hashes.Length; i++) { salts[i] = new uint256[_Parameters.FakeTransactionCountPerLevel]; feeVariations[i] = new Money[_Parameters.RealTransactionCountPerLevel]; commitments[i] = new ServerCommitment[_Hashes[i].Length]; int fakeJ = 0, realJ = 0; for (int j = 0; j < _Hashes[i].Length; j++) { if (_Hashes[i][j] is FakeHash fake) { salts[i][fakeJ++] = fake.Salt; } if (_Hashes[i][j] is RealHash real) { feeVariations[i][realJ++] = real.FeeVariation; } commitments[i][j] = _Hashes[i][j].Commitment; } } state.Salts = salts; state.FeeVariations = feeVariations; state.Commitments = commitments; } return(state); }