From edfe8d183b254e77167afb008dc10d990cc9707e Mon Sep 17 00:00:00 2001 From: Benjamin Loison Date: Sun, 16 Apr 2023 19:43:21 +0200 Subject: [PATCH] Make the prover verification work --- prover.py | 26 +++++++++++--------------- verifier.py | 26 ++++++++++++++------------ 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/prover.py b/prover.py index 1455f05..5f6d5ee 100644 --- a/prover.py +++ b/prover.py @@ -13,24 +13,22 @@ protocolInitializationPhaseId = input('protocolInitializationPhaseId: ') # To ensure that this data is cheaper to store than to generate and to allow public verifiability by requiring the stored data to be Proof of Works. # For the ease of this implementation, the data are stored in the memory instead of the disk. -# Could rename `STORED_DATA` to what it is actually storing. -STORED_DATA = [] +STORED_NONCES = [] counter = 0 lastCounter = 0 LEAST_DIFFICULT_HASH = int('F' * (common.SECURITY_PARAMETER // 4), 16) -# We enforce `STORED_DATA` to have its length being a power of 2, to ease Merkle tree implementation. -while len(STORED_DATA) < common.ENTRIES_NUMBER: +# We enforce `STORED_NONCES` to have its length being a power of 2, to ease Merkle tree implementation. +while len(STORED_NONCES) < common.ENTRIES_NUMBER: hashed = common.hash(protocolInitializationPhaseId + str(counter)) hashedInteger = int(hashed, 16) hashedDifficulty = hashedInteger / LEAST_DIFFICULT_HASH if hashedDifficulty <= common.MAXIMUM_HASH_DIFFICULTY: deltaCounter = counter - lastCounter - deltaCounterBits = common.numberOfBitsOf(deltaCounter) - STORED_DATA += [deltaCounter] + STORED_NONCES += [deltaCounter] lastCounter = counter - print(len(STORED_DATA), common.ENTRIES_NUMBER) + print(len(STORED_NONCES), common.ENTRIES_NUMBER) counter += 1 ## Execution phase: 1. Receive a random bitstring from the verifier. @@ -49,7 +47,7 @@ def getNextMerkleTreeLevel(nodes): merkleTreeLevel = [] counter = 0 -for deltaCounter in STORED_DATA: +for deltaCounter in STORED_NONCES: counter += deltaCounter hashed = common.hash(protocolInitializationPhaseId + protocolExecutionPhaseId + str(counter)) merkleTreeLevel += [hashed] @@ -74,17 +72,15 @@ indexesRequest = ast.literal_eval(input('indexesRequest: ')) # Then just transmit the hashes of these indexes, as the verifier can compute these indexes on its own. # Then proceed to the Merkle tree root validation. Designing this first to make sure transmit in the easiest way make sense. -# Note that should avoid repeating already needed index, for instance if request 0 and 2 then it requires also 1 and 3 on the first level but on the second level it would be bad to mention twice on the above level 0 and 1. Let's don't care about this detail for this prototype. - -# Using an array of dict to keep array-lookup by indexes without wasting empty memory seems to make sense. - # For verifying treat level by level -# Can't just send the `dict`, as could fill penultimate both entries and not the previous ones, that way would end up with same Merkle tree root without providing it and without providing the given entries requested. # Just sending a list of hashes that the verifier fills its data structure with, as the prover generated this list. # So have to just verify that there's no such attack when filling the first level. # Verify especially my parsing even with the use of `ast.literal_eval` like the type and the size of entries and possibly subentries. +# Could also proceed index by index by providing entry and siblings up to the root for each index. +# Could use page 28 of FlyClient: Super-Light Clients for Cryptocurrencies for the implementation. + verificationMerkleTreeLevels = [{} for _ in range(common.LEVELS)] for indexRequest in indexesRequest: @@ -110,12 +106,12 @@ for verificationMerkleTreeLevelsIndex, verificationMerkleTreeLevel in enumerate( if verificationMerkleTreeLevelsIndex > 0 or leftIndex == index: if verificationMerkleTreeLevelsIndex == 0: print(leftIndex, rightIndex) - #entries += [leftHash, rightHash] + entries += [leftHash, rightHash] # for i, hash in zip([leftIndex, rightIndex], [leftHash, rightHash]): # verificationMerkleTreeLevels[verificationMerkleTreeLevelsIndex][i] = hash else: print(otherIndex) - #entries += [otherHash] + entries += [otherHash] # verificationMerkleTreeLevels[verificationMerkleTreeLevelsIndex][otherIndex] = otherHash print(f'{entries=}') diff --git a/verifier.py b/verifier.py index 102f11c..ab83e1f 100644 --- a/verifier.py +++ b/verifier.py @@ -3,6 +3,8 @@ import secrets, common, ast # Propose a probability of confidence setting is left for future work. +# Is actually a fraction giving a constant probability of confidence no matter the number of entries? I mean doesn't a constant number of entries to verify doesn't provide such a constant probability even for various number of entries? +# Have to address this scalability issue. FRACTION_OF_SPACE_TO_VERIFY = 10 ** -2 ## Initialization phase: Generate a random bitstring to send to the prover. @@ -42,7 +44,7 @@ print(f'{indexesRequest=}') # Add mentions of rationality and code its factor? or/and precise when to run initialization and execution phases # TODO: precising `entries` size could be interesting. -# TODO: verify hash difficulty +# TODO: verify hash difficulty - requires to send actual nonces # Proceeding in a minimum number of passes could be interesting but this can be left for future work. entries = ast.literal_eval(input('entries: ')) @@ -52,25 +54,24 @@ merkleTreeLevels = [{} for _ in range(common.LEVELS)] for index in indexesRequest: otherIndex = common.otherIndex(index) leftIndex, rightIndex = sorted([index, otherIndex]) - for i, hash in zip([leftIndex, rightIndex], [entries.pop() for _ in range(2)]): + for i, hash in zip([leftIndex, rightIndex], [entries.pop(0) for _ in range(2)]): merkleTreeLevels[0][i] = hash for merkleTreeLevelsIndex, merkleTreeLevel in enumerate(merkleTreeLevels[:-1]): print(merkleTreeLevelsIndex) + print('before', merkleTreeLevels[merkleTreeLevelsIndex]) for index in merkleTreeLevel.copy(): otherIndex = common.otherIndex(index) leftIndex, rightIndex = sorted([index, otherIndex]) - if merkleTreeLevelsIndex > 0 or leftIndex == index: - if merkleTreeLevelsIndex == 0: - for i, hash in zip([leftIndex, rightIndex], [entries.pop() for _ in range(2)]): - merkleTreeLevels[merkleTreeLevelsIndex][i] = hash - else: - print(f'current: {otherIndex}') - merkleTreeLevels[merkleTreeLevelsIndex][otherIndex] = entries.pop() + if merkleTreeLevelsIndex > 0: + print(f'current: {otherIndex}') + merkleTreeLevels[merkleTreeLevelsIndex][otherIndex] = entries.pop(0) leftHash, rightHash = [merkleTreeLevels[merkleTreeLevelsIndex][i] for i in [leftIndex, rightIndex]] - for i, hash in zip([leftIndex // 2, common.otherIndex(leftIndex)], [common.hash(leftHash + rightHash), '']): + merkleTreeLevels[merkleTreeLevelsIndex + 1][leftIndex // 2] = common.hash(leftHash + rightHash) + """for i, hash in zip([leftIndex // 2, common.otherIndex(leftIndex)], [common.hash(leftHash + rightHash), '']): print(f'next: {i}') - merkleTreeLevels[merkleTreeLevelsIndex + 1][i] = hash + merkleTreeLevels[merkleTreeLevelsIndex + 1][i] = hash""" + print('after', merkleTreeLevels[merkleTreeLevelsIndex]) """ for merkleTreeLevelsIndex, merkleTreeLevel in enumerate(merkleTreeLevels[:-1]): @@ -87,7 +88,8 @@ for merkleTreeLevelsIndex, merkleTreeLevel in enumerate(merkleTreeLevels[:-1]): actualStorage = common.ENTRIES_NUMBER * common.NUMBER_OF_BITS_IN_AVERAGE_FOR_SOLVING_PUZZLE if merkleTreeRoot == merkleTreeLevels[-1][0] and actualStorage >= common.SPACE_TO_PROVE_IN_BITS: - print(f'Verified with high probability that the prover is storing {common.SPACE_TO_PROVE_IN_BITS} (actually the prover is storing {actualStorage} bits)') + # Could precise the probability. + print(f'Verified with some probability that the prover is storing in average {common.SPACE_TO_PROVE_IN_BITS} (actually the prover is storing in average {actualStorage} bits)') else: print("The prover hasn't provided a correct proof!")