Correcting latest details before having a working proof verification

This commit is contained in:
Benjamin Loison 2023-04-13 01:46:09 +02:00
parent e58af4e3d0
commit b336087da8
Signed by: Benjamin_Loison
SSH Key Fingerprint: SHA256:BtnEgYTlHdOg1u+RmYcDE0mnfz1rhv5dSbQ2gyxW8B8
3 changed files with 80 additions and 38 deletions

View File

@ -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
return math.floor(math.log2(n)) + 1
def otherIndex(n):
return n + (1 if n % 2 == 0 else -1)

View File

@ -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):

View File

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