Exemple #1
0
    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]
        ]
Exemple #2
0
    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
Exemple #3
0
    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]
Exemple #4
0
 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))
Exemple #6
0
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
Exemple #7
0
    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,")
Exemple #8
0
    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))
Exemple #9
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)
Exemple #10
0
    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
Exemple #11
0
    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)
Exemple #12
0
    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)
Exemple #13
0
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()
Exemple #15
0
    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
Exemple #18
0
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())
Exemple #19
0
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)
Exemple #20
0
        # 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"
Exemple #22
0
    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()
Exemple #23
0
    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"
Exemple #24
0
 def __init__(self, nCopies):
     self.nCopies = nCopies
     self.nCopyBits = util.clog2(nCopies)
     self.muxbits = [0]
Exemple #25
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,
Exemple #26
0
    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")