def __init__(self, nCopies, nInputs, in0vv, in1vv, typevv, muxvv=None): self.nCopies = nCopies self.nCopyBits = util.clog2(nCopies) self.nInputs = nInputs self.nInBits = util.clog2(nInputs) self.ckt_inputs = None self.ckt_outputs = None self.layerNum = 0 self.roundNum = 0 self.arith_ckt = None assert len(in0vv) == len(in1vv) assert len(in0vv) == len(typevv) assert muxvv is None or len(in0vv) == len(muxvv) if muxvv is None: muxvv = [None] * len(in0vv) # save circuit config for building layers later self.in0vv = in0vv self.in1vv = in1vv self.typevv = typevv self.muxvv = muxvv self.muxlen = max( max(muxv) if muxv is not None else 0 for muxv in muxvv) + 1 self.muxbits = [0] * self.muxlen # build instrumentation if Defs.track_fArith: fArith = Defs.fArith() self.comp_h = fArith.new_cat("p_comp_h_%d" % hash(self)) self.comp_b = fArith.new_cat("p_comp_b_%d" % hash(self)) self.comp_chi = fArith.new_cat("p_comp_chi_%d" % hash(self)) self.comp_v = fArith.new_cat("p_comp_v_%d" % hash(self)) self.comp_v_fin = fArith.new_cat("p_comp_v_fin_%d" % hash(self)) self.comp_out = fArith.new_cat("p_comp_out_%d" % hash(self)) else: self.comp_h = None self.comp_b = None self.comp_chi = None self.comp_v = None self.comp_v_fin = None self.comp_out = None # layer provers self.layer = None self.layer_inbits = [self.nInBits] + [ util.clog2(len(in0v)) for in0v in in0vv[:-1] ]
def witness_commit(self, wvals): self.nbits = util.clog2(len(wvals)) if self.bitdiv == 0: self.v1bits = 0 else: self.v1bits = int(self.nbits / self.bitdiv) self.v2bits = self.nbits - self.v1bits # build the vector out of w v1len = 2**self.v1bits v2len = 2**self.v2bits self.tvals = [] wlen = len(wvals) for i in xrange(0, v1len): # implicit padding by 0 self.tvals.append([ wvals[i + v1len * j] if i + v1len * j < wlen else 0 for j in xrange(0, v2len) ]) self.svals = [] cvals = [] for row in self.tvals: sval = self.gops.rand_scalar() cval = self.gops.pow_gih(row, sval, 0) self.svals.append(sval) cvals.append(cval) if self.com.rec: self.com.rec_q.did_rng(len(self.tvals)) self.com.rec_p.did_mexps([1 + len(self.tvals[0])] * len(self.tvals)) return cvals
def __init__(self, nCopies, nInputs, in0vv, in1vv, typvv, muxvv=None): self.nCopies = nCopies self.nCopyBits = util.clog2(nCopies) self.nInputs = nInputs self.nInBits = util.clog2(nInputs) self.nCktInputs = nInputs # these don't change even with RDL self.nCktBits = self.nInBits self.prover = None self.in0vv = in0vv self.in1vv = in1vv self.typvv = typvv self.muxvv = muxvv self.muxbits = None self.inputs = [] self.outputs = [] self.mlx_w1 = [] self.mlx_w2 = [] self.prover_fresh = False if Defs.track_fArith: fArith = Defs.fArith() self.in_a = fArith.new_cat("%s_in_%d" % (self.cat_label, hash(self))) self.out_a = fArith.new_cat("%s_out_%d" % (self.cat_label, hash(self))) self.sc_a = fArith.new_cat("%s_sc_%d" % (self.cat_label, hash(self))) self.tV_a = fArith.new_cat("%s_tV_%d" % (self.cat_label, hash(self))) self.tP_a = fArith.new_cat("%s_tP_%d" % (self.cat_label, hash(self))) self.nlay_a = fArith.new_cat("%s_nlay_%d" % (self.cat_label, hash(self))) else: self.in_a = None self.out_a = None self.sc_a = None self.tV_a = None self.tP_a = None self.nlay_a = None # nOutBits and nInBits for each layer self.layOutBits = [ util.clog2(len(lay)) for lay in reversed(self.in0vv) ] self.layInBits = self.layOutBits[1:] + [self.nInBits]
def __init__(self, nCopies, nInputs, in0vv, in1vv, typevv, muxvv=None): self.muxbits = [0] self.laySkip = max(3, int(math.sqrt(len(in0vv)))) self.nCopies = nCopies self.nInputs = nInputs self.nInBits = util.clog2(nInputs) self.in0vv = in0vv self.in1vv = in1vv self.typevv = typevv self.muxvv = muxvv
def __init__(self, nInBits, circuit, in0v, in1v, typev, muxv=None): # pylint: disable=protected-access self.nInBits = nInBits self.circuit = circuit self.nOutBits = util.clog2(len(in0v)) self.roundNum = 0 self.muls = None self.compute_v = [] self.inputs = [] self.output = [] if muxv is None: # fake it muxv = [0] * len(in0v) assert len(in0v) == len(in1v) and len(in0v) == len(muxv) and len( in0v) == len(typev) # h computation subckt self.compute_h = LayerComputeH(self, circuit.comp_h) # beta computation subckt self.compute_beta = LayerComputeBeta(self.circuit.nCopyBits, None, circuit.comp_b) # z1chi computation subckt # this uses the Verifier's fast beta eval code self.compute_z1chi = None self.compute_z1chi_2 = None # v circuits are per-input---we collapse inputs in first nCopyBits rounds for _ in xrange(0, 2**self.nInBits): lcv_tmp = LayerComputeV(self.circuit.nCopyBits, circuit.comp_v) # outputs are collapsed lcv_tmp.expand_outputs = lcv_tmp.multiple_passes = False self.compute_v.append(lcv_tmp) # after finishing the first nCopyBits rounds, we only need one ComputeV circuit, # and everything is now 2nd order, so we only need three eval points, not four self.compute_v_final = LayerComputeV(self.nInBits, circuit.comp_v_fin) self.compute_v_final.set_other_factors([util.THIRD_EVAL_POINT]) # pergate computation subckts for "early" rounds self.gates = [] max_muxbit = 0 for (out, (in0, in1, mx, tp)) in enumerate(izip(in0v, in1v, muxv, typev)): assert issubclass(tp, gateprover._GateProver) self.gates.append(tp(True, in0, in1, out, self, mx)) if mx > max_muxbit: max_muxbit = mx muxlen = max_muxbit + 1 assert len(self.circuit.muxbits ) >= muxlen, "Expected %d muxbits, found %d" % ( muxlen, len(self.circuit.muxbits))
def rand_inputs(nInBits, nCopies, inLay=None): out = [] if inLay is None: inLay = [None] * (2 ** nInBits) else: nInBits = util.clog2(len(inLay)) inLay += [0] * (2 ** nInBits - len(inLay)) for _ in xrange(0, nCopies): out.append([ Defs.gen_random() if elm is None else elm % Defs.prime for elm in inLay ]) return out
def __init__(self, q): self.q = q # compare to a multiple of q to minimize probability of throwing away values divr = 1 maskbits = util.clog2(q) maskdiff = (2 ** maskbits - q) / (2 ** maskbits + 0.0) for d in xrange(2, 128): tq = d * q tbits = util.clog2(tq) tdiff = (2 ** tbits - tq) / (2 ** tbits + 0.0) if tbits > 512: break elif tdiff < maskdiff: divr = d maskbits = tbits maskdiff = tdiff nbits = maskbits self.mask = 2 ** maskbits - 1 self.comp = divr * q self.rnum = 0 self.io = deque() self.trans = deque() self.can_put = True if nbits <= 256: self.hash = hashlib.sha256() elif nbits <= 384: self.hash = hashlib.sha384() elif nbits <= 512: self.hash = hashlib.sha512() else: assert False, "FiatShamir cannot handle q longer than 512 bits!" self.hash.update("fennel,")
def __init__(self, rdl, nInBits): # pylint: disable=protected-access self.rdl = util.flatten(rdl) self.nOutBits = util.clog2(len(self.rdl)) self.nInBits = nInBits self.roundNum = 0 self.muls = None circuit = type('', (object, ), { 'comp_chi': None, 'comp_v_fin': None, 'comp_out': None })() self.circuit = circuit if Defs.track_fArith: fArith = Defs.fArith() circuit.comp_chi = fArith.new_cat("p_rdl_comp_chi_%d" % hash(self)) circuit.comp_v_fin = fArith.new_cat("p_rdl_comp_v_fin_%d" % hash(self)) circuit.comp_out = fArith.new_cat("p_rdl_comp_out_%d" % hash(self)) else: circuit.comp_chi = None circuit.comp_v_fin = None circuit.comp_out = None self.inputs = [] self.output = [] # z1chi computation subckt # this uses V's fast beta evaluation (in set_z) self.compute_z1chi = None self.compute_z1chi_2 = None # everything is 2nd order, so we only need three eval points self.compute_v_final = LayerComputeV(nInBits, circuit.comp_v_fin) self.compute_v_final.set_other_factors([util.THIRD_EVAL_POINT]) # pergate computation subckts for "early" rounds self.gates = [] for (outNum, inNum) in enumerate(self.rdl): self.gates.append( gateprover.PassGateProver(False, inNum, 0, outNum, self, 0))
def parse_rdl(rFile, nCopies, pInputs): # 1. check that rFile is of the proper form lenPI = len(pInputs) pInPad = 2**util.clog2(lenPI) - lenPI assert len(rFile) == 2 assert all(ent[0] == "PASS" for ent in rFile[1]) if len(rFile[1]) != nCopies * lenPI: raise ValueError( "This RDL appears to be for the wrong number of copies (%d, expected %d)" % (len(rFile[1]), nCopies * lenPI)) # 2. generate the mapping rdl_map = [] for idx in xrange(0, nCopies): rdl_ent = [ent[1] for ent in rFile[1][idx * lenPI:(idx + 1) * lenPI]] rdl_ent += [0] * pInPad rdl_map.append(rdl_ent) return (rFile[0], rdl_map)
def __init__(self, nCopies, nInputs, in0vv, in1vv, typevv, muxvv=None): nInBits = util.clog2(nInputs) assert len(in0vv) == len(in1vv) and len(in0vv) == len(typevv) and ( muxvv is None or len(in0vv) == len(muxvv)) if muxvv is None: muxvv = [None] * len(in0vv) arith_circuit = ArithCircuit() arith_circuit.layers = [ArithCircuitInputLayer(arith_circuit, nInBits)] for (lay, (in0v, in1v, muxv, typev)) in enumerate(izip(in0vv, in1vv, muxvv, typevv)): typec = [typ.cgate for typ in typev] arith_circuit.layers.append( ArithCircuitLayer(arith_circuit, arith_circuit.layers[lay], in0v, in1v, typec, muxv)) self.arith_circuit = arith_circuit self.nCopies = nCopies
def iparg_init(self, xIP=None): if xIP is not None: self.u = (self.gops.pow_g(xIP), ) # pad out n, l, and r nExtra = 2**util.clog2(self.n) - self.n self.n += nExtra self.lEv += [0] * nExtra self.rEv += [0] * nExtra if nExtra != 0: self.extend_yipows() nP = self.n // 2 cL = sum( (lv * rv) % Defs.prime for (lv, rv) in izip(self.lEv[:nP], self.rEv[nP:])) % Defs.prime cR = sum( (lv * rv) % Defs.prime for (lv, rv) in izip(self.lEv[nP:], self.rEv[:nP])) % Defs.prime if xIP is not None: # for initial messages we have to be slightly careful because we have h, not h' h_pows_1 = ((rv * iv) % Defs.prime for (rv, iv) in izip(self.rEv[nP:], self.YIpows[:nP])) L1 = self.gops.pow_gi(chain(self.lEv[:nP], h_pows_1), nP, 1, self.n) L = self.gops.exp_mul(self.u[0], cL, L1) h_pows_2 = ((rv * iv) % Defs.prime for (rv, iv) in izip(self.rEv[:nP], self.YIpows[nP:])) R1 = self.gops.pow_gi(self.lEv[nP:], 0) R2 = self.gops.pow_gi(h_pows_2, self.n + nP, 1, nP) R = self.gops.exp_mul(self.u[0], cR, self.gops.mul(R1, R2)) else: # otherwise, we have the bases computed already L = self.gops.multiexp(chain(self.gV[nP:], self.hV[:nP], self.u), chain(self.lEv[:nP], self.rEv[nP:], (cL, )), self.n + 1) R = self.gops.multiexp(chain(self.gV[:nP], self.hV[nP:], self.u), chain(self.lEv[nP:], self.rEv[:nP], (cR, )), self.n + 1) return (L, R)
def witness_commit(self, aL, aR, aO): self.aL = aL self.aR = aR self.aO = aO # generate all the randomness self.alpha = self.gops.rand_scalar() self.beta = self.gops.rand_scalar() self.rho = self.gops.rand_scalar() self.sL = [self.gops.rand_scalar() for _ in xrange(self.n)] self.sR = [self.gops.rand_scalar() for _ in xrange(self.n)] # now commit to the witness nRnd = 2**util.clog2(self.n) com_AI = self.gops.pow_gih(chain(aL, repeat(0, nRnd - self.n), aR), self.alpha, 0, nRnd + self.n) com_AO = self.gops.pow_gih(aO, self.beta, 0, self.n) com_S = self.gops.pow_gih( chain(self.sL, repeat(0, nRnd - self.n), self.sR), self.rho, 0, nRnd + self.n) return (com_AI, com_AO, com_S)
def run_helper(com, ctype): bitdiv = random.choice((0, 2, 3, 4, 5)) lw = ctype(com, bitdiv) logn = util.clog2(com.gops.maxlen) if 2**logn > com.gops.maxlen: logn -= 1 rvals = [com.gops.rand_scalar() for _ in xrange(0, logn)] r0val = com.gops.rand_scalar() avals = [com.gops.rand_scalar() for _ in xrange(0, 2**logn)] dpval = (iomlext.VerifierIOMLExt(rvals).compute(avals) * r0val + 3) % Defs.prime # commit to avals and dpval Aval = lw.witness_commit(avals) (Zval, rZval) = com.commit(dpval) # run prover side of commitment lw.set_rvals_p(rvals, r0val, rZval) redc_vals = [] chal_vals = [] cont = True while cont: redc_vals.append(lw.redc_init()) chal_vals.append(com.gops.rand_scalar()) cont = lw.redc_cont_p(chal_vals[-1]) fin_init_val = lw.fin_init() fin_chal = com.gops.rand_scalar() fin_finish_val = lw.fin_finish(fin_chal) # run verifier side of commitment lwv = ctype(com, bitdiv) lwv.set_rvals_v(rvals, r0val, Aval, Zval, 3) for (rv, cv) in zip(redc_vals, chal_vals): cont = lwv.redc_cont_v(cv, rv) assert lwv.fin_check(fin_chal, fin_init_val, fin_finish_val)
def run(self, inputs, muxbits=None): self.build_prover() self.build_wcom(True) self.prover_fresh = False assert Defs.prime == self.com.gops.q ###################### # 0. Run computation # ###################### assert self.prover is not None # generate any nondet inputs inputs = self.nondet_gen(inputs, muxbits) # set muxbits and dump into transcript if muxbits is not None: self.prover.set_muxbits(muxbits) self.fs.put(muxbits, True) # figure out the nondeterministic invals = [] invals_nd = [] for ins in inputs: ins = list(ins) + [0] * (2**self.nInBits - len(ins)) if self.fs.ndb is not None: loIdx = (2 ** self.nInBits) - (2 ** (self.nInBits - self.fs.ndb)) if self.fs.rvend is not None and self.fs.rvstart is not None: ins[self.fs.rvstart:self.fs.rvend+1] = [0] * (self.fs.rvend - self.fs.rvstart + 1) ins_nd = ins[loIdx:] ins[loIdx:] = [0] * (2 ** (self.nInBits - self.fs.ndb)) invals_nd.extend(ins_nd) invals.extend(ins) # need to pad up to nCopies if we're not using an RDL if self.rdl is None: assert util.clog2(len(invals)) == self.nInBits + self.nCopyBits invals += [0] * (2 ** (self.nInBits + self.nCopyBits) - len(invals)) self.fs.put(invals, True) # commit to nondet inputs from prover if invals_nd: self.create_witness_comm(invals_nd) # now V sets r_values if necessary if self.fs.rvstart is not None and self.fs.rvend is not None: r_values = [ self.fs.rand_scalar() for _ in xrange(self.fs.rvstart, self.fs.rvend + 1) ] if self.rdl is None: assert len(inputs) == self.nCopies for inp in inputs: inp[self.fs.rvstart:self.fs.rvend+1] = r_values else: assert len(inputs) == 1 inputs[0][self.fs.rvstart:self.fs.rvend+1] = r_values if self.rdl is None: self.prover.set_inputs(inputs) else: rdl_inputs = [] for r_ents in self.rdl: rdl_inputs.append([ inputs[0][r_ent] for r_ent in r_ents ]) self.prover.set_inputs(rdl_inputs) # now evaluate the AC and put the outputs in the transcript outvals = util.flatten(self.prover.ckt_outputs) nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(outvals)) == nOutBits + self.nCopyBits outvals += [0] * (2 ** (nOutBits + self.nCopyBits) - len(outvals)) self.fs.put(outvals, True) # generate random point in (z1, z2) \in F^{nOutBits + nCopyBits} z1 = [ self.fs.rand_scalar() for _ in xrange(0, nOutBits) ] z1_2 = None z2 = [ self.fs.rand_scalar() for _ in xrange(0, self.nCopyBits) ] if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) # to start, we reconcile with mlext of output # V knows it, so computes g^{mlext}, i.e., Com(mlext; 0) prev_rval = 0 muls = None # if the AC has only one layer, tell P to give us H(.) project_line = len(self.in0vv) == 1 self.prover.set_z(z1, z2, None, None, project_line) ########################################## # 1. Interact with prover for each layer # ########################################## for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] w1 = [] w2 = [] w3 = [] self.com.reset() if Defs.track_fArith: self.sc_a.did_rng(2*nInBits + self.nCopyBits) ################### ### A. Sumcheck ### ################### for rd in xrange(0, 2 * nInBits + self.nCopyBits): # get output from prv and check against expected value outs = self.prover.get_outputs() # 1. commit to these values self.fs.put(self.com.compress(self.com.commitvec(outs))) # 2. compute new rand value and go to next round nrand = self.fs.rand_scalar() self.prover.next_round(nrand) if rd < self.nCopyBits: assert len(outs) == 4 w3.append(nrand) else: assert len(outs) == 3 if rd < self.nCopyBits + nInBits: w1.append(nrand) else: w2.append(nrand) ############################### ### B. Extend to next layer ### ############################### outs = self.prover.get_outputs() if project_line: assert len(outs) == 1 + nInBits assert lay == len(self.in0vv) - 1 # (1) commit to all values plus their sum # (2) figure out c2val, r2val from above and outs[0] com # (3) create prod com # (4) send PoK of product for outs[0], c2val, prod (outs_rvals, pr_rvals) = self.create_final_prod_pok(outs) else: # just need to do product PoK since we're sending tV(r1) and tV(r2) assert len(outs) == 2 pr_rvals = self.create_prod_pok(outs) ### all claimed values are now in the transcript, so we can do vector proof # put delvals in the transcript self.fs.put([ self.com.compress(delval) for delval in self.com.vecpok_init() ]) # now we need the vector of J values. first, generate the per-row Js j1val = self.fs.rand_scalar() jvals = [ self.fs.rand_scalar() for _ in xrange(0, 2 * nInBits + self.nCopyBits) ] # next, compute Jvec and put corresponding element in proof Jvec = _compute_Jvec(j1val, jvals, w3 + w1 + w2, self.nCopyBits, nInBits, False, self.com_q_a) self.fs.put(self.com.compress(self.com.vecpok_cont(Jvec))) # next, need mlext evals to do PoK (mlext_evals, mlx_z2) = self.eval_mlext(lay, z1, z2, w1, w2, w3, z1_2, muls) xyzvals = [0, 0, 0, 0] for (idx, elm) in enumerate(mlext_evals): GateFunctionsPVC[idx](elm, jvals[-1], xyzvals, self.tV_a) xyzvals = [ (mlx_z2 * v) % Defs.prime for v in xyzvals ] # finally, run vecpok_finish to put zvals in transcript chal = self.fs.rand_scalar() self.fs.put(self.com.vecpok_finish(j1val, prev_rval, xyzvals, pr_rvals, chal)) if Defs.track_fArith: self.com_q_a.did_rng(2*nInBits + self.nCopyBits + 1) self.tV_a.did_mul(len(xyzvals)) self.com_q_a.did_rng() project_next = (lay == len(self.in0vv) - 2) and (self.rdl is None) if project_line: tau = self.fs.rand_scalar() muls = None prev_rval = util.horner_eval(outs_rvals, tau) z1 = [ (elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in izip(w1, w2) ] z1_2 = None if Defs.track_fArith: self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) self.sc_a.did_rng() else: muls = [self.fs.rand_scalar(), self.fs.rand_scalar()] tau = None prev_rval = (muls[0] * pr_rvals[0] + muls[1] * pr_rvals[1]) % Defs.prime z1 = w1 z1_2 = w2 if Defs.track_fArith: self.nlay_a.did_add() self.nlay_a.did_mul(2) self.sc_a.did_rng(2) if lay < len(self.in0vv) - 1: self.prover.next_layer(muls, project_next) project_line = project_next z2 = w3 self.prover = None # don't need this anymore ############################# # 1.5. Run RDL if necessary # ############################# if self.rdl is not None: self.rdl_prover = RDLProver(self.rdl, self.nInBits) self.rdl_prover.set_inputs(inputs) self.rdl_prover.set_z(z1 + z2, z1_2 + z2, muls) w1 = [] self.com.reset() if Defs.track_fArith: self.rdl_sc_a.did_rng(self.nInBits) #################### # Sumcheck for RDL # #################### for _ in xrange(0, self.nInBits): # get outputs outs = self.rdl_prover.compute_outputs() # commit to these values self.fs.put(self.com.compress(self.com.commitvec(outs))) # compute new value and go to next round nrand = self.fs.rand_scalar() w1.append(nrand) self.rdl_prover.next_round(nrand) ####################### # Finish RDL sumcheck # ####################### outs = self.rdl_prover.compute_outputs() self.rdl_prover = None # don't need this any more; save the memory # in this case, output is just claimed eval of V_0 assert len(outs) == 1 pr_rvals = self.create_pok(outs) # all claimed values are now in the transcript, so we can do a vector proof self.fs.put([ self.com.compress(delval) for delval in self.com.vecpok_init() ]) # now need vector of J values; generate per-row Js j1val = self.fs.rand_scalar() jvals = [ self.fs.rand_scalar() for _ in xrange(0, self.nInBits) ] # compute Jvec and put corresponding element in proof Jvec = _compute_Jvec(j1val, jvals, w1, 0, self.nInBits, True, self.com_q_a) self.fs.put(self.com.compress(self.com.vecpok_cont(Jvec))) # next, need mlext eval for PASS to do PoK mlext_pass = self.eval_mlext_pass(z1, z1_2, z2, w1, muls) xyzvals = [(mlext_pass * jvals[-1]) % Defs.prime] # run vecpok_finish to put zvals in transcript chal = self.fs.rand_scalar() self.fs.put(self.com.vecpok_finish(j1val, prev_rval, xyzvals, pr_rvals, chal)) if Defs.track_fArith: self.com_q_a.did_rng(self.nInBits + 1) self.tP_a.did_mul() self.com_q_a.did_rng() # prepare variables for final check muls = None tau = None prev_rval = pr_rvals[0] z1 = w1 z1_2 = None z2 = [] ############################# # 2. Proof of eq with input # ############################# if invals_nd: # do witness proof r0val = reduce(lambda x, y: (x * y) % Defs.prime, z1[len(z1)-self.fs.ndb:], 1) rvals = z1[:len(z1)-self.fs.ndb] + z2 self.create_witness_proof(rvals, r0val, prev_rval) if Defs.track_fArith: self.com_q_a.did_mul(self.fs.ndb) else: self.create_eq_proof(None, prev_rval) ######################## # 3. Return transcript # ######################## return self.fs.to_string()
def run(self, inputs, muxbits=None): self.build_prover() self.prover_fresh = False assert Defs.prime == self.com.gops.q ###################### # 0. Run computation # ###################### assert self.prover is not None # generate any nondet inputs inputs = self.nondet_gen(inputs, muxbits) # set muxbits and dump into transcript if muxbits is not None: self.prover.set_muxbits(muxbits) self.fs.put(muxbits, True) # run AC, then dump inputs and outputs into the transcript invals = [] invals_nd = [] for ins in inputs: ins = list(ins) + [0] * (2**self.nInBits - len(ins)) if self.fs.ndb is not None: loIdx = (2**self.nInBits) - (2**(self.nInBits - self.fs.ndb)) if self.fs.rvend is not None and self.fs.rvstart is not None: ins[self.fs.rvstart:self.fs.rvend + 1] = [0] * (self.fs.rvend - self.fs.rvstart + 1) ins_nd = ins[loIdx:] ins[loIdx:] = [0] * (2**(self.nInBits - self.fs.ndb)) invals_nd.append(ins_nd) invals.extend(ins) # need to pad up to nCopies if we're not using an RDL if self.rdl is None: assert util.clog2(len(invals)) == self.nInBits + self.nCopyBits invals += [0] * (2**(self.nInBits + self.nCopyBits) - len(invals)) self.fs.put(invals, True) # commit to nondet inputs from prover nd_rvals = [] if self.fs.ndb is not None: loIdx = (2**self.nInBits) - (2**(self.nInBits - self.fs.ndb)) prefill = [0] * loIdx for nd in invals_nd: nd_rvals.extend(prefill + self.create_pok(nd)) if self.rdl is None: assert len(nd_rvals) == self.nCopies * (2**self.nInBits) nd_rvals += [0] * (2**(self.nInBits + self.nCopyBits) - len(nd_rvals)) else: assert len(nd_rvals) == 2**self.nInBits # now V sets r_values if necessary if self.fs.rvstart is not None and self.fs.rvend is not None: r_values = [ self.fs.rand_scalar() for _ in xrange(self.fs.rvstart, self.fs.rvend + 1) ] if self.rdl is None: assert len(inputs) == self.nCopies for inp in inputs: inp[self.fs.rvstart:self.fs.rvend + 1] = r_values else: assert len(inputs) == 1 inputs[0][self.fs.rvstart:self.fs.rvend + 1] = r_values if self.rdl is None: self.prover.set_inputs(inputs) else: assert len(inputs) == 1 rdl_inputs = [] nd_rvals_new = [] for r_ents in self.rdl: rdl_inputs.append([inputs[0][r_ent] for r_ent in r_ents]) nd_rvals_new.extend(nd_rvals[r_ent] for r_ent in r_ents) nd_rvals_new.extend( 0 for _ in xrange((2**self.nCktBits) - len(r_ents))) self.prover.set_inputs(rdl_inputs) nd_rvals = nd_rvals_new assert len(nd_rvals) == len(self.rdl) * 2**self.nCktBits # evaluate the AC and put the outputs in the transcript outvals = util.flatten(self.prover.ckt_outputs) nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(outvals)) == nOutBits + self.nCopyBits outvals += [0] * (2**(nOutBits + self.nCopyBits) - len(outvals)) self.fs.put(outvals, True) # generate random point in (z1, z2) \in F^{nOutBits + nCopyBits} z1 = [self.fs.rand_scalar() for _ in xrange(0, nOutBits)] z1_2 = None z2 = [self.fs.rand_scalar() for _ in xrange(0, self.nCopyBits)] if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) # to start, we reconcile with mlext of input prev_rval = None muls = None # if the AC has only one layer, tell P to give us H(.) project_line = len(self.in0vv) == 1 self.prover.set_z(z1, z2, None, None, project_line) ########################################## # 1. Interact with prover for each layer # ########################################## for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] w1 = [] w2 = [] w3 = [] if Defs.track_fArith: self.sc_a.did_rng(2 * nInBits + self.nCopyBits) ################### ### A. Sumcheck ### ################### for rd in xrange(0, 2 * nInBits + self.nCopyBits): # get output from prv and check against expected value outs = self.prover.get_outputs() # 1. commitments to each val in the transcript outs_rvals = self.create_pok(outs) # 2. prove equality of poly(0) + poly(1) to prev comm value (or out mlext) zp1_rval = (sum(outs_rvals) + outs_rvals[0]) % Defs.prime self.create_eq_proof(prev_rval, zp1_rval) if Defs.track_fArith: self.sc_a.did_add(len(outs_rvals)) # 3. compute new prev_rval and go to next round nrand = self.fs.rand_scalar() self.prover.next_round(nrand) # compute comm to eval of poly(.) that V will use prev_rval = util.horner_eval(outs_rvals, nrand, self.sc_a) if rd < self.nCopyBits: assert len(outs) == 4 w3.append(nrand) else: assert len(outs) == 3 if rd < self.nCopyBits + nInBits: w1.append(nrand) else: w2.append(nrand) ############################### ### B. Extend to next layer ### ############################### outs = self.prover.get_outputs() if project_line: assert len(outs) == 1 + nInBits assert lay == len(self.in0vv) - 1 # (1) commit to all values plus their sum # (2) figure out c2val, r2val from above and outs[0] com # (3) create prod com # (4) send PoK of product for outs[0], c2val, prod (outs_rvals, pr_rvals) = self.create_final_prod_pok(outs) else: # just need to do product PoK since we're sending tV(r1) and tV(r2) assert len(outs) == 2 pr_rvals = self.create_prod_pok(outs) # prove final value in mlext eval # need mlext evals to do PoK (mlext_evals, mlx_z2) = self.eval_mlext(lay, z1, z2, w1, w2, w3, z1_2, muls) # mul gate is special, rest are OK tV_rval = 0 for (idx, elm) in enumerate(mlext_evals): tV_rval += elm * GateFunctionsPC[idx](pr_rvals[0], pr_rvals[1], pr_rvals[2], self.tV_a) tV_rval %= Defs.prime tV_rval *= mlx_z2 tV_rval %= Defs.prime self.create_eq_proof(prev_rval, tV_rval) if Defs.track_fArith: self.tV_a.did_add(len(mlext_evals) - 1) self.tV_a.did_mul(len(mlext_evals) + 1) project_next = lay == len(self.in0vv) - 2 if project_line: tau = self.fs.rand_scalar() muls = None prev_rval = util.horner_eval(outs_rvals, tau) z1 = [(elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in izip(w1, w2)] z1_2 = None if Defs.track_fArith: self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) self.sc_a.did_rng() else: muls = [self.fs.rand_scalar(), self.fs.rand_scalar()] self.prover.next_layer(muls, project_next) tau = None prev_rval = (muls[0] * pr_rvals[0] + muls[1] * pr_rvals[1]) % Defs.prime z1 = w1 z1_2 = w2 if Defs.track_fArith: self.nlay_a.did_add() self.nlay_a.did_mul(2) self.sc_a.did_rng(2) project_line = project_next z2 = w3 ############################# # 2. Proof of eq with input # ############################# if nd_rvals: rval_mlext_eval = VerifierIOMLExt(z1 + z2, self.in_a).compute(nd_rvals) self.create_eq_proof(prev_rval, rval_mlext_eval) assert sum(val1 * val2 for (val1, val2) in izip(nd_rvals, invals)) == 0 else: self.create_eq_proof(None, prev_rval) ######################## # 3. Return transcript # ######################## return self.fs.to_string()
def run(self, pf, _=None): assert Defs.prime == self.com.gops.q self.fs = fs.FiatShamir.from_string(pf) assert Defs.prime == self.fs.q self.build_wcom(False) #### # 0. Get i/o #### # get inputs self.muxbits = self.fs.take(True) self.inputs = self.fs.take(True) # get witness commitments nd_cvals = None if self.fs.ndb is not None: nd_cvals = self.fs.take() # now generate rvals if self.fs.rvstart is not None and self.fs.rvend is not None: r_values = [ self.fs.rand_scalar() for _ in xrange(self.fs.rvstart, self.fs.rvend + 1) ] nCopies = 1 if self.rdl is None: nCopies = self.nCopies for idx in xrange(0, nCopies): first = idx * (2 ** self.nInBits) + self.fs.rvstart last = first + self.fs.rvend - self.fs.rvstart + 1 self.inputs[first:last] = r_values # finally, get outputs self.outputs = self.fs.take(True) #### # 1. mlext of outs #### nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(self.outputs)) == nOutBits + self.nCopyBits # z1 and z2 vals z1 = [ self.fs.rand_scalar() for _ in xrange(0, nOutBits) ] z1_2 = None z2 = [ self.fs.rand_scalar() for _ in xrange(0, self.nCopyBits) ] # instructions for P muls = None project_line = len(self.in0vv) == 1 expectNext = VerifierIOMLExt(z1 + z2, self.out_a).compute(self.outputs) prev_cval = self.com.gops.pow_g(expectNext) if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) self.com_p_a.did_exp() #### # 2. Simulate prover interactions #### for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] w1 = [] w2 = [] w3 = [] alphas = [] if Defs.track_fArith: self.sc_a.did_rng(2*nInBits + self.nCopyBits) #### # A. Sumcheck #### for rd in xrange(0, 2 * nInBits + self.nCopyBits): # take next alpha value from transcript alphas.append(self.com.decompress(self.fs.take()[0])) # generate new rand value nrand = self.fs.rand_scalar() if rd < self.nCopyBits: w3.append(nrand) elif rd < self.nCopyBits + nInBits: w1.append(nrand) else: w2.append(nrand) #### # B. Extend to next layer #### if project_line: assert lay == len(self.in0vv) - 1 (cvals, c2val, c3val, is_ok) = self.check_final_prod_pok(nInBits) if not is_ok: raise RuntimeError("Verification of final product PoK failed") pr_cvals = (cvals[0], c2val, c3val) else: (pr_cvals, is_ok) = self.check_prod_pok() if not is_ok: raise RuntimeError("Verification of product PoK failed in layer %d" % lay) # get delvals from proof delvals = [ self.com.decompress(delval) for delval in self.fs.take() ] # generate vector of J values j1val = self.fs.rand_scalar() jvals = [ self.fs.rand_scalar() for _ in xrange(0, 2 * nInBits + self.nCopyBits) ] # compute Jvec Jvec = _compute_Jvec(j1val, jvals, w3 + w1 + w2, self.nCopyBits, nInBits, False, self.com_q_a) Cval = self.com.decompress(self.fs.take()[0]) # mlext eval (mlext_evals, mlx_z2) = self.eval_mlext(lay, z1, z2, w1, w2, w3, z1_2, muls) xyzvals = [0, 0, 0, 0] for (idx, elm) in enumerate(mlext_evals): GateFunctionsPVC[idx](elm, jvals[-1], xyzvals, self.tV_a) xyzvals = [ (mlx_z2 * v) % Defs.prime for v in xyzvals ] # generate challenge and take zvals from transcript chal = self.fs.rand_scalar() zvals = self.fs.take()[0] if Defs.track_fArith: self.com_q_a.did_rng(2*nInBits + self.nCopyBits + 1) self.tV_a.did_mul(len(xyzvals)) self.com_q_a.did_rng() # check vector PoK is_ok = self.com.vecpok_check_lay(alphas, delvals, zvals, Cval, prev_cval, pr_cvals, Jvec, j1val, xyzvals, chal) if not is_ok: raise ValueError("Sumcheck verification failed at layer %d" % lay) project_next = (lay == len(self.in0vv) - 2) and (self.rdl is None) if project_line: tau = self.fs.rand_scalar() muls = None prev_cval = self.com.horner_eval(cvals, tau) z1 = [ (elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in izip(w1, w2) ] z1_2 = None if Defs.track_fArith: self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) self.sc_a.did_rng() else: muls = [self.fs.rand_scalar(), self.fs.rand_scalar()] tau = None prev_cval = self.com.muls_eval(pr_cvals, muls) z1 = w1 z1_2 = w2 if Defs.track_fArith: self.sc_a.did_rng(2) project_line = project_next z2 = w3 #### # 2.5. do RDL if necessary #### if self.rdl is not None: w1 = [] alphas = [] if Defs.track_fArith: self.rdl_sc_a.did_rng(self.nInBits) #### # sumcheck for RDL #### for _ in xrange(0, self.nInBits): # take next val from transcript alphas.append(self.com.decompress(self.fs.take()[0])) # generate new rand value w1.append(self.fs.rand_scalar()) # get PoK for V0 val (pr_cvals, is_ok) = self.check_pok(1) if not is_ok: raise ValueError("Verification of V0 PoK failed in RDL") # get delvals from proof delvals = [ self.com.decompress(delval) for delval in self.fs.take() ] # generate vector of J values j1val = self.fs.rand_scalar() jvals = [ self.fs.rand_scalar() for _ in xrange(0, self.nInBits) ] # compute Jvec Jvec = _compute_Jvec(j1val, jvals, w1, 0, self.nInBits, True, self.com_q_a) Cval = self.com.decompress(self.fs.take()[0]) # mlext eval mlext_pass = self.eval_mlext_pass(z1, z1_2, z2, w1, muls) xyzvals = [(mlext_pass * jvals[-1]) % Defs.prime] # generate challenge and take zvals from transcript chal = self.fs.rand_scalar() zvals = self.fs.take()[0] if Defs.track_fArith: self.com_q_a.did_rng(self.nInBits + 1) self.tP_a.did_mul() self.com_q_a.did_rng() # check vector PoK is_ok = self.com.vecpok_check_rdl(alphas, delvals, zvals, Cval, prev_cval, pr_cvals, Jvec, j1val, xyzvals, chal) if not is_ok: raise ValueError("Sumcheck verification failed for RDL") # get variables right for finishing muls = None tau = None prev_cval = pr_cvals[0] z1 = w1 z1_2 = None z2 = [] #### # 3. mlext of inputs #### if self.rdl is None: input_mlext_eval = VerifierIOMLExt(z1 + z2, self.in_a).compute(self.inputs) else: # we can reuse evaluation of compute_betas(w1) from eval_mlext_pass input_mlext_eval = sum( 0 if inp == 0 else inp * mle % Defs.prime for (inp, mle) in izip(self.inputs, self.mlx_w1) ) % Defs.prime if Defs.track_fArith: nvals = sum( 1 if x != 0 else 0 for x in self.inputs ) self.in_a.did_add(nvals-1) self.in_a.did_mul(nvals) if nd_cvals is None: is_ok = self.check_val_proof(prev_cval, input_mlext_eval) else: r0val = reduce(lambda x, y: (x * y) % Defs.prime, z1[len(z1)-self.fs.ndb:], 1) rvals = z1[:len(z1)-self.fs.ndb] + z2 is_ok = self.check_witness(nd_cvals, rvals, r0val, prev_cval, input_mlext_eval) if Defs.track_fArith: self.com_q_a.did_mul(self.fs.ndb) if not is_ok: raise ValueError("Verification failed checking input mlext")
def set_rdl(self, rdl, nRDLInputs): self.nInputs = nRDLInputs self.nCktBits = self.nInBits self.nInBits = util.clog2(nRDLInputs) assert len(rdl) == self.nCopies self.rdl = rdl
def main(): uStr = get_usage() oStr = "c:i:p:n:g:o:v:C:Pz:Tr:R:L:w:" try: (opts, args) = getopt.getopt(sys.argv[1:], oStr) except getopt.GetoptError as err: print uStr print str(err) sys.exit(1) if args: print uStr print "ERROR: extraneous arguments." sys.exit(1) for (opt, arg) in opts: if opt == "-c": if arg[0] == "=": nC = int(arg[1:]) nCB = util.clog2(nC) else: nCB = int(arg) nC = 1 << nCB VerifierInfo.nCopyBits = nCB VerifierInfo.nCopies = nC elif opt == "-i": VerifierInfo.inputFile = arg elif opt == "-p": VerifierInfo.pwsFile = arg elif opt == "-r": VerifierInfo.rdlFile = arg elif opt == "-n": VerifierInfo.ndBits = int(arg) elif opt == "-R": (VerifierInfo.rvStart, VerifierInfo.rvEnd) = [int(x) for x in arg.split(',')] elif opt == "-g": arg_ns = {} try: execfile(arg, arg_ns) VerifierInfo.ndGen = staticmethod(arg_ns['nondet_gen']) except IOError: print uStr print "ERROR: Could not open file %s" % arg sys.exit(1) except NameError: print uStr print "ERROR: Could not find nondet_gen function in file %s" % arg sys.exit(1) elif opt == "-v": VerifierInfo.vProofFile = arg elif opt == "-o": VerifierInfo.pProofFile = arg elif opt == "-C": VerifierInfo.curve = arg elif opt == "-P": VerifierInfo.curve = None elif opt == "-z": arg = int(arg) if arg == 0: VerifierInfo.proofType = libfennel.circuitni elif arg == 1: VerifierInfo.proofType = libfennel.circuitnizk elif arg == 2: raise ValueError("circuitnizkvec no longer exists") elif arg == 3: VerifierInfo.proofType = libfennel.circuitnizkvecwit else: assert False, "got '-z %s', expected 0, 1, or 2" % arg if arg != 3: VerifierInfo.witnessDiv = None elif opt == "-T": VerifierInfo.showPerf = True elif opt == "-L": VerifierInfo.logFile = arg elif opt == "-w": if arg == '1': VerifierInfo.witnessDiv = None else: VerifierInfo.witnessDiv = float(arg) else: assert False, "logic error: got unexpected option %s from getopt" % opt if VerifierInfo.pwsFile is None: print uStr print "ERROR: missing required argument, -p <pwsFile>." sys.exit(1) if VerifierInfo.nCopyBits < 1: print uStr print "ERROR: nCopyBits must be at least 1." sys.exit(1) if VerifierInfo.vProofFile is not None and VerifierInfo.pProofFile is not None: print uStr print "ERROR: only one of -o and -v can be supplied." sys.exit(1) if VerifierInfo.witnessDiv is not None: if VerifierInfo.proofType is not libfennel.circuitnizkvecwit: print "WARNING: -w can only be specified for -z 3. Ignoring." VerifierInfo.witnessDiv = None run_fennel(VerifierInfo) VerifierInfo.Log.log( "Prover runtime: %f" % (VerifierInfo.pEndTime - VerifierInfo.pStartTime), VerifierInfo.showPerf) VerifierInfo.Log.log( "Verifier runtime: %f" % (VerifierInfo.vEndTime - VerifierInfo.vStartTime), VerifierInfo.showPerf) VerifierInfo.Log.log( "Max memory usage: %d kB" % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss, VerifierInfo.showPerf) if VerifierInfo.logFile is not None: with open(VerifierInfo.logFile, 'w') as fh: fh.writelines(VerifierInfo.Log.get_lines())
def run_fennel(verifier_info): # set curve and prime Defs.curve = verifier_info.curve util.set_prime(libfennel.commit.MiraclEC.get_order(Defs.curve)) # pylint doesn't seed to understand how classmethods are inherited from metclasses p_from_pws = verifier_info.proofType.ProverClass.from_pws # pylint: disable=no-member v_from_pws = verifier_info.proofType.VerifierClass.from_pws # pylint: disable=no-member pFile = pypws.parse_pws(verifier_info.pwsFile, str(Defs.prime)) # handle RDL if verifier_info.rdlFile is not None: rFile = pypws.parse_pws_unopt(verifier_info.rdlFile, str(Defs.prime)) (r_input_layer, rdl_map) = libfennel.parse_pws.parse_rdl(rFile, verifier_info.nCopies, pFile[0]) # either generate or read in proof if verifier_info.vProofFile is None: (input_layer, prv) = p_from_pws(pFile, verifier_info.nCopies) prv.build_prover() # set up RDL if verifier_info.rdlFile is not None: inputs = get_inputs(verifier_info, r_input_layer) prv.set_rdl(rdl_map, len(r_input_layer)) else: inputs = get_inputs(verifier_info, input_layer) # handle nondeterminism options if verifier_info.ndBits is not None: prv.set_nondet_range(verifier_info.ndBits) if verifier_info.ndGen is not None: prv.set_nondet_gen(verifier_info.ndGen) if verifier_info.rvStart is not None and verifier_info.rvEnd is not None: prv.set_rval_range(verifier_info.rvStart, verifier_info.rvEnd) if verifier_info.witnessDiv is not None: prv.set_wdiv(verifier_info.witnessDiv) verifier_info.pStartTime = time.time() proof = prv.run(inputs) verifier_info.pEndTime = time.time() else: with open(verifier_info.vProofFile, 'r') as fh: proof = bz2.decompress(fh.read()) verifier_info.Log.log( "Proof size: %d elems, %d bytes" % FiatShamir.proof_size(proof), True) # either verify or write out proof if verifier_info.pProofFile is None: (_, ver) = v_from_pws(pFile, verifier_info.nCopies) # set up RDL if verifier_info.rdlFile is not None: ver.set_rdl(rdl_map, len(r_input_layer)) verifier_info.vStartTime = time.time() try: ver.run(proof) except Exception as e: # pylint: disable=broad-except verifier_info.Log.log("Verification failed: %s" % e, True) verifier_info.Log.log(traceback.format_exc(), True) else: verifier_info.Log.log("Verification succeeded.", True) verifier_info.vEndTime = time.time() else: with open(verifier_info.pProofFile, 'w') as fh: fh.write(bz2.compress(proof)) nInBits = util.clog2(len(input_layer)) if verifier_info.rdlFile is not None: nInBits = util.clog2(len(r_input_layer)) nCopies = verifier_info.nCopies nLayers = len(ver.in0vv) + 1 if verifier_info.rdlFile is not None else 0 verifier_info.Log.log( "nInBits: %d, nCopies: %d, nLayers: %d" % (nInBits, nCopies, nLayers), verifier_info.showPerf) if Defs.track_fArith: verifier_info.Log.log(str(Defs.fArith()), verifier_info.showPerf)
# first, let's do powers of g, which is just WR^x = x * yIZWR pow_g = ((x * yv) % Defs.prime for yv in self.yIZWR) # For h', we have x * ZWL + ZWO - Ypows, where h' = h ^ YIpows # thus, to the base h we have (x * ZWL + ZWO - Ypows) * YIpows = (x * ZWL + ZWO) * YIpows - 1 comp_h = lambda lv, ov, iv: ((( (x * lv) % Defs.prime) + ov) * iv - 1) % Defs.prime pow_h = (comp_h(lv, ov, iv) for (lv, ov, iv) in izip(self.ZWL, self.ZWO, self.YIpows)) # we're going to run an inner-product argument on # g_vec, h'_vec, g, P h^-mu, t # to use Bulletproofs Protocol #1, we convert this statement to # g_vec, h'_vec, g^xIP, P h^-mu g^(xIP t) # here, we only compute part of P h^-mu g^(xIP t); we wait to compute the rest until the very end nRnd = 2**util.clog2(self.n) self.P = self.gops.pow_gih( chain(pow_g, repeat(0, nRnd - self.n), pow_h), Defs.prime - mu, 0, nRnd + self.n) # get ready for inner product arg Xpows[2] = x2 Xpows[4] = (tEval * xIP) % Defs.prime self.Xpows = Xpows[:5] self.xIP = xIP self.cvals = [] self.LRvals = [] self.nbits = util.clog2(self.n) if self.n != 2**self.nbits: self.n = 2**self.nbits self.extend_yipows()
def run(self, inputs, muxbits=None): self.build_prover() self.prover_fresh = False ############ # 0. Setup # ############ assert self.prover is not None # set muxbits self.muxbits = muxbits if muxbits is not None: self.prover.set_muxbits(muxbits) # set inputs and outputs self.prover.set_inputs(inputs) self.inputs = [] for ins in inputs: self.inputs.extend(ins + [0] * (2**self.nInBits - len(ins))) # pad to power-of-2 number of copies assert util.clog2(len(self.inputs)) == self.nInBits + self.nCopyBits self.inputs += [0] * (2 ** (self.nInBits + self.nCopyBits) - len(self.inputs)) ############################################### # 1. Compute multilinear extension of outputs # ############################################### self.outputs = util.flatten(self.prover.ckt_outputs) nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(self.outputs)) == nOutBits + self.nCopyBits # pad out to power-of-2 number of copies self.outputs += [0] * (2 ** (nOutBits + self.nCopyBits) - len(self.outputs)) # generate random point in (z1, z2) \in F^{nOutBits + nCopyBits} z1 = [ Defs.gen_random() for _ in xrange(0, nOutBits) ] z1_2 = None z2 = [ Defs.gen_random() for _ in xrange(0, self.nCopyBits) ] if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) # if the AC has only one layer, tell P to give us H(.) muls = None project_line = len(self.in0vv) == 1 self.prover.set_z(z1, z2, None, None, project_line) # eval mlext of output at (z1,z2) expectNext = VerifierIOMLExt(z1 + z2, self.out_a).compute(self.outputs) ########################################## # 2. Interact with prover for each layer # ########################################## for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] # random coins for this round w3 = [ Defs.gen_random() for _ in xrange(0, self.nCopyBits) ] w1 = [ Defs.gen_random() for _ in xrange(0, nInBits) ] w2 = [ Defs.gen_random() for _ in xrange(0, nInBits) ] if Defs.track_fArith: self.sc_a.did_rng(2*nInBits + self.nCopyBits) # convenience ws = w3 + w1 + w2 ################### ### A. Sumcheck ### ################### for rd in xrange(0, 2 * nInBits + self.nCopyBits): # get output from prv and check against expected value outs = self.prover.get_outputs() gotVal = (outs[0] + sum(outs)) % Defs.prime if Defs.track_fArith: self.sc_a.did_add(len(outs)) assert expectNext == gotVal, "Verification failed in round %d of layer %d" % (rd, lay) # go to next round self.prover.next_round(ws[rd]) expectNext = util.horner_eval(outs, ws[rd], self.sc_a) outs = self.prover.get_outputs() if project_line: v1 = outs[0] % Defs.prime v2 = sum(outs) % Defs.prime if Defs.track_fArith: self.tV_a.did_add(len(outs)-1) else: assert len(outs) == 2 v1 = outs[0] v2 = outs[1] ############################################ ### B. Evaluate mlext of wiring predicates # ############################################ tV_eval = self.eval_tV(lay, z1, z2, w1, w2, w3, v1, v2, z1_2 is not None, muls) # check that we got the correct value from the last round of the sumcheck assert expectNext == tV_eval, "Verification failed computing tV for layer %d" % lay ############################### ### C. Extend to next layer ### ############################### project_next = lay == len(self.in0vv) - 2 if project_line: tau = Defs.gen_random() muls = None expectNext = util.horner_eval(outs, tau, self.nlay_a) # z1 = w1 + ( w2 - w1 ) * tau z1 = [ (elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in izip(w1, w2) ] z1_2 = None if Defs.track_fArith: self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) self.sc_a.did_rng() else: muls = (Defs.gen_random(), Defs.gen_random()) tau = None expectNext = ( muls[0] * v1 + muls[1] * v2 ) % Defs.prime self.prover.next_layer(muls, project_next) z1 = w1 z1_2 = w2 if Defs.track_fArith: self.nlay_a.did_add() self.nlay_a.did_mul(2) self.sc_a.did_rng(2) project_line = project_next z2 = w3 ############################################## # 3. Compute multilinear extension of inputs # ############################################## # Finally, evaluate mlext of input at z1, z2 input_mlext = VerifierIOMLExt(z1 + z2, self.in_a) input_mlext_eval = input_mlext.compute(self.inputs) assert input_mlext_eval == expectNext, "Verification failed checking input mlext"
def run(self, inputs, muxbits=None): self.build_prover() self.prover_fresh = False ###################### # 0. Run computation # ###################### assert self.prover is not None # set muxbits and dump into transcript if muxbits is not None: self.prover.set_muxbits(muxbits) self.fs.put(muxbits, True) # run AC, then dump inputs and outputs into the transcript self.prover.set_inputs(inputs) invals = [] for ins in inputs: invals.extend(ins + [0] * (2**self.nInBits - len(ins))) assert util.clog2(len(invals)) == self.nInBits + self.nCopyBits invals += [0] * (2 ** (self.nInBits + self.nCopyBits) - len(invals)) self.fs.put(invals, True) outvals = util.flatten(self.prover.ckt_outputs) nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(outvals)) == nOutBits + self.nCopyBits outvals += [0] * (2 ** (nOutBits + self.nCopyBits) - len(outvals)) self.fs.put(outvals, True) # generate random point in (z1, z2) \in F^{nOutBits + nCopyBits} z1 = [ self.fs.rand_scalar() for _ in xrange(0, nOutBits) ] z2 = [ self.fs.rand_scalar() for _ in xrange(0, self.nCopyBits) ] if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) # if the AC has only one layer, tell P to give us H(.) muls = None project_line = len(self.in0vv) == 1 self.prover.set_z(z1, z2, None, None, project_line) ########################################## # 1. Interact with prover for each layer # ########################################## for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] if Defs.track_fArith: self.sc_a.did_rng(2*nInBits + self.nCopyBits) ################### ### A. Sumcheck ### ################### for rd in xrange(0, 2 * nInBits + self.nCopyBits): # get output from prv and check against expected value outs = self.prover.get_outputs() self.fs.put(outs) if rd < self.nCopyBits: assert len(outs) == 4 else: assert len(outs) == 3 # go to next round self.prover.next_round(self.fs.rand_scalar()) outs = self.prover.get_outputs() self.fs.put(outs) if project_line: assert len(outs) == 1 + nInBits else: assert len(outs) == 2 ############################### ### B. Extend to next layer ### ############################### project_next = lay == len(self.in0vv) - 2 if not project_line: muls = [self.fs.rand_scalar(), self.fs.rand_scalar()] self.prover.next_layer(muls, project_next) if Defs.track_fArith: self.sc_a.did_rng(2) project_line = project_next ######################## # 2. Return transcript # ######################## return self.fs.to_string()
def run(self, pf, _=None): # pylint: disable=arguments-differ self.fs = fs.FiatShamir.from_string(pf) #### # 0. Get i/o #### self.muxbits = self.fs.take(True) self.inputs = self.fs.take(True) self.outputs = self.fs.take(True) #### # 1. mlext of outs #### nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(self.outputs)) == nOutBits + self.nCopyBits # z1 and z2 vals z1 = [ self.fs.rand_scalar() for _ in xrange(0, nOutBits) ] z1_2 = None z2 = [ self.fs.rand_scalar() for _ in xrange(0, self.nCopyBits) ] if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) # instructions for P muls = None project_line = len(self.in0vv) == 1 expectNext = VerifierIOMLExt(z1 + z2, self.out_a).compute(self.outputs) #### # 2. Simulate prover interactions #### for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] w1 = [] w2 = [] w3 = [] if Defs.track_fArith: self.sc_a.did_rng(2*nInBits + self.nCopyBits) #### # A. Sumcheck #### for rd in xrange(0, 2 * nInBits + self.nCopyBits): outs = self.fs.take() gotVal = (outs[0] + sum(outs)) % Defs.prime if Defs.track_fArith: self.sc_a.did_add(len(outs)) assert expectNext == gotVal, "Verification failed in round %d of layer %d" % (rd, lay) nrand = self.fs.rand_scalar() expectNext = util.horner_eval(outs, nrand, self.sc_a) if rd < self.nCopyBits: assert len(outs) == 4 w3.append(nrand) else: assert len(outs) == 3 if rd < self.nCopyBits + nInBits: w1.append(nrand) else: w2.append(nrand) outs = self.fs.take() if project_line: assert len(outs) == 1 + nInBits v1 = outs[0] % Defs.prime v2 = sum(outs) % Defs.prime if Defs.track_fArith: self.tV_a.did_add(len(outs)-1) else: assert len(outs) == 2 v1 = outs[0] v2 = outs[1] #### # B. mlext of wiring predicate #### tV_eval = self.eval_tV(lay, z1, z2, w1, w2, w3, v1, v2, z1_2, muls) assert expectNext == tV_eval, "Verification failed computing tV for layer %d" % lay #### # C. Extend to next layer #### project_next = lay == len(self.in0vv) - 2 if project_line: tau = self.fs.rand_scalar() muls = None expectNext = util.horner_eval(outs, tau, self.nlay_a) # z1 = w1 + ( w2 - w1 ) * tau z1 = [ (elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in izip(w1, w2) ] z1_2 = None if Defs.track_fArith: self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) self.sc_a.did_rng() else: muls = [self.fs.rand_scalar(), self.fs.rand_scalar()] tau = None expectNext = ( muls[0] * v1 + muls[1] * v2 ) % Defs.prime z1 = w1 z1_2 = w2 if Defs.track_fArith: self.nlay_a.did_add() self.nlay_a.did_mul(2) self.sc_a.did_rng(2) project_line = project_next z2 = w3 #### # 3. mlext of inputs #### input_mlext_eval = VerifierIOMLExt(z1 + z2, self.in_a).compute(self.inputs) assert input_mlext_eval == expectNext, "Verification failed checking input mlext"
def __init__(self, nCopies): self.nCopies = nCopies self.nCopyBits = util.clog2(nCopies) self.muxbits = [0]
self.cvals[:idx] + self.cvals[idx + 1:], cprodinv)) # compute powers for multiexps azpows = [c] + [ (c * cval) % self.gops.q for cval in chain.from_iterable(izip(cinvs, self.cvals)) ] gpows = [(cprodinv * cprodinv) % self.gops.q] for cval in self.cvals: new = [] for gpow in gpows: new.extend([(gpow * cval) % self.gops.q, gpow]) gpows = new # compute bvals stopbits = util.clog2(self.stoplen) bvinit = (VerifierIOMLExt(self.rvals[stopbits:], self.com.rec_q).compute(gpows) * self.r0val) % self.gops.q bvals = VerifierIOMLExt.compute_beta(self.rvals[:stopbits], self.com.rec_q, bvinit) # now compute the check values themselves gvals = [ self.gops.pow_gi(gpows, idx, self.stoplen) for idx in xrange(0, self.stoplen) ] lhs1 = self.gops.multiexp(self.Avals + [delta], azpows + [1]) rhs1 = self.gops.multiexp(gvals + [self.gops.h], zvals + [zdelta]) prod_bz = sum(util.mul_vecs(bvals, zvals,
def run(self, pf, _=None): # pylint: disable=arguments-differ assert Defs.prime == self.com.gops.q self.fs = fs.FiatShamir.from_string(pf) assert Defs.prime == self.fs.q #### # 0. Get i/o #### self.muxbits = self.fs.take(True) self.inputs = self.fs.take(True) # get witness commitments nd_cvals = [] if self.fs.ndb is not None: num_vals = 2**(self.nInBits - self.fs.ndb) nCopies = 1 if self.rdl is None: nCopies = self.nCopies for copy in xrange(0, nCopies): (cvals, is_ok) = self.check_pok(num_vals) if not is_ok: raise ValueError( "Failed getting commitments to input for copy %d" % copy) if self.rdl is None: nd_cvals.append(cvals) else: nd_cvals.extend(cvals) # now generate rvals if self.fs.rvstart is not None and self.fs.rvend is not None: r_values = [ self.fs.rand_scalar() for _ in xrange(self.fs.rvstart, self.fs.rvend + 1) ] nCopies = 1 if self.rdl is None: nCopies = self.nCopies for idx in xrange(0, nCopies): first = idx * (2**self.nInBits) + self.fs.rvstart last = first + self.fs.rvend - self.fs.rvstart + 1 self.inputs[first:last] = r_values # finally, get outputs self.outputs = self.fs.take(True) #### # 1. mlext of outs #### nOutBits = util.clog2(len(self.in0vv[-1])) assert util.clog2(len(self.outputs)) == nOutBits + self.nCopyBits # z1 and z2 vals z1 = [self.fs.rand_scalar() for _ in xrange(0, nOutBits)] z1_2 = None z2 = [self.fs.rand_scalar() for _ in xrange(0, self.nCopyBits)] if Defs.track_fArith: self.sc_a.did_rng(nOutBits + self.nCopyBits) # instructions for P muls = None project_line = len(self.in0vv) == 1 expectNext = VerifierIOMLExt(z1 + z2, self.out_a).compute(self.outputs) prev_cval = None #### # 2. Simulate prover interactions #### for lay in xrange(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] w1 = [] w2 = [] w3 = [] if Defs.track_fArith: self.sc_a.did_rng(2 * nInBits + self.nCopyBits) #### # A. Sumcheck #### for rd in xrange(0, 2 * nInBits + self.nCopyBits): if rd < self.nCopyBits: nelms = 4 else: nelms = 3 (cvals, is_ok) = self.check_pok(nelms) if not is_ok: raise ValueError( "PoK failed for commits in round %d of layer %d" % (rd, lay)) ncom = self.com.zero_plus_one_eval(cvals) if prev_cval is None: is_ok = self.check_val_proof(ncom, expectNext) else: is_ok = self.check_eq_proof(prev_cval, ncom) if not is_ok: raise ValueError( "Verification failed in round %d of layer %d" % (rd, lay)) nrand = self.fs.rand_scalar() prev_cval = self.com.horner_eval(cvals, nrand) if rd < self.nCopyBits: w3.append(nrand) elif rd < self.nCopyBits + nInBits: w1.append(nrand) else: w2.append(nrand) #### # B. Extend to next layer #### if project_line: assert lay == len(self.in0vv) - 1 (cvals, c2val, c3val, is_ok) = self.check_final_prod_pok(nInBits) if not is_ok: raise ValueError( "Verification of final product PoK failed") pr_cvals = (cvals[0], c2val, c3val) else: (pr_cvals, is_ok) = self.check_prod_pok() if not is_ok: raise ValueError( "Verification of product PoK failed in layer %d" % lay) # check final val with mlext eval (mlext_evals, mlx_z2) = self.eval_mlext(lay, z1, z2, w1, w2, w3, z1_2, muls) tV_cval = self.com.tV_eval(pr_cvals, mlext_evals, mlx_z2) is_ok = self.check_eq_proof(prev_cval, tV_cval) if not is_ok: raise ValueError( "Verification of mlext eq proof failed in layer %d" % lay) project_next = lay == len(self.in0vv) - 2 if project_line: tau = self.fs.rand_scalar() muls = None prev_cval = self.com.horner_eval(cvals, tau) z1 = [(elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in izip(w1, w2)] z1_2 = None if Defs.track_fArith: self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) self.sc_a.did_rng() else: muls = [self.fs.rand_scalar(), self.fs.rand_scalar()] tau = None prev_cval = self.com.muls_eval(pr_cvals, muls) z1 = w1 z1_2 = w2 if Defs.track_fArith: self.sc_a.did_rng(2) project_line = project_next z2 = w3 #### # 3. mlext of inputs #### if self.rdl is None: fin_inputs = self.inputs else: fin_inputs = [] for r_ents in self.rdl: fin_inputs.extend(self.inputs[r_ent] for r_ent in r_ents) input_mlext_eval = VerifierIOMLExt(z1 + z2, self.in_a).compute(fin_inputs) if len(nd_cvals) is 0 or self.fs.ndb is None: is_ok = self.check_val_proof(prev_cval, input_mlext_eval) elif self.rdl is None: copy_vals = VerifierIOMLExt.compute_beta(z2, self.in_a) loIdx = (2**self.nInBits) - (2**(self.nInBits - self.fs.ndb)) hiIdx = (2**self.nInBits) - 1 gate_vals = VerifierIOMLExt.compute_beta(z1, self.in_a, 1, loIdx, hiIdx) num_nd = 2**(self.nInBits - self.fs.ndb) cval_acc = self.com.accum_init(input_mlext_eval) for (cidx, vals) in enumerate(nd_cvals): copy_mul = copy_vals[cidx] assert len(vals) == num_nd for (gidx, val) in enumerate(vals, start=loIdx): exp = (copy_mul * gate_vals[gidx]) % Defs.prime cval_acc = self.com.accum_add(cval_acc, val, exp) if Defs.track_fArith: self.com_q_a.did_mul(len(vals)) fin_cval = self.com.accum_finish(cval_acc) is_ok = self.check_eq_proof(prev_cval, fin_cval) else: beta_vals = VerifierIOMLExt.compute_beta(z1 + z2, self.in_a) loIdx = (2**self.nInBits) - (2**(self.nInBits - self.fs.ndb)) perCkt = 2**self.nCktBits nd_cvals.append(self.com.gops.g) exps = [0] * len(nd_cvals) exps[-1] = input_mlext_eval for (cidx, r_ents) in enumerate(self.rdl): for (gidx, r_ent) in enumerate(r_ents): if r_ent >= loIdx: exps[r_ent - loIdx] += beta_vals[cidx * perCkt + gidx] exps[r_ent - loIdx] %= Defs.prime fin_cval = self.com.gops.multiexp(nd_cvals, exps) is_ok = self.check_eq_proof(prev_cval, fin_cval) if not is_ok: raise ValueError("Verification failed checking input mlext")