def verify_eval(self, c, i, phi_at_i, witness): t = witness[-1][0] - 1 y_vec = [ZR(i)**j for j in range(t + 1)] if len(witness) == 6: [S, T, D, mu, t_hat, iproof] = witness challenge = ZR.hash(pickle.dumps([self.gs, self.h, self.u, S, T])) else: [roothash, branch, S, T, D, mu, t_hat, iproof] = witness if not MerkleTree.verify_membership(pickle.dumps(T), branch, roothash): return False challenge = ZR.hash( pickle.dumps([roothash, self.gs, self.h, self.u, S])) ret = self.gs[0]**t_hat == self.gs[0]**phi_at_i * T**challenge ret &= D * self.h**mu == S**challenge * c if len(iproof[-1]) > 3: ret &= verify_batch_inner_product_one_known(D, t_hat, y_vec, iproof, crs=[self.gs, self.u]) else: ret &= verify_inner_product_one_known(D, t_hat, y_vec, iproof, crs=[self.gs, self.u]) return ret
def test_batch_inner_product_proof_one_known(): n = 13 a = [ZR.random() for i in range(n)] bs = [[ZR.random() for j in range(n)] for i in range(3 * n)] comm, iprods, proofs = prove_batch_inner_product_one_known(a, bs) assert verify_batch_inner_product_one_known(comm, iprods[2], bs[2], proofs[2]) comm, iprods, badproofs = prove_batch_inner_product_one_known( a, bs, comm=G1.rand()) assert not verify_batch_inner_product_one_known(comm, iprods[2], bs[2], badproofs[2])
def poly_lagrange_at_x(s, j, x): s = sorted(s) assert j in s l1 = [x - jj for jj in s if jj != j] l2 = [j - jj for jj in s if jj != j] (num, den) = (ZR(1), ZR(1)) for item in l1: num *= item for item in l2: den *= item return num / den
def test_inner_product_proof_one_known(): n = 15 a = [ZR.random() for i in range(n)] b = [ZR.random() for i in range(n)] iprod = ZR(0) for i in range(n): iprod += a[i] * b[i] comm, iprod, proof = prove_inner_product_one_known(a, b) assert verify_inner_product_one_known(comm, iprod, b, proof) comm, iprod, badproof = prove_inner_product_one_known(a, b, comm=G1.rand()) assert not verify_inner_product_one_known(comm, iprod, b, badproof)
def get_all_roots_of_unity(n): #get smallest power of two greater than or equal to N N = 2**ceil(log(n, 2)) #hardcoded value for bls12-381. modulus = 2^s * t + 1 s = 32 omega = ZR.root_of_unity() for i in range(s, ceil(log(n, 2)), -1): omega *= ZR.root_of_unity() omegas = [ZR(1), omega] for i in range(2, n): omegas.append(omegas[i - 1] * omega) return omegas
def gen_crs(degree_max=32, alpha=None): if alpha is None: alpha = ZR.rand() g1g = G1.hash(b"honeybadgerg1g") g2g = G2.hash(b"honeybadgerg2g") exp = ZR(1) g1s = [g1g] g2s = [g2g] for i in range(degree_max): exp *= alpha g1s.append(g1g**exp) g2s.append(g2g**exp) return [g1s, g2s]
def test_inner_product_proof(): n = 10 a = [ZR.random() for i in range(n)] b = [ZR.random() for i in range(n)] iprod = ZR(0) for i in range(n): iprod += a[i] * b[i] comm, iprod, proof = prove_inner_product(a, b) assert verify_inner_product(comm, iprod, proof) comm, iprod, proof2 = prove_inner_product(a, b, comm=comm) assert verify_inner_product(comm, iprod, proof2) comm, iprod, badproof = prove_inner_product(a, b, comm=G1.rand()) assert not verify_inner_product(comm, iprod, badproof)
def double_batch_create_witness(self, phis, r, n=None): t = len(phis[0].coeffs) - 1 numpolys = len(phis) if n is None: n = 3 * t + 1 numverifiers = n if len(self.y_vecs) < numverifiers: i = len(self.y_vecs) while i < numverifiers: self.y_vecs.append([ZR(i + 1)**j for j in range(t + 1)]) i += 1 # length t s_vec = [ZR.random() for _ in range(t + 1)] sy_prods = [ZR(0) for _ in range(numverifiers)] S = G1.identity() T_vec = [None] * numverifiers witnesses = [[] for _ in range(numverifiers)] for i in range(t + 1): S *= self.gs[i].pow(s_vec[i]) for j in range(numverifiers): for i in range(t + 1): sy_prods[j] += s_vec[i] * self.y_vecs[j][i] T_vec[j] = self.gs[0].pow(sy_prods[j]) rho = ZR.random() S *= self.h**rho # Fiat Shamir tree = MerkleTree() for j in range(numverifiers): tree.append(pickle.dumps(T_vec[j])) roothash = tree.get_root_hash() for j in range(numverifiers): branch = tree.get_branch(j) witnesses[j].append(roothash) witnesses[j].append(branch) challenge = ZR.hash( pickle.dumps([roothash, self.gs, self.h, self.u, S])) d_vecs = [] for i in range(len(phis)): d_vecs.append([ phis[i].coeffs[j] + s_vec[j] * challenge for j in range(t + 1) ]) Ds = [G1.identity() for _ in range(len(phis))] _ = [[ Ds[i].__imul__(self.gs[j].pow(d_vecs[i][j])) for j in range(t + 1) ] for i in range(len(phis))] mu = r + rho * challenge comms, t_hats, iproofs = prove_double_batch_inner_product_one_known_but_differenter( d_vecs, self.y_vecs, crs=[self.gs, self.u]) for j in range(numverifiers): witnesses[j] += [t, S, T_vec[j], Ds, mu, t_hats[j], iproofs[j]] return witnesses
def gen_accumulator_tree(n): omegas = get_all_roots_of_unity(n) #tree is a list of lists, where tree[i][j] is the j'th leaf in the i'th row (bottom row is row 0) numlevels = ceil(log(n, 2)) + 1 tree = [2**i * [None] for i in reversed(range(numlevels))] poly = polynomials_over(ZR) for i in range(len(omegas)): tree[0][bit_reverse(i, numlevels - 1)] = poly([ZR(-1) * omegas[i], ZR(1)]) for k in range(1, numlevels): for i in range(len(tree[k])): tree[k][i] = tree[k - 1][2 * i] * tree[k - 1][2 * i + 1] return tree
async def test_HbACSS1Recoverer(test_router): t = 2 n = 3 * t + 1 poly = polynomials_over(ZR) secrets = [ZR.random() for i in range(t + 1)] secretpolys = [poly.random(t, secrets[i]) for i in range(t + 1)] crs = gen_pc_const_dl_crs(t) pc = PolyCommitConstDL(crs) commits = [pc.commit(phi) for phi in secretpolys] #witnesses[i][j] should give the proof for party i's share of polynomial number j witnesses = [[pc.create_witness(phi, i) for phi in secretpolys] for i in range(1, n + 1)] shares = [[phi(i) for phi in secretpolys] for i in range(1, n + 1)] sends, recvs, _ = test_router(n) loop = asyncio.get_event_loop() players = [ HbACSS1Recoverer(crs, n, t, i, sends[i], recvs[i], shares[i], True, commits, witnesses[i], pc=pc) for i in range(n) ] playertasks = [loop.create_task(player._run()) for player in players] for task in playertasks: task.add_done_callback(print_exception_callback) #loop.run_forever() await asyncio.gather(*playertasks)
def test_pc_log_batch(t): pc = PolyCommitLog() phi = polynomials_over(ZR).random(t) r = ZR.random() c = pc.commit(phi, r) witnesses = pc.batch_create_witness(phi, r) assert pc.verify_eval(c, 4, phi(4), witnesses[3])
def recursive_verify(g_vec, b_vec, u, proofs, n, Ps, transcript): if n == 1: ret = True for i in range(len(proofs)): a, b = proofs[i][0][0], b_vec[0] ret &= Ps[i] == g_vec[0].pow(a) * u.pow(a * b) return ret Ls = [] Rs = [] branches = [] last_roothash = None if n % 2 == 1: for i in range(len(proofs)): [na, roothash, branch, L, R] = proofs[i][-1] Ps[i] *= g_vec[-1].pow(na) * u.pow(na * b_vec[-1]) Ls.append(L) Rs.append(R) branches.append(branch) if i != 0: assert last_roothash == roothash else: last_roothash = roothash else: for i in range(len(proofs)): [roothash, branch, L, R] = proofs[i][-1] Ls.append(L) Rs.append(R) branches.append(branch) if i != 0: assert last_roothash == roothash else: last_roothash = roothash for i in range(len(proofs)): leafi = hash_list_to_bytes( [hashzrlist(b_vec), hashg1list([Ps[i], Ls[i], Rs[i]])]) if not MerkleTree.verify_membership(leafi, branches[i], last_roothash): return False transcript += pickle.dumps([hashg1list(g_vec), last_roothash]) x = ZR.hash(transcript) xi = x**-1 x2 = x * x xi2 = xi * xi n_p = n // 2 g_vec_p = [] b_vec_p = [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i].pow(xi) * g_vec[n_p:][i].pow(x)) b_vec_p.append(b_vec[:n_p][i] * xi + b_vec[n_p:][i] * x) Ps_p = [] for i in range(len(proofs)): Ps_p.append(Ls[i]**(x2) * Ps[i] * Rs[i]**(xi2)) proofs_p = [] for i in range(len(proofs)): proofs_p.append(proofs[i][:-1]) return recursive_verify(g_vec_p, b_vec_p, u, proofs_p, n_p, Ps_p, transcript)
def test_inner_product_interactive_proof(): loop = asyncio.get_event_loop() pr_queue = asyncio.Queue(loop=loop) vr_queue = asyncio.Queue(loop=loop) prover = inner_product_prover(vr_queue, pr_queue) verifier = inner_product_verifier(pr_queue, vr_queue) n = 10 a = [ZR.random() for i in range(n)] b = [ZR.random() for i in range(n)] iprod = ZR(0) for i in range(n): iprod += a[i] * b[i] (comm1, iprod1, g_vec1, h_vec1, u1, a_vec1, b_vec1, n1, P1) = prover.set_up_params(a, b) (g_vec2, h_vec2, u2, n2, P2) = verifier.set_up_params(n1, P1) prover_coro = prover.recursive_prove(g_vec1, h_vec1, u1, a_vec1, b_vec1, n1, P1) verifier_coro = verifier.recursive_verify(g_vec2, h_vec2, u2, n2, P2) _, ret = loop.run_until_complete(asyncio.gather(prover_coro, verifier_coro)) assert ret == True (_, _, g_vec1, h_vec1, u1, a_vec1, b_vec1, n1, P1) = prover.set_up_params(a, b, comm=comm1) (g_vec2, h_vec2, u2, n2, P2) = verifier.set_up_params(n1, P1) prover_coro = prover.recursive_prove(g_vec1, h_vec1, u1, a_vec1, b_vec1, n1, P1) verifier_coro = verifier.recursive_verify(g_vec2, h_vec2, u2, n2, P2) _, ret = loop.run_until_complete(asyncio.gather(prover_coro, verifier_coro)) assert ret == True (comm1, iprod1, g_vec1, h_vec1, u1, a_vec1, b_vec1, n1, P1) = prover.set_up_params(a, b, comm=G1.rand()) (g_vec2, h_vec2, u2, n2, P2) = verifier.set_up_params(n1, P1) prover_coro = prover.recursive_prove(g_vec1, h_vec1, u1, a_vec1, b_vec1, n1, P1) verifier_coro = verifier.recursive_verify(g_vec2, h_vec2, u2, n2, P2) _, ret = loop.run_until_complete(asyncio.gather(prover_coro, verifier_coro)) assert ret == False loop.close()
def test_hbacss2_size_benchmark_batch_creation(benchmark, t): pc = PolyCommitLog(degree_max=t) pc.preprocess_prover(16) r = ZR.random() phis = [] for _ in range(t): phi_curr = polynomials_over(ZR).random(t) phis.append(phi_curr) benchmark(pc.double_batch_create_witness, phis, r)
def batch_create_witness(self, phi, r, n=None): t = len(phi.coeffs) - 1 if n is None: n = 3 * t + 1 if len(self.y_vecs) < n: i = len(self.y_vecs) while i < n: self.y_vecs.append([ZR(i + 1)**j for j in range(t + 1)]) i += 1 s_vec = [ZR.random() for _ in range(t + 1)] sy_prods = [ZR(0) for _ in range(n)] S = G1.identity() T_vec = [None] * n witnesses = [[] for _ in range(n)] for i in range(t + 1): S *= self.gs[i]**s_vec[i] for j in range(n): for i in range(t + 1): sy_prods[j] += s_vec[i] * self.y_vecs[j][i] T_vec[j] = self.gs[0]**sy_prods[j] rho = ZR.random() S *= self.h**rho # Fiat Shamir tree = MerkleTree() for j in range(n): tree.append(pickle.dumps(T_vec[j])) roothash = tree.get_root_hash() for j in range(n): branch = tree.get_branch(j) witnesses[j].append(roothash) witnesses[j].append(branch) challenge = ZR.hash( pickle.dumps([roothash, self.gs, self.h, self.u, S])) d_vec = [phi.coeffs[j] + s_vec[j] * challenge for j in range(t + 1)] D = G1.identity() for j in range(t + 1): D *= self.gs[j]**d_vec[j] mu = r + rho * challenge comm, t_hats, iproofs = prove_batch_inner_product_one_known( d_vec, self.y_vecs, crs=[self.gs, self.u]) for j in range(len(witnesses)): witnesses[j] += [S, T_vec[j], D, mu, t_hats[j], iproofs[j]] return witnesses
def recursive_proof(g_vec, h_vec, u, a_vec, b_vec, n, P, transcript): if n == 1: proof = [] proof.append([a_vec[0], b_vec[0]]) return proof proofstep = [] if n % 2 == 1: na, nb = a_vec[-1] * -1, b_vec[-1] * -1 P *= g_vec[-1]**(na) * h_vec[-1]**(nb) * u**(-na * nb) proofstep.append(na) proofstep.append(nb) n_p = n // 2 cl = ZR(0) cr = ZR(0) L = G1.identity() R = G1.identity() for i in range(n_p): cl += a_vec[:n_p][i] * b_vec[n_p:][i] cr += a_vec[n_p:][i] * b_vec[:n_p][i] L *= g_vec[n_p:][i]**a_vec[:n_p][i] * h_vec[:n_p][i]**b_vec[n_p:][i] R *= g_vec[:n_p][i]**a_vec[n_p:][i] * h_vec[n_p:][i]**b_vec[:n_p][i] L *= u**cl R *= u**cr # Fiat Shamir L, R, state... #transcript += pickle.dumps([g_vec, h_vec, u, P, L, R]) transcript += pickle.dumps(hashg1list(g_vec + h_vec + [u, P, L, R])) x = ZR.hash(transcript) xi = x**-1 # this part must come after the challenge is generated, which must # come after L and R are calculated. Don't try to condense the loops g_vec_p, h_vec_p, a_vec_p, b_vec_p = [], [], [], [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i]**xi * g_vec[n_p:][i]**x) h_vec_p.append(h_vec[:n_p][i]**x * h_vec[n_p:][i]**xi) a_vec_p.append(a_vec[:n_p][i] * x + a_vec[n_p:][i] * xi) b_vec_p.append(b_vec[:n_p][i] * xi + b_vec[n_p:][i] * x) P_p = L**(x * x) * P * R**(xi * xi) proof = recursive_proof(g_vec_p, h_vec_p, u, a_vec_p, b_vec_p, n_p, P_p, transcript) proofstep.append(L) proofstep.append(R) proof.append(proofstep) return proof
def batch_verify_eval(self, cs, i, phis_at_i, witness, degree=None): [roothash, branch, t, S, T, Ds, mu, t_hats, proof] = witness if degree is not None: t = degree iproof, treeparts = proof if not MerkleTree.verify_membership(pickle.dumps(T), branch, roothash): return False # TODO: Should include cs challenge = ZR.hash( pickle.dumps([roothash, self.gs, self.h, self.u, S])) y_vec = [ZR(i)**j for j in range(t + 1)] ret = True for j in range(len(Ds)): ret &= self.gs[0]**t_hats[ j] == self.gs[0]**phis_at_i[j] * T**challenge ret &= Ds[j] * self.h**mu == S**challenge * cs[j] ret &= verify_double_batch_inner_product_one_known_but_differenter( Ds, t_hats, y_vec, iproof, treeparts, crs=[self.gs, self.u]) return ret
async def recursive_prove(self, g_vec, h_vec, u, a_vec, b_vec, n, P): if n == 1: await self.send_queue.put([a_vec[0], b_vec[0]]) return proofStep = [] if n % 2 == 1: na, nb = a_vec[-1] * -1, b_vec[-1] * -1 P *= g_vec[-1]**(na) * h_vec[-1]**(nb) * u**(-na * nb) proofStep.append(na) proofStep.append(nb) n_p = n // 2 cl = ZR(0) cr = ZR(0) L = G1.identity() R = G1.identity() for i in range(n_p): cl += a_vec[:n_p][i] * b_vec[n_p:][i] cr += a_vec[n_p:][i] * b_vec[:n_p][i] L *= g_vec[n_p:][i]**a_vec[:n_p][i] * h_vec[:n_p][i]**b_vec[n_p:][i] R *= g_vec[:n_p][i]**a_vec[n_p:][i] * h_vec[n_p:][i]**b_vec[:n_p][i] L *= u**cl R *= u**cr proofStep.append(L) proofStep.append(R) await self.send_queue.put(proofStep) x = await self.receive_queue.get() xi = x**-1 g_vec_p, h_vec_p, a_vec_p, b_vec_p = [], [], [], [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i]**xi * g_vec[n_p:][i]**x) h_vec_p.append(h_vec[:n_p][i]**x * h_vec[n_p:][i]**xi) a_vec_p.append(a_vec[:n_p][i] * x + a_vec[n_p:][i] * xi) b_vec_p.append(b_vec[:n_p][i] * xi + b_vec[n_p:][i] * x) P_p = L**(x * x) * P * R**(xi * xi) await self.recursive_prove(g_vec_p, h_vec_p, u, a_vec_p, b_vec_p, n_p, P_p) return
def test_pc_log(t): pc = PolyCommitLog() phi = polynomials_over(ZR).random(t) # ToDo: see if other polycommits return the commit randomness # rather than expecting it as arg r = ZR.random() c = pc.commit(phi, r) witness = pc.create_witness(phi, r, 3) assert pc.verify_eval(c, 3, phi(3), witness) assert not pc.verify_eval(c, 4, phi(3), witness) assert not pc.verify_eval(G1.rand(), 3, phi(3), witness)
def test_double_batch_pc_log_batch_prove_and_verify(t): pc = PolyCommitLog() phi1 = polynomials_over(ZR).random(t) phi2 = polynomials_over(ZR).random(t) phi3 = polynomials_over(ZR).random(t) r = ZR.random() c1 = pc.commit(phi1, r) c2 = pc.commit(phi2, r) witnesses = pc.double_batch_create_witness([phi1, phi2], r) assert pc.batch_verify_eval([c1,c2], 4, [phi1(4), phi2(4)], witnesses[3]) assert not pc.batch_verify_eval([c1,c2], 3, [phi1(4), phi2(4)], witnesses[3]) assert not pc.batch_verify_eval([c1,c2], 4, [phi1(4), phi2(4)], witnesses[2]) assert not pc.batch_verify_eval([c1,c1], 4, [phi1(4), phi2(4)], witnesses[3])
def create_witness(self, phi, r, i): t = len(phi.coeffs) - 1 y_vec = [ZR(i)**j for j in range(t + 1)] s_vec = [ZR.random() for _ in range(t + 1)] sy_prod = ZR(0) S = G1.identity() for j in range(t + 1): S *= self.gs[j]**s_vec[j] sy_prod += s_vec[j] * y_vec[j] T = self.gs[0]**sy_prod rho = ZR.random() S *= self.h**rho # Fiat Shamir challenge = ZR.hash(pickle.dumps([self.gs, self.h, self.u, S, T])) d_vec = [phi.coeffs[j] + s_vec[j] * challenge for j in range(t + 1)] D = G1.identity() for j in range(t + 1): D *= self.gs[j]**d_vec[j] mu = r + rho * challenge comm, t_hat, iproof = prove_inner_product_one_known( d_vec, y_vec, crs=[self.gs, self.u]) return [S, T, D, mu, t_hat, iproof]
def test_double_batch_pc_log_batch_differing_degrees(t): pc = PolyCommitLog() n = 2*t+1 phi1 = polynomials_over(ZR).random(t) phi2 = polynomials_over(ZR).random(t) r = ZR.random() c1 = pc.commit(phi1, r) c2 = pc.commit(phi2, r) witnesses = pc.double_batch_create_witness([phi1, phi2], r, n=n) assert pc.batch_verify_eval([c1,c2], 4, [phi1(4), phi2(4)], witnesses[3]) assert pc.batch_verify_eval([c1,c2], 4, [phi1(4), phi2(4)], witnesses[3], degree=t) assert not pc.batch_verify_eval([c1,c2], 4, [phi1(4), phi2(4)], witnesses[3], degree=t+1) assert not pc.batch_verify_eval([c1,c2], 4, [phi1(4), phi2(4)], witnesses[3], degree=t-1)
def test_hbacss2_size_benchmark_batch_verify(benchmark, t): pc = PolyCommitLog(degree_max=t) pc.preprocess_verifier(16) phis = [] r = ZR.random() cs = [] for _ in range(t): phi_curr = polynomials_over(ZR).random(t) phis.append(phi_curr) c_curr = pc.commit(phi_curr, r) cs.append(c_curr) witnesses = pc.double_batch_create_witness(phis, r) i = 4 phis_at_4 = [] for j in range(len(phis)): phis_at_4.append(phis[j](i)) benchmark(pc.batch_verify_eval, cs, i, phis_at_4, witnesses[i - 1])
def gen_pc_const_dl_crs(t, alpha=None, g=None, ghat=None, ZR=ZR, G1=G1, G2=G2): nonetype = type(None) assert type(t) is int assert type(alpha) in (ZR, int, nonetype) assert type(g) in (G1, nonetype) assert type(ghat) in (G2, nonetype) if alpha is None: alpha = ZR.random() if g is None: g = G1.rand() if ghat is None: ghat = G2.rand() (gs, ghats) = ([], []) for i in range(t + 1): gs.append(g**(alpha**i)) for i in range(2): ghats.append(ghat**(alpha**i)) crs = [gs, ghats] return crs
async def recursive_verify(self, g_vec, h_vec, u, n, P): if n == 1: [a, b] = await self.receive_queue.get() return P == g_vec[0]**a * h_vec[0]**b * u**(a * b) if n % 2 == 1: [na, nb, L, R] = await self.receive_queue.get() P *= g_vec[-1]**(na) * h_vec[-1]**(nb) * u**(-na * nb) else: [L, R] = await self.receive_queue.get() x = ZR.random() await self.send_queue.put(x) xi = x**-1 n_p = n // 2 g_vec_p = [] h_vec_p = [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i]**xi * g_vec[n_p:][i]**x) h_vec_p.append(h_vec[:n_p][i]**x * h_vec[n_p:][i]**xi) P_p = L**(x * x) * P * R**(xi * xi) ret = await self.recursive_verify(g_vec_p, h_vec_p, u, n_p, P_p) return ret
def set_up_params(self, a_vec, b_vec, comm=None, crs=None): n = len(a_vec) assert len(b_vec) == n if crs is None: g_vec = G1.hash_many(b"honeybadgerg", n) h_vec = G1.hash_many(b"honeybadgerh", n) u = G1.hash(b"honeybadgeru") else: [g_vec, h_vec, u] = crs g_vec = g_vec[:n] h_vec = h_vec[:n] if comm is not None: P = comm * G1.identity() else: comm = G1.identity() for i in range(n): comm *= g_vec[i]**a_vec[i] * h_vec[i]**b_vec[i] iprod = ZR(0) for i in range(n): iprod += a_vec[i] * b_vec[i] P = comm * u**iprod return (comm, iprod, g_vec, h_vec, u, a_vec, b_vec, n, P)
def recursive_verify(g_vec, b_vec, u, proof, n, P, transcript): if n == 1: a, b = proof[0][0], b_vec[0] return P == g_vec[0]**a * u**(a * b) if n % 2 == 1: [na, L, R] = proof[-1] P *= g_vec[-1]**(na) * u**(na * b_vec[-1]) else: [L, R] = proof[-1] #transcript += pickle.dumps([g_vec, u, P, L, R]) transcript += pickle.dumps(hashg1list(g_vec + [u, P, L, R])) x = ZR.hash(transcript) xi = x**-1 n_p = n // 2 g_vec_p = [] b_vec_p = [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i]**xi * g_vec[n_p:][i]**x) b_vec_p.append(b_vec[:n_p][i] * xi + b_vec[n_p:][i] * x) P_p = L**(x * x) * P * R**(xi * xi) return recursive_verify(g_vec_p, b_vec_p, u, proof[:-1], n_p, P_p, transcript)
def recursive_verify(g_vec, b_vec, u, proof, n, P, transcript): if n == 1: a, b = proof[0][0], b_vec[0] return P == g_vec[0]**a * u.pow(a * b) if n % 2 == 1: [na, roothash, branch, L, R] = proof[-1] P *= g_vec[-1]**(na) * u.pow(na * b_vec[-1]) else: [roothash, branch, L, R] = proof[-1] leaf = hash_list_to_bytes([hashzrlist(b_vec), hashg1list([P, L, R])]) if not MerkleTree.verify_membership(leaf, branch, roothash): return False transcript += pickle.dumps([hashg1list(g_vec), roothash]) x = ZR.hash(transcript) xi = x**-1 n_p = n // 2 g_vec_p = [] b_vec_p = [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i].pow(xi) * g_vec[n_p:][i].pow(x)) b_vec_p.append(b_vec[:n_p][i] * xi + b_vec[n_p:][i] * x) P_p = L**(x * x) * P * R**(xi * xi) return recursive_verify(g_vec_p, b_vec_p, u, proof[:-1], n_p, P_p, transcript)
def recursive_proofs(g_vec, a_vecs, b_vecs, u, n, P_vec, transcript): numverifiers = len(b_vecs) numpolys = len(a_vecs) numproofs = numverifiers * numpolys _ = [g.preprocess(5) for g in g_vec] if n == 1: treeparts = [[] for j in range(numverifiers)] proofs = [[[[a_vecs[i][0]]] for i in range(numpolys)] for _ in range(numverifiers)] return [proofs, treeparts] proofsteps = [[[] for _ in range(numpolys)] for _ in range(numverifiers)] nas = None if n % 2 == 1: for i in range(numpolys): na = a_vecs[i][-1] * -1 gtail = g_vec[-1].pow(na) for j in range(numverifiers): P_vec[j][i] *= gtail * u.pow(na * b_vecs[j][-1]) # proofsteps[j][i].append(na) nas = [a_vecs[i][-1] * -1 for i in range(numpolys)] proofsteps = [[[nas[i]] for i in range(numpolys)] for j in range(numverifiers)] n_p = n // 2 #cl_vec = [ [ 0 for _ in range(numpolys)] for _ in range(numverifiers)] #cr_vec = [ [ 0 for _ in range(numpolys)] for _ in range(numverifiers)] #L_vec = [ [ [] for _ in range(numpolys)] for _ in range(numverifiers)] #R_vec = [ [ [] for _ in range(numpolys)] for _ in range(numverifiers)] Las = [G1.identity() for _ in range(len(a_vecs))] Ras = [G1.identity() for _ in range(len(a_vecs))] for j in range(len(a_vecs)): for i in range(n_p): Las[j] *= g_vec[n_p:][i].pow(a_vecs[j][:n_p][i]) Ras[j] *= g_vec[:n_p][i].pow(a_vecs[j][n_p:][i]) #for i in range(numpolys): # for j in range(numverifiers): # cl_vec[j][i] = inner_product(a_vecs[i][:n_p], b_vecs[j][n_p:2*n_p]) # cr_vec[j][i] = inner_product(a_vecs[i][n_p:2*n_p], b_vecs[j][:n_p]) # L_vec[j][i] = Las[i] * (u.pow(cl_vec[j][i])) # R_vec[j][i] = Ras[i] * (u.pow(cr_vec[j][i])) cl_vec = [[ inner_product(a_vecs[i][:n_p], b_vecs[j][n_p:2 * n_p]) for i in range(numpolys) ] for j in range(numverifiers)] cr_vec = [[ inner_product(a_vecs[i][n_p:2 * n_p], b_vecs[j][:n_p]) for i in range(numpolys) ] for j in range(numverifiers)] L_vec = [[Las[i] * (u.pow(cl_vec[j][i])) for i in range(numpolys)] for j in range(numverifiers)] R_vec = [[Ras[i] * (u.pow(cr_vec[j][i])) for i in range(numpolys)] for j in range(numverifiers)] # Fiat Shamir # Make a merkle tree over everything that varies between verifiers # TODO: na should be in the transcript tree = MerkleTree() if nas is None: zr_hashes = [hashzrlist(b_vecs[i]) for i in range(len(b_vecs))] else: zr_hashes = [ hashzrlist(b_vecs[i] + nas) for i in range(len(b_vecs)) ] g1lists = [[] for j in range(numverifiers)] for j in range(numverifiers): #smash each list of lists into a single list (list() causes the map operation to execute) _ = list(map(g1lists[j].extend, [P_vec[j], L_vec[j], R_vec[j]])) leaves = [ pickle.dumps([zr_hashes[j], hashg1listbn(g1lists[j])]) for j in range(numverifiers) ] tree.append_many(leaves) roothash = tree.get_root_hash() treesteps = [[roothash, tree.get_branch(j)] for j in range(numverifiers)] transcript += pickle.dumps([hashg1list(g_vec), roothash]) x = ZR.hash(transcript) xi = x**-1 # this part must come after the challenge is generated, which must # come after L and R are calculated. Don't try to condense the loops g_vec_p, a_vecs_p = [], [] b_vecs_p = [[] for _ in range(len(b_vecs))] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i].pow(xi) * g_vec[n_p:][i].pow(x)) for k in range(len(a_vecs)): a_vecs_p.append([]) for i in range(n_p): a_vecs_p[k].append(a_vecs[k][:n_p][i] * x + a_vecs[k][n_p:][i] * xi) for j in range(len(b_vecs)): b_vecs_p[j] = [ b_vecs[j][:n_p][i] * xi + b_vecs[j][n_p:][i] * x for i in range(n_p) ] x2, xi2 = x * x, xi * xi Lax2Raxi2s = [ Las[i].pow(x2) * Ras[i].pow(xi2) for i in range(len(a_vecs)) ] xil = [x2, xi2] # the following line is equivalent to: # for i in range(numpolys): # for j in range(numverifiers): # upow = inner_product(xil, [cl_vec[j][i], cr_vec[j][i]]) # P_vec[j][i] *= Lax2Raxi2s[i] * u.pow(upow) _ = [[ P_vec[j][i].__imul__( Lax2Raxi2s[i] * u.pow(inner_product(xil, [cl_vec[j][i], cr_vec[j][i]]))) for i in range(numpolys) ] for j in range(numverifiers)] proofs, treeparts = recursive_proofs(g_vec_p, a_vecs_p, b_vecs_p, u, n_p, P_vec, transcript) for j in range(len(proofs)): treeparts[j].append(treesteps[j]) #for i in range(len(proofs[0])): # proofs[j][i].append(proofsteps[j][i] + [L_vec[j][i]] + [R_vec[j][i]]) _ = [[ proofs[j][i].append(proofsteps[j][i] + [L_vec[j][i]] + [R_vec[j][i]]) for i in range(numpolys) ] for j in range(numverifiers)] return [proofs, treeparts]
def prove_inner_product(a_vec, b_vec, comm=None, crs=None): def recursive_proof(g_vec, h_vec, u, a_vec, b_vec, n, P, transcript): if n == 1: proof = [] proof.append([a_vec[0], b_vec[0]]) return proof proofstep = [] if n % 2 == 1: na, nb = a_vec[-1] * -1, b_vec[-1] * -1 P *= g_vec[-1]**(na) * h_vec[-1]**(nb) * u**(-na * nb) proofstep.append(na) proofstep.append(nb) n_p = n // 2 cl = ZR(0) cr = ZR(0) L = G1.identity() R = G1.identity() for i in range(n_p): cl += a_vec[:n_p][i] * b_vec[n_p:][i] cr += a_vec[n_p:][i] * b_vec[:n_p][i] L *= g_vec[n_p:][i]**a_vec[:n_p][i] * h_vec[:n_p][i]**b_vec[n_p:][i] R *= g_vec[:n_p][i]**a_vec[n_p:][i] * h_vec[n_p:][i]**b_vec[:n_p][i] L *= u**cl R *= u**cr # Fiat Shamir L, R, state... #transcript += pickle.dumps([g_vec, h_vec, u, P, L, R]) transcript += pickle.dumps(hashg1list(g_vec + h_vec + [u, P, L, R])) x = ZR.hash(transcript) xi = x**-1 # this part must come after the challenge is generated, which must # come after L and R are calculated. Don't try to condense the loops g_vec_p, h_vec_p, a_vec_p, b_vec_p = [], [], [], [] for i in range(n_p): g_vec_p.append(g_vec[:n_p][i]**xi * g_vec[n_p:][i]**x) h_vec_p.append(h_vec[:n_p][i]**x * h_vec[n_p:][i]**xi) a_vec_p.append(a_vec[:n_p][i] * x + a_vec[n_p:][i] * xi) b_vec_p.append(b_vec[:n_p][i] * xi + b_vec[n_p:][i] * x) P_p = L**(x * x) * P * R**(xi * xi) proof = recursive_proof(g_vec_p, h_vec_p, u, a_vec_p, b_vec_p, n_p, P_p, transcript) proofstep.append(L) proofstep.append(R) proof.append(proofstep) return proof n = len(a_vec) assert len(b_vec) == n if crs is None: g_vec = G1.hash_many(b"honeybadgerg", n) h_vec = G1.hash_many(b"honeybadgerh", n) u = G1.hash(b"honeybadgeru") else: [g_vec, h_vec, u] = crs g_vec = g_vec[:n] h_vec = h_vec[:n] if comm is not None: P = comm * G1.identity() else: comm = G1.identity() for i in range(n): comm *= g_vec[i]**a_vec[i] * h_vec[i]**b_vec[i] iprod = ZR(0) for i in range(n): iprod += a_vec[i] * b_vec[i] P = comm * u**iprod transcript = b"" return [ comm, iprod, [n] + recursive_proof(g_vec, h_vec, u, a_vec, b_vec, n, P, transcript), ]