From 815080552e93d6485436450b5b578756ec01202a Mon Sep 17 00:00:00 2001 From: Qi Zhou Date: Wed, 18 Jan 2023 14:44:17 -0800 Subject: [PATCH 1/2] fix fri test with permuted merkle tree --- mimc_stark/test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mimc_stark/test.py b/mimc_stark/test.py index 557b32cb..fb944ee7 100644 --- a/mimc_stark/test.py +++ b/mimc_stark/test.py @@ -1,6 +1,7 @@ from fft import fft from mimc_stark import mk_mimc_proof, modulus, mimc, verify_mimc_proof from merkle_tree import merkelize, mk_branch, verify_branch, bin_length +from permuted_tree import merkelize as pmerkelize from fri import prove_low_degree, verify_low_degree_proof def test_merkletree(): @@ -19,17 +20,17 @@ def test_fri(): evaluations = fft(poly, modulus, root_of_unity) proof = prove_low_degree(evaluations, root_of_unity, 4096, modulus) print("Approx proof length: %d" % fri_proof_bin_length(proof)) - assert verify_low_degree_proof(merkelize(evaluations)[1], root_of_unity, proof, 4096, modulus) + assert verify_low_degree_proof(pmerkelize(evaluations)[1], root_of_unity, proof, 4096, modulus) try: fakedata = [x if pow(3, i, 4096) > 400 else 39 for x, i in enumerate(evaluations)] proof2 = prove_low_degree(fakedata, root_of_unity, 4096, modulus) - assert verify_low_degree_proof(merkelize(fakedata)[1], root_of_unity, proof, 4096, modulus) + assert verify_low_degree_proof(pmerkelize(fakedata)[1], root_of_unity, proof, 4096, modulus) raise Exception("Fake data passed FRI") except: pass try: - assert verify_low_degree_proof(merkelize(evaluations)[1], root_of_unity, proof, 2048, modulus) + assert verify_low_degree_proof(pmerkelize(evaluations)[1], root_of_unity, proof, 2048, modulus) raise Exception("Fake data passed FRI") except: pass @@ -50,4 +51,5 @@ def test_stark(): assert verify_mimc_proof(3, 2**LOGSTEPS, constants, mimc(3, 2**LOGSTEPS, constants), proof) if __name__ == '__main__': + test_fri() test_stark() From cc05e512f4eeaa98d5edbbbb62d11510d8150b07 Mon Sep 17 00:00:00 2001 From: Qi Zhou Date: Thu, 19 Jan 2023 11:07:34 -0800 Subject: [PATCH 2/2] FRI uses barycentric formula to evaluate poly --- mimc_stark/fri.py | 17 ++++++++++++----- mimc_stark/poly_utils.py | 32 ++++++++++++++++++++++++++++++++ mimc_stark/test.py | 5 ++++- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/mimc_stark/fri.py b/mimc_stark/fri.py index ed76ad13..7f598090 100644 --- a/mimc_stark/fri.py +++ b/mimc_stark/fri.py @@ -35,11 +35,18 @@ def prove_low_degree(values, root_of_unity, maxdeg_plus_1, modulus, exclude_mult # We calculate the column by Lagrange-interpolating each row, and not # directly from the polynomial, as this is more efficient quarter_len = len(xs)//4 - x_polys = f.multi_interp_4( - [[xs[i+quarter_len*j] for j in range(4)] for i in range(quarter_len)], - [[values[i+quarter_len*j] for j in range(4)] for i in range(quarter_len)] - ) - column = [f.eval_quartic(p, special_x) for p in x_polys] + # Using Barycentric forumla to evaluate the polynomial without interpolation + # column = [f.eval_barycentric(special_x, + # [xs[i+quarter_len*j] for j in range(4)], + # [values[i+quarter_len*j] for j in range(4)]) for i in range(quarter_len)] + column = f.eval_barycentric_all(special_x, xs, values, 4) + # Evaluate the polynomial using Lagrange interpolation + # x_polys = f.multi_interp_4( + # [[xs[i+quarter_len*j] for j in range(4)] for i in range(quarter_len)], + # [[values[i+quarter_len*j] for j in range(4)] for i in range(quarter_len)] + # ) + # column1 = [f.eval_quartic(p, special_x) for p in x_polys] + # assert column == column1 m2 = merkelize(column) # Pseudo-randomly select y indices to sample diff --git a/mimc_stark/poly_utils.py b/mimc_stark/poly_utils.py index c29d1b51..d4260200 100644 --- a/mimc_stark/poly_utils.py +++ b/mimc_stark/poly_utils.py @@ -17,6 +17,38 @@ def mul(self, x, y): def exp(self, x, p): return pow(x, p, self.modulus) + # evaluate the polynomal in the evaluation form in a coset + # xs[0] must the shifting parameter h + # formula is (x^m - h^m) / (m h^m) * sum(ys[i] * xs[i] / (x - xs[i])) + def eval_barycentric(self, x, xs, ys): + m = len(xs) # coset order + xm = self.exp(x, m) + hm = self.exp(xs[0], m) + s = 0 + for i in range(len(xs)): + s = self.add(s, self.div(self.mul(xs[i], ys[i]), self.sub(x, xs[i]))) + return self.mul(s, self.div(self.sub(xm, hm), self.mul(m, hm))) + + # evaluate the polynomal in the evaluate form for all cosets + # with some optimization on inversion + def eval_barycentric_all(self, x, xs, ys, m): + ncosets = len(xs) // m + # evaluate all inversions in batch + toinv = [x - xx for xx in xs] + toinv.append(m) + inved = self.multi_inv(toinv) + invm = inved[-1] + xm = self.exp(x, m) + ss = [] + modulus = self.modulus + for i in range(ncosets): + s = 0 + for j in range(m): + idx = j*ncosets+i + s = (s + xs[idx] * ys[idx] * inved[idx]) % modulus + ss.append(s * (xm - xs[i * m]) * invm * xs[-i * m] % modulus) + return ss + # Modular inverse using the extended Euclidean algorithm def inv(self, a): if a == 0: diff --git a/mimc_stark/test.py b/mimc_stark/test.py index fb944ee7..15245ee0 100644 --- a/mimc_stark/test.py +++ b/mimc_stark/test.py @@ -1,3 +1,5 @@ +import time + from fft import fft from mimc_stark import mk_mimc_proof, modulus, mimc, verify_mimc_proof from merkle_tree import merkelize, mk_branch, verify_branch, bin_length @@ -18,8 +20,9 @@ def test_fri(): poly = list(range(4096)) root_of_unity = pow(7, (modulus-1)//16384, modulus) evaluations = fft(poly, modulus, root_of_unity) + start_time = time.time() proof = prove_low_degree(evaluations, root_of_unity, 4096, modulus) - print("Approx proof length: %d" % fri_proof_bin_length(proof)) + print("Approx proof length: %d, used time: %.4f" % (fri_proof_bin_length(proof), (time.time() - start_time))) assert verify_low_degree_proof(pmerkelize(evaluations)[1], root_of_unity, proof, 4096, modulus) try: