WIP for correctly estimating the proved storage size

This commit is contained in:
Benjamin Loison 2023-04-12 18:21:39 +02:00
parent ad82609715
commit 126bd7c16a
Signed by: Benjamin_Loison
SSH Key Fingerprint: SHA256:BtnEgYTlHdOg1u+RmYcDE0mnfz1rhv5dSbQ2gyxW8B8
3 changed files with 40 additions and 10 deletions

View File

@ -1,8 +1,17 @@
import math
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.
MAXIMUM_HASH_DIFFICULTY = 1 / 16
# The following space is a minimum.
SPACE_TO_PROVE_IN_BITS = 1_000
def hash(x):
return sha256(x.encode('ascii')).hexdigest()
return sha256(x.encode('ascii')).hexdigest()
# Storage could be done by using a separator but is it optimal? In fact how to do a separator optimally in binary? Could for instance encode on two bits, for normal bits the first one should be 0 otherwise if the first is 1 then whatever the second bit, it's a separator.
# TODO: sure that this function is meaningly correct? cf below comment, should also consider the serialization of the actual array
# Have to pay attention that `0` isn't interesting us.
def numberOfBitsOf(n):
return math.floor(math.log2(n)) + 1

View File

@ -23,18 +23,23 @@ 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 STORED_DATA_IN_BITS < SPACE_TO_PROVE_IN_BITS or not math.log2(len(STORED_DATA)).is_integer():
print(STORED_DATA_IN_BITS, len(STORED_DATA))
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 = math.floor(math.log2(deltaCounter)) + 1
deltaCounterBits = common.numberOfBitsOf(deltaCounter)
STORED_DATA += [deltaCounter]
STORED_DATA_IN_BITS += deltaCounterBits
lastCounter = counter
print(STORED_DATA_IN_BITS, len(STORED_DATA))
counter += 1
# TODO: update `SPACE_TO_PROVE_IN_BITS` to prove more than what initially intended to.
entriesNumber = len(STORED_DATA)
print(f'{entriesNumber=}')
## Execution phase: 1. Receive a random bitstring from the verifier.
protocolExecutionPhaseId = input('protocolExecutionPhaseId: ')
@ -68,8 +73,10 @@ print(f'{merkleTreeRoot=}')
## Execution phase: 3. Receive a random set of indices from the prover.
indicesRequest = input('indicesRequest: ')
## Execution phase: 4. Respond with the corresponding table entries and commitment openings.
## Execution phase: 4.

View File

@ -2,20 +2,24 @@
import secrets, common
def generateARandomHexString(hexStringLength):
return ''.join(secrets.choice('0123456789abcdef') for _ in range(hexStringLength))
# Should instead propose a probability of confidence setting.
FRACTION_OF_SPACE_TO_VERIFY = 10 ** -2
## Initialization phase: Generate a random bitstring to send to the prover.
## Initialization phase: 1. Generate a random bitstring to send to the prover.
# To make sure that the following protocol execution can't be used partially or totally by the prover to reduce the cost of another protocol execution.
protocolInitializationPhaseId = generateARandomHexString(common.SECURITY_PARAMETER // 4)
protocolInitializationPhaseId = secrets.token_hex(common.SECURITY_PARAMETER // 8)
print(f'{protocolInitializationPhaseId=}')
## Initialization phase: 2. Receive the table size of the prover.
entriesNumber = input('entriesNumber: ')
## Execution phase: 1. Generate a random bitstring to send to the prover.
# TODO: improve step numbering
# Wait the initialization phase termination from the prover side before starting the execution phase.
protocolExecutionPhaseId = generateARandomHexString(common.SECURITY_PARAMETER // 4)
protocolExecutionPhaseId = secrets.token_hex(common.SECURITY_PARAMETER // 8)
print(f'{protocolExecutionPhaseId=}')
## Execution phase: 2. Receive the prover commitment to the table contents given this random challenge.
@ -24,10 +28,20 @@ merkleTreeRoot = input('merkleTreeRoot: ')
## Execution phase: 3. Generate and send a random set of indices to the prover.
# Need to know the actual table size to choose a random set of indices. This point isn't discussed to the best of my knowledge in Simple Proofs of Space-Time and Rational Proofs of Storage, Tal Moran and Ilan Orlov, 2016.
# Need to know the actual table size to choose a random set of indices. This point isn't discussed to the best of my knowledge in Simple Proofs of Space-Time and Rational Proofs of Storage, Tal Moran and Ilan Orlov, 2016. In a more important manner, it's unclear how the prover proves to the verifier precisely with high probability or *for sure* that he is actually storing a given number of bits.
# For this prototype the prover claims a given table size and the verifier estimate the total table number of bits thanks to the requested set of its entries.
# Note that there's no advantage to request the last table entry by hoping that the prover is storing the nonces with delta in such order, for instance he can have stored the delta the other way around which screw up this additional request aim.
indicesRequest = set()
while len(indicesRequest) < entriesNumber * FRACTION_OF_SPACE_TO_VERIFY:
index = secrets.randbelow(entriesNumber)
indicesRequest.add(index)
print(f'{indicesRequest=}')
## 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