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.prover = None self.in0vv = in0vv self.in1vv = in1vv self.typvv = typvv self.muxvv = muxvv self.muxbits = None self.inputs = [] self.outputs = [] fArith = FArith() self.in_a = fArith.new_cat("v_in") self.out_a = fArith.new_cat("v_out") self.sc_a = fArith.new_cat("v_sc") self.tV_a = fArith.new_cat("v_tv") self.nlay_a = fArith.new_cat("v_nlay") # 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.nCopies = nCopies self.nCopyBits = util.clog2(nCopies) self.nInBits = util.clog2(nInputs) self.ckt_inputs = [] self.ckt_outputs = [] self.muxbits = [] self.layerNum = 0 self.roundNum = 0 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) # build circuit and provers layer-by-layer self.layers = [InputLayer(self.nInBits)] self.arith_circuit = ArithCircuitBuilder(nCopies, nInputs, in0vv, in1vv, typevv, muxvv) self.arith_circuit.set_muxbits(self.muxbits) for (lay, (in0v, in1v, muxv, typev)) in enumerate(zip(in0vv, in1vv, muxvv, typevv)): # layer prover self.layers.append( LayerProver(self.layers[lay], self, in0v, in1v, typev, muxv))
def run_giraffe(verifier_info): # pylint doesn't seed to understand how classmethods are inherited from metclasses from_pws = cver.CircuitVerifier.from_pws # pylint: disable=no-member (input_layer, ver) = from_pws(pypws.parse_pws(verifier_info.pwsFile), verifier_info.nCopies) ver.build_prover() inputs = get_inputs(verifier_info, input_layer) ver.run(inputs) nInBits = util.clog2(len(input_layer)) nCopies = VerifierInfo.nCopies nLayers = len(ver.in0vv) print "nInBits: %d, nCopies: %d, nLayers: %d" % (nInBits, nCopies, nLayers) (tMul, tAdd, tSub) = (0, 0, 0) for fArith in [ver.in_a, ver.out_a, ver.sc_a, ver.tV_a, ver.nlay_a]: (mul, add, sub) = fArith.get_counts() tMul += mul tAdd += add tSub += sub print " %s: %d mul, %d add, %d sub" % (fArith.cat, mul, add, sub) print " TOTAL: %d mul, %d add, %d sub" % (tMul, tAdd, tSub) lcosts = ver.local_costs() print " LOCAL: %d mul, %d add, %d sub" % (lcosts.get( 'mul', 0), lcosts.get('add', 0), lcosts.get('sub', 0))
def __init__(self, prevL, circuit, in0v, in1v, typev, muxv=None): # pylint: disable=protected-access self.prevL = prevL self.circuit = circuit self.nOutBits = util.clog2(len(in0v)) self.roundNum = 0 self.compute_v = [] self.inputs = [] self.output = [] self.z2_save = [] 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) # beta computation subckt self.compute_beta = LayerComputeBeta(self.circuit.nCopyBits) # z1chi computation subckt # this just takes advantage of the code in LayerComputeBeta # that does the dynamic-programming computation self.compute_z1chi = LayerComputeBeta(self.nOutBits) # v circuits are per-input---we collapse inputs in first nCopyBits rounds for _ in range(0, 2**self.prevL.nOutBits): lcv_tmp = LayerComputeV(self.circuit.nCopyBits) # 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.prevL.nOutBits) 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(zip(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 self.circuit.muxbits += [0] * (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 range(0, nCopies): out.append( [Defs.gen_random() if elm is None else elm for elm in inLay]) return out
def run(self, inputs, muxbits=None): ############ # 0. Setup # ############ assert self.prover is not None # 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))) self.outputs = util.flatten(self.prover.ckt_outputs) # set muxbits self.muxbits = muxbits if muxbits is not None: self.prover.set_muxbits(muxbits) ############################################### # 1. Compute multilinear extension of 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 range(0, nOutBits)] z2 = [Defs.gen_random() for _ in range(0, self.nCopyBits)] self.prover.set_z(z1, z2) # eval mlext of output at (z1,z2) output_mlext = VerifierIOMLExt(z1 + z2, self.out_a) expectNext = output_mlext.compute(self.outputs) ########################################## # 2. Interact with prover for each layer # ########################################## for lay in range(0, len(self.in0vv)): nInBits = self.layInBits[lay] nOutBits = self.layOutBits[lay] # random coins for this round w3 = [Defs.gen_random() for _ in range(0, self.nCopyBits)] w1 = [Defs.gen_random() for _ in range(0, nInBits)] w2 = [Defs.gen_random() for _ in range(0, nInBits)] # convenience ws = w3 + w1 + w2 ################### ### A. Sumcheck ### ################### for rd in range(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 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() v1 = outs[0] % Defs.prime v2 = sum(outs) % Defs.prime self.tV_a.did_add(len(outs) - 1) ############################################ ### B. Evaluate mlext of wiring predicates # ############################################ tV_eval = self.eval_mlext(lay, z1, z2, w1, w2, w3, v1, v2) # 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 ### ############################### tau = Defs.gen_random() if lay < len(self.in0vv) - 1: self.prover.next_layer(tau) expectNext = util.horner_eval(outs, tau, self.nlay_a) # next z values # z1 = w1 + ( w2 - w1 ) * tau; z2 is just w3 z1 = [(elm1 + (elm2 - elm1) * tau) % Defs.prime for (elm1, elm2) in zip(w1, w2)] self.nlay_a.did_sub(len(w1)) self.nlay_a.did_mul(len(w1)) self.nlay_a.did_add(len(w1)) z2 = w3 ############################################## # 3. Compute multilinear extension of inputs # ############################################## # Finally, evaluate mlext of input at z1, z2 assert util.clog2(len(self.inputs)) == self.nInBits + self.nCopyBits self.inputs += [0] * (2**(self.nInBits + self.nCopyBits) - len(self.inputs)) 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 __init__(self, nCopies): self.nCopies = nCopies self.nCopyBits = util.clog2(nCopies) self.muxbits = []