From 126bd7c16a15aa3e706d716542fa3147cf37a551 Mon Sep 17 00:00:00 2001 From: Benjamin Loison Date: Wed, 12 Apr 2023 18:21:39 +0200 Subject: [PATCH] WIP for correctly estimating the proved storage size --- common.py | 11 ++++++++++- prover.py | 13 ++++++++++--- verifier.py | 26 ++++++++++++++++++++------ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/common.py b/common.py index 00d49bd..05ed28f 100644 --- a/common.py +++ b/common.py @@ -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() \ No newline at end of file + 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 \ No newline at end of file diff --git a/prover.py b/prover.py index 66359d8..15211d0 100644 --- a/prover.py +++ b/prover.py @@ -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. diff --git a/verifier.py b/verifier.py index 244d9a0..53486cd 100644 --- a/verifier.py +++ b/verifier.py @@ -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