Optimized proof size down by 1/8 or so

This commit is contained in:
Vitalik Buterin 2018-07-20 13:07:45 -04:00
parent 63599737d1
commit cf7e8e1e63
4 changed files with 33 additions and 33 deletions

View File

@ -98,11 +98,11 @@ def verify_low_degree_proof(merkle_root, root_of_unity, proof, maxdeg_plus_1, mo
xcoords.append([(quartic_roots_of_unity[j] * x1) % modulus for j in range(4)]) xcoords.append([(quartic_roots_of_unity[j] * x1) % modulus for j in range(4)])
# The values from the original polynomial # The values from the original polynomial
row = [verify_branch(merkle_root, y + (roudeg // 4) * j, prf) row = [verify_branch(merkle_root, y + (roudeg // 4) * j, prf, output_as_int=True)
for j, prf in zip(range(4), branches[i][1:])] for j, prf in zip(range(4), branches[i][1:])]
rows.append(row) rows.append(row)
columnvals.append(verify_branch(root2, y, branches[i][0])) columnvals.append(verify_branch(root2, y, branches[i][0], output_as_int=True))
# Verify for each selected y coordinate that the four points from the # Verify for each selected y coordinate that the four points from the
# polynomial and the one point from the column that are on that y # polynomial and the one point from the column that are on that y

View File

@ -5,7 +5,7 @@ except:
blake = lambda x: blake2s(x).digest() blake = lambda x: blake2s(x).digest()
def merkelize(L): def merkelize(L):
nodes = [b''] * len(L) + [x.to_bytes(32, 'big') for x in L] nodes = [b''] * len(L) + [x.to_bytes(32, 'big') if isinstance(x, int) else x for x in L]
for i in range(len(L) - 1, 0, -1): for i in range(len(L) - 1, 0, -1):
nodes[i] = blake(nodes[i*2] + nodes[i*2+1]) nodes[i] = blake(nodes[i*2] + nodes[i*2+1])
return nodes return nodes
@ -18,7 +18,7 @@ def mk_branch(tree, index):
index //= 2 index //= 2
return o return o
def verify_branch(root, index, proof): def verify_branch(root, index, proof, output_as_int=False):
index += 2**len(proof) index += 2**len(proof)
v = proof[0] v = proof[0]
for p in proof[1:]: for p in proof[1:]:
@ -28,6 +28,6 @@ def verify_branch(root, index, proof):
v = blake(v + p) v = blake(v + p)
index //= 2 index //= 2
assert v == root assert v == root
return int.from_bytes(proof[0], 'big') return int.from_bytes(proof[0], 'big') if output_as_int else proof[0]

View File

@ -89,19 +89,20 @@ def mk_mimc_proof(inp, steps, round_constants):
b_evaluations = [((p - i) * invq) % modulus for p, i, invq in zip(p_evaluations, i_evaluations, inv_z2_evaluations)] b_evaluations = [((p - i) * invq) % modulus for p, i, invq in zip(p_evaluations, i_evaluations, inv_z2_evaluations)]
print('Computed B polynomial') print('Computed B polynomial')
# Compute their Merkle roots # Compute their Merkle root
p_mtree = merkelize(p_evaluations) mtree = merkelize([pval.to_bytes(32, 'big') +
d_mtree = merkelize(d_evaluations) dval.to_bytes(32, 'big') +
b_mtree = merkelize(b_evaluations) bval.to_bytes(32, 'big') for
pval, dval, bval in zip(p_evaluations, d_evaluations, b_evaluations)])
print('Computed hash root') print('Computed hash root')
# Based on the hashes of P, D and B, we select a random linear combination # Based on the hashes of P, D and B, we select a random linear combination
# of P * x^steps, P, B * x^steps, B and D, and prove the low-degreeness of that, # of P * x^steps, P, B * x^steps, B and D, and prove the low-degreeness of that,
# instead of proving the low-degreeness of P, B and D separately # instead of proving the low-degreeness of P, B and D separately
k1 = int.from_bytes(blake(p_mtree[1] + d_mtree[1] + b_mtree[1] + b'\x01'), 'big') k1 = int.from_bytes(blake(mtree[1] + b'\x01'), 'big')
k2 = int.from_bytes(blake(p_mtree[1] + d_mtree[1] + b_mtree[1] + b'\x02'), 'big') k2 = int.from_bytes(blake(mtree[1] + b'\x02'), 'big')
k3 = int.from_bytes(blake(p_mtree[1] + d_mtree[1] + b_mtree[1] + b'\x03'), 'big') k3 = int.from_bytes(blake(mtree[1] + b'\x03'), 'big')
k4 = int.from_bytes(blake(p_mtree[1] + d_mtree[1] + b_mtree[1] + b'\x04'), 'big') k4 = int.from_bytes(blake(mtree[1] + b'\x04'), 'big')
# Compute the linear combination. We don't even both calculating it in # Compute the linear combination. We don't even both calculating it in
# coefficient form; we just compute the evaluations # coefficient form; we just compute the evaluations
@ -125,18 +126,14 @@ def mk_mimc_proof(inp, steps, round_constants):
positions = get_pseudorandom_indices(l_mtree[1], precision, samples, positions = get_pseudorandom_indices(l_mtree[1], precision, samples,
exclude_multiples_of=extension_factor) exclude_multiples_of=extension_factor)
for pos in positions: for pos in positions:
branches.append(mk_branch(p_mtree, pos)) branches.append(mk_branch(mtree, pos))
branches.append(mk_branch(p_mtree, (pos + skips) % precision)) branches.append(mk_branch(mtree, (pos + skips) % precision))
branches.append(mk_branch(d_mtree, pos))
branches.append(mk_branch(b_mtree, pos))
branches.append(mk_branch(l_mtree, pos)) branches.append(mk_branch(l_mtree, pos))
print('Computed %d spot checks' % samples) print('Computed %d spot checks' % samples)
# Return the Merkle roots of P and D, the spot check Merkle proofs, # Return the Merkle roots of P and D, the spot check Merkle proofs,
# and low-degree proofs of P and D # and low-degree proofs of P and D
o = [p_mtree[1], o = [mtree[1],
d_mtree[1],
b_mtree[1],
l_mtree[1], l_mtree[1],
branches, branches,
prove_low_degree(l_evaluations, G2, steps * 2, modulus, exclude_multiples_of=extension_factor)] prove_low_degree(l_evaluations, G2, steps * 2, modulus, exclude_multiples_of=extension_factor)]
@ -145,7 +142,7 @@ def mk_mimc_proof(inp, steps, round_constants):
# Verifies a STARK # Verifies a STARK
def verify_mimc_proof(inp, steps, round_constants, output, proof): def verify_mimc_proof(inp, steps, round_constants, output, proof):
p_root, d_root, b_root, l_root, branches, fri_proof = proof m_root, l_root, branches, fri_proof = proof
start_time = time.time() start_time = time.time()
assert steps <= 2**32 // extension_factor assert steps <= 2**32 // extension_factor
assert is_a_power_of_2(steps) and is_a_power_of_2(len(round_constants)) assert is_a_power_of_2(steps) and is_a_power_of_2(len(round_constants))
@ -165,10 +162,10 @@ def verify_mimc_proof(inp, steps, round_constants, output, proof):
assert verify_low_degree_proof(l_root, G2, fri_proof, steps * 2, modulus, exclude_multiples_of=extension_factor) assert verify_low_degree_proof(l_root, G2, fri_proof, steps * 2, modulus, exclude_multiples_of=extension_factor)
# Performs the spot checks # Performs the spot checks
k1 = int.from_bytes(blake(p_root + d_root + b_root + b'\x01'), 'big') k1 = int.from_bytes(blake(m_root + b'\x01'), 'big')
k2 = int.from_bytes(blake(p_root + d_root + b_root + b'\x02'), 'big') k2 = int.from_bytes(blake(m_root + b'\x02'), 'big')
k3 = int.from_bytes(blake(p_root + d_root + b_root + b'\x03'), 'big') k3 = int.from_bytes(blake(m_root + b'\x03'), 'big')
k4 = int.from_bytes(blake(p_root + d_root + b_root + b'\x04'), 'big') k4 = int.from_bytes(blake(m_root + b'\x04'), 'big')
samples = spot_check_security_factor samples = spot_check_security_factor
positions = get_pseudorandom_indices(l_root, precision, samples, positions = get_pseudorandom_indices(l_root, precision, samples,
exclude_multiples_of=extension_factor) exclude_multiples_of=extension_factor)
@ -176,11 +173,14 @@ def verify_mimc_proof(inp, steps, round_constants, output, proof):
for i, pos in enumerate(positions): for i, pos in enumerate(positions):
x = f.exp(G2, pos) x = f.exp(G2, pos)
x_to_the_steps = f.exp(x, steps) x_to_the_steps = f.exp(x, steps)
p_of_x = verify_branch(p_root, pos, branches[i*5]) mbranch1 = verify_branch(m_root, pos, branches[i*3])
p_of_g1x = verify_branch(p_root, (pos+skips)%precision, branches[i*5 + 1]) mbranch2 = verify_branch(m_root, (pos+skips)%precision, branches[i*3+1])
d_of_x = verify_branch(d_root, pos, branches[i*5 + 2]) l_of_x = verify_branch(l_root, pos, branches[i*3 + 2], output_as_int=True)
b_of_x = verify_branch(b_root, pos, branches[i*5 + 3])
l_of_x = verify_branch(l_root, pos, branches[i*5 + 4]) p_of_x = int.from_bytes(mbranch1[:32], 'big')
p_of_g1x = int.from_bytes(mbranch2[:32], 'big')
d_of_x = int.from_bytes(mbranch1[32:64], 'big')
b_of_x = int.from_bytes(mbranch1[64:], 'big')
zvalue = f.div(f.exp(x, steps) - 1, zvalue = f.div(f.exp(x, steps) - 1,
x - last_step_position) x - last_step_position)

View File

@ -5,9 +5,9 @@ from merkle_tree import merkelize, mk_branch, verify_branch
from fri import prove_low_degree, verify_low_degree_proof from fri import prove_low_degree, verify_low_degree_proof
def test_merkletree(): def test_merkletree():
t = merkelize(range(128)) t = merkelize([x.to_bytes(32, 'big') for x in range(128)])
b = mk_branch(t, 59) b = mk_branch(t, 59)
assert verify_branch(t[1], 59, b) == 59 assert verify_branch(t[1], 59, b, output_as_int=True) == 59
print('Merkle tree works') print('Merkle tree works')
def test_fri(): def test_fri():
@ -41,7 +41,7 @@ def test_stark():
#constants = [random.randrange(modulus) for i in range(64)] #constants = [random.randrange(modulus) for i in range(64)]
constants = [(i**7) ^ 42 for i in range(64)] constants = [(i**7) ^ 42 for i in range(64)]
proof = mk_mimc_proof(INPUT, 2**LOGSTEPS, constants) proof = mk_mimc_proof(INPUT, 2**LOGSTEPS, constants)
p_root, d_root, b_root, l_root, branches, fri_proof = proof m_root, l_root, branches, fri_proof = proof
L1 = bin_length(compress_branches(branches)) L1 = bin_length(compress_branches(branches))
L2 = bin_length(compress_fri(fri_proof)) L2 = bin_length(compress_fri(fri_proof))
print("Approx proof length: %d (branches), %d (FRI proof), %d (total)" % (L1, L2, L1 + L2)) print("Approx proof length: %d (branches), %d (FRI proof), %d (total)" % (L1, L2, L1 + L2))