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 commit(self, phi, aux=None): c = G1.identity() i = 0 for item in self.gs: c *= item**phi.coeffs[i] i += 1 # c should equal g **(phi(alpha)) return c
def create_witness(self, phi, i): poly = polynomials_over(self.field) div = poly([-1 * i, 1]) psi = (phi - poly([phi(i)])) / div witness = G1.identity() j = 0 for item in self.gs[:-1]: witness *= item**psi.coeffs[j] j += 1 return witness
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
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 create_witness(self, phi, i): if self.evaltree is None: self.evaltree = gen_multipoint_eval_tree(phi, self.acctree) if self.comevaltree is None: self.comevaltree = commit_eval_tree(self.evaltree, self.g1s) branch = get_tree_branch(self.comevaltree, bit_reverse(i, ceil(log(self.n, 2)))) #if n is bigger than the length of the polynomial, the witness will end up having unneeded elements while branch[-1] == G1.identity(): branch = branch[:-1] return branch
def commit_eval_tree(evaltree, g1s): numlevels = len(evaltree) committree = [2**i * [None] for i in reversed(range(numlevels))] for k in range(len(evaltree)): for i in range(len(evaltree[k])): qpoly = evaltree[k][i][0] c = G1.identity() #this is a multiexponentiation for j in range(len(qpoly.coeffs)): c *= g1s[j]**qpoly.coeffs[j] committree[k][i] = c return committree
def verify_eval(self, c, i, phi_at_omega_i, witness): valcom = self.g1s[0]**phi_at_omega_i valcom.negate() lhs = pair(c * valcom, self.g2s[0]) rhs = pair(G1.identity(), G2.identity()) acc_branch = get_tree_branch(self.comacctree, bit_reverse(i, ceil(log(self.n, 2)))) #if witness is shorter (due to more than degree + 1 recipients), it will only #check as many entries as are in witness, which is what we want for items in zip(witness, acc_branch): rhs = rhs * pair(items[0], items[1]) return lhs == rhs
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 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 batch_create_witness(self, phi): if self.evaltree is None: self.evaltree = gen_multipoint_eval_tree(phi, self.acctree) if self.comevaltree is None: self.comevaltree = commit_eval_tree(self.evaltree, self.g1s) branches = [ get_tree_branch(self.comevaltree, bit_reverse(i, ceil(log(self.n, 2)))) for i in range(self.n) ] for i in range(len(branches)): while branches[i][-1] == G1.identity(): branches[i] = branches[i][:-1] return branches
def interpolate_g1_at_x(coords, x, order=-1): if isinstance(coords[0][1], SimulatedPclProof): out = SimulatedPclProof(1) return out elif isinstance(coords[0][1], SimulatedPclCom): out = SimulatedPclCom() return out if order == -1: order = len(coords) xs = [] sortedcoords = sorted(coords, key=lambda x: x[0]) for coord in sortedcoords: xs.append(coord[0]) s = set(xs[0:order]) out = G1.identity() for i in range(order): out *= (sortedcoords[i][1]**(lagrange_at_x(s, xs[i], x))) return out
def commit(self, phi, r): c = G1.identity() for i in range(len(phi.coeffs)): c *= self.gs[i]**phi.coeffs[i] c *= self.h**r return c
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), ]
def recursive_proofs(g_vec, a_vecs, b_vecs, u, n, P_vec, transcript): #row_length = len(b_vecs)//len(a_vecs) numproofs = len(a_vecs) * len(b_vecs) row_length = numproofs // len(a_vecs) col_length = numproofs // len(b_vecs) numverifiers = len(b_vecs) numpolys = len(a_vecs) _ = [g.preprocess(5) for g in g_vec] if n == 1: #proofs = [None] * numproofs #for i in range(len(proofs) // row_length): # for j in range(row_length): # abs_idx = i * row_length + j # proofs[abs_idx] = [[a_vecs[i][0]]] #return proofs proofs = [[[] for _ in range(numpolys)] for _ in range(numverifiers)] for i in range(numpolys): for j in range(numverifiers): proofs[j][i] = [[a_vecs[i][0]]] #proofs = [[a_vecs[:][0]]] * numverifiers return proofs #proofsteps = [[] for _ in range(numproofs)] proofsteps = [[[] for _ in range(numpolys)] for _ in range(numverifiers)] 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): #abs_idx = i * row_length + j #P_vec[abs_idx] *= gtail * u.pow(na * b_vecs[j][-1]) P_vec[j][i] *= gtail * u.pow(na * b_vecs[j][-1]) #proofsteps[abs_idx].append(na) proofsteps[j][i].append(na) n_p = n // 2 #cl_vec = [0 for _ in range(len(P_vecs))] #cr_vec = [0 for _ in range(len(P_vecs))] #L_vec = [None] * len(P_vecs) #R_vec = [None] * len(P_vecs) 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): #abs_idx = i * numverifiers + j #cl_vec[abs_idx] = inner_product(a_vecs[i][:n_p], b_vecs[j][n_p:2*n_p]) #cr_vec[abs_idx] = inner_product(a_vecs[i][n_p:2*n_p], b_vecs[j][:n_p]) #L_vec[abs_idx] = Las[i] * (u.pow(cl_vec[abs_idx])) #R_vec[abs_idx] = Ras[i] * (u.pow(cr_vec[abs_idx])) 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])) # Fiat Shamir # Make a merkle tree over everything that varies between verifiers # TODO: na should be in the transcript tree = MerkleTree() b_hashes = [hashzrlist(b_vecs[i]) for i in range(len(b_vecs))] leaves = [ hash_list_to_bytes( #[b_hashes[j%len(b_vecs)], hashg1list([P_vec[j], L_vec[j], R_vec[j]])] [ b_hashes[j % len(b_vecs)], hashg1list([ P_vec[j % numverifiers][j // numverifiers], L_vec[j % numverifiers][j // numverifiers], R_vec[j % numverifiers][j // numverifiers] ]) ]) for j in range(numproofs) ] tree.append_many(leaves) roothash = tree.get_root_hash() #for j in range(len(P_vecs)): # branch = tree.get_branch(j) # proofsteps[j].append(roothash) # proofsteps[j].append(branch) for i in range(numpolys): for j in range(numverifiers): branch = tree.get_branch(i * numverifiers + j) proofsteps[j][i].append(roothash) proofsteps[j][i].append(branch) 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)): #for i in range(n_p): # b_vecs_p[j].append(b_vecs[j][:n_p][i] * xi + b_vecs[j][n_p:][i] * x) 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)) ] #for i in range(numproofs // row_length): # for j in range(row_length): # abs_idx = i * row_length + j # P_vec[abs_idx] *= Lax2Raxi2s[i] * u ** (x2 * cl_vec[abs_idx] + xi2 * cr_vec[abs_idx]) xil = [x2, xi2] #for i in range(numproofs): # upow = inner_product(xil, [cl_vec[i], cr_vec[i]]) # P_vec[i] *= Lax2Raxi2s[i//row_length] * u.pow(upow) 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) proofs = recursive_proofs(g_vec_p, a_vecs_p, b_vecs_p, u, n_p, P_vec, transcript) #for j in range(len(proofs)): # proofsteps[j].append(L_vec[j]) # proofsteps[j].append(R_vec[j]) # proofs[j].append(proofsteps[j]) for j in range(len(proofs)): for i in range(len(proofs[0])): proofsteps[j][i].append(L_vec[j][i]) proofsteps[j][i].append(R_vec[j][i]) proofs[j][i].append(proofsteps[j][i]) return proofs
def prove_double_batch_inner_product_one_known(a_vecs, b_vecs, comms=None, crs=None): #@profile def recursive_proofs(g_vec, a_vecs, b_vecs, u, n, P_vec, transcript): #row_length = len(b_vecs)//len(a_vecs) numproofs = len(P_vec) row_length = numproofs // len(a_vecs) col_length = numproofs // len(b_vecs) numverifiers = row_length _ = [g.preprocess(5) for g in g_vec] if n == 1: proofs = [None] * numproofs for i in range(len(proofs) // row_length): for j in range(row_length): abs_idx = i * row_length + j proofs[abs_idx] = [[a_vecs[i][0]]] return proofs proofsteps = [[] for _ in range(numproofs)] if n % 2 == 1: for i in range(numproofs // row_length): na = a_vecs[i][-1] * -1 gtail = g_vec[-1].pow(na) for j in range(row_length): abs_idx = i * row_length + j P_vec[abs_idx] *= gtail * u.pow(na * b_vecs[j][-1]) proofsteps[abs_idx].append(na) n_p = n // 2 cl_vec = [0 for _ in range(len(P_vecs))] cr_vec = [0 for _ in range(len(P_vecs))] L_vec = [None] * len(P_vecs) R_vec = [None] * len(P_vecs) 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(numproofs // row_length): for j in range(row_length): abs_idx = i * row_length + j cl_vec[abs_idx] = inner_product(a_vecs[i][:n_p], b_vecs[j][n_p:2 * n_p]) cr_vec[abs_idx] = inner_product(a_vecs[i][n_p:2 * n_p], b_vecs[j][:n_p]) L_vec[abs_idx] = Las[i] * (u.pow(cl_vec[abs_idx])) R_vec[abs_idx] = Ras[i] * (u.pow(cr_vec[abs_idx])) # Fiat Shamir # Make a merkle tree over everything that varies between verifiers # TODO: na should be in the transcript tree = MerkleTree() b_hashes = [hashzrlist(b_vecs[i]) for i in range(len(b_vecs))] leaves = [ hash_list_to_bytes([ b_hashes[j % len(b_vecs)], hashg1list([P_vec[j], L_vec[j], R_vec[j]]) ]) for j in range(numproofs) ] tree.append_many(leaves) roothash = tree.get_root_hash() #for h in range(numverifiers): for j in range(len(P_vecs)): branch = tree.get_branch(j) proofsteps[j].append(roothash) proofsteps[j].append(branch) 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)): #for i in range(n_p): # b_vecs_p[j].append(b_vecs[j][:n_p][i] * xi + b_vecs[j][n_p:][i] * x) 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)) ] #for i in range(numproofs // row_length): # for j in range(row_length): # abs_idx = i * row_length + j # P_vec[abs_idx] *= Lax2Raxi2s[i] * u ** (x2 * cl_vec[abs_idx] + xi2 * cr_vec[abs_idx]) xil = [x2, xi2] for i in range(numproofs): upow = inner_product(xil, [cl_vec[i], cr_vec[i]]) P_vec[i] *= Lax2Raxi2s[i // row_length] * u.pow(upow) proofs = recursive_proofs(g_vec_p, a_vecs_p, b_vecs_p, u, n_p, P_vec, transcript) for j in range(len(proofs)): proofsteps[j].append(L_vec[j]) proofsteps[j].append(R_vec[j]) proofs[j].append(proofsteps[j]) return proofs t = len(a_vecs[0]) if crs is None: g_vec = G1.hash_many(b"honeybadgerg", n) u = G1.hash(b"honeybadgeru") else: [g_vec, u] = crs g_vec = g_vec[:t] if comms is None: comms = [] for j in range(len(a_vecs)): comms.append(G1.identity()) for i in range(t): comms[j] *= g_vec[i].pow(a_vecs[j][i]) iprods = [ZR(0) for _ in range(len(b_vecs) * len(a_vecs))] P_vecs = [None] * (len(b_vecs) * len(a_vecs)) row_length = len(b_vecs) for i in range(len(a_vecs)): for j in range(len(b_vecs)): abs_idx = i * row_length + j #for k in range(t): # iprods[abs_idx] += a_vecs[i][k] * b_vecs[j][k] iprods[abs_idx] = inner_product(a_vecs[i], b_vecs[j]) P_vecs[abs_idx] = comms[i] * u.pow(iprods[abs_idx]) transcript = pickle.dumps(u) proofsize = len(a_vecs) * len(b_vecs) i = 0 proofs = recursive_proofs(g_vec, a_vecs, b_vecs, u, t, P_vecs, transcript) for j in range(len(proofs)): proofs[j].insert(0, t) # Transform the proofs into a list of lists proofs_p = [] for i in range(len(a_vecs)): proofs_p.append([]) for j in range(len(proofs) // len(a_vecs)): proofs_p[i].append(proofs[i * (len(proofs) // len(a_vecs)) + j]) return [comms, iprods, proofs_p]
def recursive_proofs(g_vec, a_vec, b_vecs, u, n, P_vec, transcript): if n == 1: proofs = [None] * len(b_vecs) for j in range(len(proofs)): proofs[j] = [[a_vec[0]]] return proofs proofsteps = [[] for _ in range(len(b_vecs))] if n % 2 == 1: na = a_vec[-1] * -1 for j in range(len(P_vec)): P_vec[j] *= g_vec[-1]**(na) * u**(na * b_vecs[j][-1]) proofsteps[j].append(na) n_p = n // 2 cl_vec = [ZR(0) for _ in range(len(b_vecs))] cr_vec = [ZR(0) for _ in range(len(b_vecs))] La = G1.identity() Ra = G1.identity() L_vec = [None] * len(b_vecs) R_vec = [None] * len(b_vecs) for i in range(n_p): La *= g_vec[n_p:][i]**a_vec[:n_p][i] Ra *= g_vec[:n_p][i]**a_vec[n_p:][i] for j in range(len(b_vecs)): #for i in range(n_p): # cl_vec[j] += a_vec[:n_p][i] * b_vecs[j][n_p:][i] # cr_vec[j] += a_vec[n_p:][i] * b_vecs[j][:n_p][i] cl_vec[j] = inner_product(a_vec[:n_p], b_vecs[j][n_p:2 * n_p]) cr_vec[j] = inner_product(a_vec[n_p:2 * n_p], b_vecs[j][:n_p]) L_vec[j] = La * (u**cl_vec[j]) R_vec[j] = Ra * (u**cr_vec[j]) # Fiat Shamir # Make a merkle tree over everything that varies between verifiers # TODO: na should be in the transcript tree = MerkleTree() #for j in range(len(b_vecs)): # tree.append(pickle.dumps([b_vecs[j], P_vec[j], L_vec[j], R_vec[j]])) b_hashes = [hashzrlist(b_vecs[i]) for i in range(len(b_vecs))] leaves = [ hash_list_to_bytes( [b_hashes[j], hashg1list([P_vec[j], L_vec[j], R_vec[j]])]) for j in range(len(b_vecs)) ] tree.append_many(leaves) roothash = tree.get_root_hash() for j in range(len(b_vecs)): branch = tree.get_branch(j) proofsteps[j].append(roothash) proofsteps[j].append(branch) 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_vec_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]**xi * g_vec[n_p:][i]**x) a_vec_p.append(a_vec[:n_p][i] * x + a_vec[n_p:][i] * xi) for j in range(len(b_vecs)): b_vecs_p[j].append(b_vecs[j][:n_p][i] * xi + b_vecs[j][n_p:][i] * x) x2, xi2 = x * x, xi * xi Lax2Raxi2 = La**x2 * Ra**xi2 for j in range(len(P_vec)): # Instead of doing L_vec[j]**(x2)*P_vec[j]*R_vec[j]**(xi2), save computation P_vec[j] *= Lax2Raxi2 * u**(x2 * cl_vec[j] + xi2 * cr_vec[j]) proofs = recursive_proofs(g_vec_p, a_vec_p, b_vecs_p, u, n_p, P_vec, transcript) for j in range(len(proofs)): proofsteps[j].append(L_vec[j]) proofsteps[j].append(R_vec[j]) proofs[j].append(proofsteps[j]) return proofs
def commit(self, phi): c = G1.identity() for j in range(len(phi.coeffs)): c *= self.g1s[j]**phi.coeffs[j] return c