Add implementation up to (excluded) exchanging the random set of indices

This commit is contained in:
Benjamin Loison 2023-04-10 18:53:42 +02:00
parent 11daae87ad
commit ad82609715
Signed by: Benjamin_Loison
SSH Key Fingerprint: SHA256:BtnEgYTlHdOg1u+RmYcDE0mnfz1rhv5dSbQ2gyxW8B8
3 changed files with 86 additions and 21 deletions

View File

@ -1 +1,8 @@
SECURITY_PARAMETER = 256
from hashlib import sha256
SECURITY_PARAMETER = 256
MAXIMUM_HASH_DIFFICULTY = 1 / 16
SPACE_TO_PROVE_IN_BITS = 1_000
def hash(x):
return sha256(x.encode('ascii')).hexdigest()

View File

@ -1,39 +1,75 @@
# Proof of Space-Time prover
## Proof of Space-Time prover
import math, common
from hashlib import sha256
SPACE_TO_PROVE_IN_BITS = 1_000
MAXIMUM_HASH_DIFFICULTY = 0.1
# 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.
# 1. Receive a random bitstring from the verifier.
## Initialization phase: 1. Receive a random bitstring from the verifier.
protocolExecutionId = input('protocolExecutionId: ')
protocolInitializationPhaseId = input('protocolInitializationPhaseId: ')
# 2. Generate in a table the data that the prover has to store.
## Initialization phase: 2. Generate in a table the data that the prover has to store.
# 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_DATA_IN_BITS = 0
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 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))
# 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.
hash = sha256((protocolExecutionId + str(counter)).encode('ascii')).hexdigest()
hashInteger = int(hash, 16)
hashDifficulty = hashInteger / LEAST_DIFFICULT_HASH
if hashDifficulty <= MAXIMUM_HASH_DIFFICULTY:
lastCounter = STORED_DATA[-1] if STORED_DATA != [] else -1
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.ceil(math.log2(deltaCounter))
deltaCounterBits = math.floor(math.log2(deltaCounter)) + 1
STORED_DATA += [deltaCounter]
STORED_DATA_IN_BITS += deltaCounterBits
print(hash, hashDifficulty, counter, lastCounter, deltaCounterBits)
lastCounter = counter
counter += 1
## Execution phase: 1. Receive a random bitstring from the verifier.
protocolExecutionPhaseId = input('protocolExecutionPhaseId: ')
## Execution phase: 2. The prover commits to the table contents given this random challenge.
def pairwise(iterable):
"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)
return zip(a, a)
def getNextMerkleTreeLevel(nodes):
return [hash(leftNode + rightNode) for leftNode, rightNode in pairwise(nodes)]
merkleTreeLevel = []
counter = 0
for deltaCounter in STORED_DATA:
counter += deltaCounter
hashed = hash(protocolInitializationPhaseId + protocolExecutionPhaseId + str(counter))
merkleTreeLevel += [hashed]
merkleTreeLevels = [merkleTreeLevel]
while len(merkleTreeLevels[-1]) > 1:
nextMerkleTreeLevel = getNextMerkleTreeLevel(merkleTreeLevels[-1])
merkleTreeLevels += [nextMerkleTreeLevel]
merkleTreeRoot = merkleTreeLevels[-1]
print(f'{merkleTreeRoot=}')
## Execution phase: 3. Receive a random set of indices from the prover.
## Execution phase: 4.

View File

@ -1,11 +1,33 @@
# Proof of Space-Time verifier
## Proof of Space-Time verifier
import secrets, common
# 1. Generate a random bitstring to send to the prover.
def generateARandomHexString(hexStringLength):
return ''.join(secrets.choice('0123456789abcdef') for _ in range(hexStringLength))
## Initialization phase: 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.
protocolExecutionId = ''.join(secrets.choice('0123456789abcdef') for _ in range(common.SECURITY_PARAMETER // 4))
print(protocolExecutionId)
protocolInitializationPhaseId = generateARandomHexString(common.SECURITY_PARAMETER // 4)
print(f'{protocolInitializationPhaseId=}')
## 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)
print(f'{protocolExecutionPhaseId=}')
## Execution phase: 2. Receive the prover commitment to the table contents given this random challenge.
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.
## Execution phase: 4. Receive and verify corresponding table entries and commitment openings.
# 2.