Make the prover verification work

This commit is contained in:
Benjamin Loison 2023-04-16 19:43:21 +02:00
parent b336087da8
commit edfe8d183b
Signed by: Benjamin_Loison
SSH Key Fingerprint: SHA256:BtnEgYTlHdOg1u+RmYcDE0mnfz1rhv5dSbQ2gyxW8B8
2 changed files with 25 additions and 27 deletions

View File

@ -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=}')

View File

@ -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!")