def run_one_test(nbits, squawk, nbins, pattern): z = [ Defs.gen_random() for _ in range(0, nbits) ] inv = [ Defs.gen_random() for _ in range(0, (2 ** nbits) - nbins) ] if pattern is 0: inv += [ 0 for _ in range(0, nbins) ] elif pattern is 1: inv += [ 1 for _ in range(0, nbins) ] elif pattern is 2: inv += [ (i % 2) for i in range(0, nbins) ] elif pattern is 3: inv += [ ((i + 1) % 2) for i in range(0, nbins) ] else: inv += [ random.randint(0, 1) for _ in range(0, nbins) ] assert len(inv) == (2 ** nbits) fa = FArith() oldrec = fa.new_cat("old") newrec = fa.new_cat("new") nw2rec = fa.new_cat("nw2") nw3rec = fa.new_cat("nw3") oldbeta = LayerComputeBeta(nbits, z, oldrec) oldval = sum(util.mul_vecs(oldbeta.outputs, inv)) % Defs.prime oldrec.did_mul(len(inv)) oldrec.did_add(len(inv)-1) newcomp = VerifierIOMLExt(z, newrec) newval = newcomp.compute(inv) nw2comp = LayerComputeV(nbits, nw2rec) nw2comp.other_factors = [] nw2comp.set_inputs(inv) for zz in z: nw2comp.next_round(zz) nw2val = nw2comp.prevPassValue nw3comp = VerifierIOMLExt(z, nw3rec) nw3val = nw3comp.compute_sqrtbits(inv) assert oldval == newval, "error for inputs (new) %s : %s" % (str(z), str(inv)) assert oldval == nw2val, "error for inputs (nw2) %s : %s" % (str(z), str(inv)) assert oldval == nw3val, "error for inputs (nw3) %s : %s" % (str(z), str(inv)) if squawk: print print "nbits: %d" % nbits print "OLD: %d mul %d add %d sub" % oldrec.get_counts() print "NEW: %d mul %d add %d sub" % newrec.get_counts() print "NW2: %d mul %d add %d sub" % nw2rec.get_counts() print "NW3: %d mul %d add %d sub" % nw3rec.get_counts() return newrec.get_counts()
def divided_diffs(yvals, rec=None): # ASSUMPTION: y0 = f(0), y1 = f(1), y2 = f(2), ... # to start, generate incremental differences diffs = yvals if rec is None: rec = FArith().new_cat("q") out = [diffs[0]] for i in range(0, len(diffs) - 1): # this inversion can be stored statically, so we don't have to account its cost div = invert_modp(i + 1) assert len(diffs) > 1 diffs = [ rec.mul(x, div) for x in sub_vecs(diffs[1:], diffs[:-1], rec) ] out.append(diffs[0]) return out
def proc_vecs(f, ident, a, b, rec=None): if rec is None: rec = FArith().new_cat("q") la = len(a) lb = len(b) lc = max(la, lb) ff = lambda i: f(a[i] if i < la else ident, b[i] if i < lb else ident, rec) c = [ ff(i) for i in range(0, lc) ] return c
def lagrange_interpolate(yvals, rec=None): assert len(yvals) > 1 if rec is None: rec = FArith().new_cat("q") ## step 1: generate coefficients # these can be stored statically, so no need to account their cost coeffs = generate_lagrange_coeffs(len(yvals) - 1) ## step 2: dot products return matrix_times_vector(coeffs, yvals, rec)
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 newton_interpolate(yvals, rec=None): assert len(yvals) > 1 if rec is None: rec = FArith().new_cat("q") ## step 1, generate divided differences diffs = divided_diffs(yvals, rec) ## step 2, generate coefficients # these can be stored statically, so no need to account their cost coeffs = generate_newton_coeffs(len(yvals) - 1) ## step 3, combine return matrix_times_vector(coeffs, diffs, rec)
def matrix_times_vector(mat, vec, rec=None): if rec is None: rec = FArith().new_cat("q") return reduce(lambda x, y: add0_vecs(x, y, rec), [ [ rec.mul0(x, z) for z in y ] for (x, y) in zip(vec, mat) ])