From b336087da8233a585bb737a28ba7f25e4c693115 Mon Sep 17 00:00:00 2001 From: Benjamin Loison Date: Thu, 13 Apr 2023 01:46:09 +0200 Subject: [PATCH] Correcting latest details before having a working proof verification --- common.py | 12 ++++++++--- prover.py | 48 ++++++++++++++++---------------------------- verifier.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 80 insertions(+), 38 deletions(-) diff --git a/common.py b/common.py index 8d4d815..0fa6fe7 100644 --- a/common.py +++ b/common.py @@ -3,13 +3,16 @@ from hashlib import sha256 SECURITY_PARAMETER = 256 # Note that `MAXIMUM_HASH_DIFFICULTY` and `SPACE_TO_PROVE_IN_BITS` should be sent from the prover to the verifier before the second verifier initialization step. However to ease this prototype this communication isn't performed. +# For the ease of this prototype only 1 / (2 ** n) values are supported for `MAXIMUM_HASH_DIFFICULTY`. MAXIMUM_HASH_DIFFICULTY = 1 / 16 # The following space is a minimum. SPACE_TO_PROVE_IN_BITS = 1_000 -ENTRIES_NUMBER = math.ceil(SPACE_TO_PROVE_IN_BITS // int(math.log2(1 / MAXIMUM_HASH_DIFFICULTY))) -# To ease Merkle tree implementation. +NUMBER_OF_BITS_IN_AVERAGE_FOR_SOLVING_PUZZLE = int(math.log2(1 / MAXIMUM_HASH_DIFFICULTY)) +ENTRIES_NUMBER = math.ceil(SPACE_TO_PROVE_IN_BITS // NUMBER_OF_BITS_IN_AVERAGE_FOR_SOLVING_PUZZLE) +# To ease Merkle tree implementation use a power of 2 number of leafs. ENTRIES_NUMBER = 2 ** math.ceil(math.log2(ENTRIES_NUMBER)) +LEVELS = int(math.log2(ENTRIES_NUMBER)) + 1 def hash(x): return sha256(x.encode('ascii')).hexdigest() @@ -18,4 +21,7 @@ def hash(x): # TODO: sure that this function is meaningly correct? cf below comment, should also consider the serialization of the actual array - should in a similar way verify `ENTRIES_NUMBER` computation # Have to pay attention that `0` isn't interesting us. def numberOfBitsOf(n): - return math.floor(math.log2(n)) + 1 \ No newline at end of file + return math.floor(math.log2(n)) + 1 + +def otherIndex(n): + return n + (1 if n % 2 == 0 else -1) \ No newline at end of file diff --git a/prover.py b/prover.py index c40721c..1455f05 100644 --- a/prover.py +++ b/prover.py @@ -1,6 +1,6 @@ ## Proof of Space-Time prover -import math, common +import math, common, ast # For the ratio between storing and power: # Note that for a production ready system hashing speedup (as designed for Bitcoin in [AsicBoost - A Speedup for Bitcoin Mining, Dr. Timo Hanke, March 31, 2016 (rev. 5)](https://arxiv.org/pdf/1604.00575.pdf)) should be considered. @@ -66,7 +66,7 @@ print(f'{merkleTreeRoot=}') ## Execution phase: 3. Receive a random set of indexes from the verifier. -indexesRequest = set([int(n) for n in input('indexesRequest: ')[1:-1].split(',')]) +indexesRequest = ast.literal_eval(input('indexesRequest: ')) ## Execution phase: 4. Respond with the corresponding table entries and commitment openings. @@ -83,54 +83,40 @@ indexesRequest = set([int(n) for n in input('indexesRequest: ')[1:-1].split(',') # 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. -indexes = [] - -""" -for indexRequest in indexesRequest: - otherIndex = indexRequest + (1 if indexRequest % 2 == 0 else -1) - #indexes += [] - leftIndex, rightIndex = sorted([indexRequest, otherIndex]) - #leftHash, rightHash = merkleTreeLevels[0][leftIndex], merkleTreeLevels[0][rightIndex] -""" - -levels = int(math.log2(common.ENTRIES_NUMBER)) + 1 -verificationMerkleTreeLevels = [{} for _ in range(levels)] +verificationMerkleTreeLevels = [{} for _ in range(common.LEVELS)] for indexRequest in indexesRequest: - otherIndex = indexRequest + (1 if indexRequest % 2 == 0 else -1) + otherIndex = common.otherIndex(indexRequest) for index in [indexRequest, otherIndex]: verificationMerkleTreeLevels[0][index] = merkleTreeLevels[0][index] -#import copy - -#verificationMerkleTreeLevels = copy.deepcopy(merkleTreeLevels) - +""" for merkleTreeLevelsIndex, merkleTreeLevel in enumerate(merkleTreeLevels): for i, hash in enumerate(merkleTreeLevel): verificationMerkleTreeLevels[merkleTreeLevelsIndex][i] = hash +""" entries = [] for verificationMerkleTreeLevelsIndex, verificationMerkleTreeLevel in enumerate(verificationMerkleTreeLevels[:-1]): - #print(verificationMerkleTreeLevel) for index in verificationMerkleTreeLevel: - otherIndex = index + (1 if index % 2 == 0 else -1) + otherIndex = common.otherIndex(index) leftIndex, rightIndex = sorted([index, otherIndex]) - #leftHash, rightHash = verificationMerkleTreeLevel[leftIndex], verificationMerkleTreeLevel[rightIndex] - leftHash, rightHash = merkleTreeLevels[verificationMerkleTreeLevelsIndex][leftIndex], merkleTreeLevels[verificationMerkleTreeLevelsIndex][rightIndex] + #leftHash, rightHash = [merkleTreeLevels[verificationMerkleTreeLevel][i] for i in [leftIndex, rightIndex]] + leftHash, rightHash = [merkleTreeLevels[verificationMerkleTreeLevelsIndex][i] for i in [leftIndex, rightIndex]] otherHash = merkleTreeLevels[verificationMerkleTreeLevelsIndex][otherIndex] verificationMerkleTreeLevels[verificationMerkleTreeLevelsIndex + 1][leftIndex // 2] = common.hash(leftHash + rightHash) if verificationMerkleTreeLevelsIndex > 0 or leftIndex == index: if verificationMerkleTreeLevelsIndex == 0: - #print(leftIndex, rightIndex) - entries += [leftHash, rightHash] + print(leftIndex, rightIndex) + #entries += [leftHash, rightHash] + # for i, hash in zip([leftIndex, rightIndex], [leftHash, rightHash]): + # verificationMerkleTreeLevels[verificationMerkleTreeLevelsIndex][i] = hash else: - #print(otherIndex) - entries += [otherHash] + print(otherIndex) + #entries += [otherHash] + # verificationMerkleTreeLevels[verificationMerkleTreeLevelsIndex][otherIndex] = otherHash print(f'{entries=}') -# Assuming first level filled. - -#for level in range(levels): - diff --git a/verifier.py b/verifier.py index 0772380..102f11c 100644 --- a/verifier.py +++ b/verifier.py @@ -1,8 +1,8 @@ ## Proof of Space-Time verifier -import secrets, common +import secrets, common, ast -# Should instead propose a probability of confidence setting. +# Propose a probability of confidence setting is left for future work. FRACTION_OF_SPACE_TO_VERIFY = 10 ** -2 ## Initialization phase: Generate a random bitstring to send to the prover. @@ -12,7 +12,7 @@ protocolInitializationPhaseId = secrets.token_hex(common.SECURITY_PARAMETER // 8 print(f'{protocolInitializationPhaseId=}') ## Execution phase: 1. Generate a random bitstring to send to the prover. -# TODO: improve step numbering +# TODO: improve step numbering, as it's a bit unclear what step of each to run after which one # Wait the initialization phase termination from the prover side before starting the execution phase. protocolExecutionPhaseId = secrets.token_hex(common.SECURITY_PARAMETER // 8) @@ -39,5 +39,55 @@ print(f'{indexesRequest=}') ## Execution phase: 4. Receive and verify corresponding table entries and commitment openings. -# Use `MAXIMUM_HASH_DIFFICULTY` to estimate amount of stored data and any incorrect hash shows that the prover cheated +# 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 +# Proceeding in a minimum number of passes could be interesting but this can be left for future work. + +entries = ast.literal_eval(input('entries: ')) + +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)]): + merkleTreeLevels[0][i] = hash + +for merkleTreeLevelsIndex, merkleTreeLevel in enumerate(merkleTreeLevels[:-1]): + print(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() + leftHash, rightHash = [merkleTreeLevels[merkleTreeLevelsIndex][i] for i in [leftIndex, rightIndex]] + for i, hash in zip([leftIndex // 2, common.otherIndex(leftIndex)], [common.hash(leftHash + rightHash), '']): + print(f'next: {i}') + merkleTreeLevels[merkleTreeLevelsIndex + 1][i] = hash + +""" +for merkleTreeLevelsIndex, merkleTreeLevel in enumerate(merkleTreeLevels[:-1]): + for index in merkleTreeLevel: + otherIndex = common.otherIndex(index) + leftIndex, rightIndex = sorted([index, otherIndex]) + leftHash, rightHash = [merkleTreeLevels[merkleTreeLevel][i] for i in [leftIndex, rightIndex]] + otherHash = merkleTreeLevels[merkleTreeLevelsIndex][otherIndex] + merkleTreeLevels[merkleTreeLevelsIndex + 1][leftIndex // 2] = common.hash(leftHash + rightHash) +""" + +# Note that `actualStorage` is the average storage that the prover should have dedicated to be able to solve this execution phase challenge. +# If any entry corresponding to requested indexes is incorrect, the Merkle tree won't match or the verification of the claimed difficulty of the provided hash will fail. +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)') +else: + print("The prover hasn't provided a correct proof!")