Ejemplo n.º 1
0
def inner_product_verifier(n, V, prf):
    final_pc, pc2, a, b, L, R, comm1 = prf

    # Simulate a challenge e, TODO: use fiat shamir later
    e = hashlib.sha256(V).digest()
    e = decode(e, 256)

    lhs = final_pc
    rhs = ecmult(e, V, False)
    rhs_2 = pc2
    rhs = ecadd_pubkeys([rhs, rhs_2], False)

    print("**Verifying Inner product: **")
    #Note that the 'a' and 'b' vectors in the following constructor are dummy
    #values, they only set the length:
    verifier_ipc = IPC(["\x01"] * n, ["\x02"] * n)
    result = verifier_ipc.verify_proof(a, b, comm1, L, R)
    print("Verification result: ", result)

    if lhs == rhs:
        print("Positive Number")
        return True
    else:
        print("Negetive Number")
        return False
Ejemplo n.º 2
0
def inner_product_prover(w, xi, n, V, gamma):
    w_vec = Vector(w)
    xi_vec = Vector(xi)
    value = xi_vec.inner_product(w_vec)

    randints = [decode(os.urandom(32), 256) for _ in range(n)]
    b_vec = Vector(randints)

    # Simulate a challenge e, TODO: use fiat shamir later
    e = hashlib.sha256(V).digest()
    e = decode(e, 256)

    w_blind_vec = w_vec.scalar_mult(e).add(b_vec)
    blinded_commit_product = xi_vec.inner_product(b_vec)
    blinded_final_product = xi_vec.inner_product(w_blind_vec)

    r0 = os.urandom(32)
    pc2 = PC(blinded_commit_product, blinding=r0)

    r2 = (decode(gamma, 256) * e + decode(r0, 256)) % N

    r2_enc = encode(r2, 256, 32)
    final_pc = PC(blinded_final_product, blinding=r2)

    w_blind_enc = [encode(x, 256, 32) for x in w_blind_vec.v]
    xi_enc = [encode(x, 256, 32) for x in xi_vec.v]

    ipc1 = IPC(w_blind_enc, xi_enc)
    comm1 = ipc1.get_commitment()
    # print('generated commitment: ', binascii.hexlify(comm1))
    proof = ipc1.generate_proof()
    a, b, L, R = proof
    print('generated proof: ')
    print('a: ', binascii.hexlify(a))
    print('b: ', binascii.hexlify(b))
    print('L: ', [binascii.hexlify(_) for _ in L])
    print('R: ', [binascii.hexlify(_) for _ in R])
    print(
        'Total byte length is: ',
        len(a) + len(b) + len(L) * len(L[0]) + len(R) * len(R[0]) +
        len(comm1) + len(final_pc.get_commitment()) +
        len(pc2.get_commitment()))
    print('Length of L, R array: ', len(L))

    prf = final_pc.get_commitment(), pc2.get_commitment(), a, b, L, R, comm1

    return prf
Ejemplo n.º 3
0
    def generate_proof(self, value):
        """Given the value value, follow the algorithm laid out
        on p.16, 17 (section 4.2) of paper for prover side.
        """

        # generate Pederson commitment for value
        self.fsstate = ""
        self.value = value
        self.gamma = os.urandom(32)
        pc = PC(encode(self.value, 256, minlen=32), blinding=self.gamma)

        # generate the 3 conditions
        self.V = pc.get_commitment()
        self.aL = Vector(value, self.bitlength)
        self.aR = self.aL.subtract([1] * self.bitlength)

        # assert checks
        assert self.aL.hadamard(self.aR).v == Vector([0] * self.bitlength).v
        assert self.aL.inner_product(PowerVector(2, self.bitlength)) == value

        # Get the commitment A
        self.alpha = self.get_blinding_value()
        # print("Maybe")
        self.A = VPC(self.aL.v,
                     self.aR.v,
                     vtype="int",
                     u=getNUMS(255).serialize())
        self.A.set_blinding(c=self.alpha)
        self.A.get_commitment()

        # get the 3 corresponding blinding vectors/values to convert proof into zero knowledge
        self.rho = self.get_blinding_value()
        self.sL = self.get_blinding_vector()
        self.sR = self.get_blinding_vector()

        # create a commitment to the blinding vector
        self.S = VPC(self.sL.v,
                     self.sR.v,
                     vtype="int",
                     u=getNUMS(255).serialize())
        self.S.set_blinding(c=self.rho)
        self.S.get_commitment()

        # generate the challenges y and z as per fiat shamir hueristic
        self.y, self.z = self.fiat_shamir([self.V, self.A.P, self.S.P])
        self.z2 = (self.z * self.z) % N
        self.zv = Vector([self.z] * self.bitlength)

        #construct l(X) and r(X) coefficients; l[0] = constant term, l[1] linear term,
        #same for r(X)
        self.l = []
        self.l.append(self.aL.subtract(self.zv))
        self.l.append(self.sL)
        self.yn = PowerVector(self.y, self.bitlength)
        self.r = []
        #0th coeff is y^n o (aR + z.1^n) + z^2 . 2^n
        self.r.append(
            self.yn.hadamard(self.aR.add(self.zv)).add(
                PowerVector(2, self.bitlength).scalar_mult(self.z2)))
        self.r.append(self.yn.hadamard(self.sR))
        #constant term of t(X) = <l(X), r(X)> is the inner product of the
        #constant terms of l(X) and r(X)
        self.t0 = self.l[0].inner_product(self.r[0])

        self.t1 = (self.l[0].inner_product(self.r[1]) +
                   (self.l[1].inner_product(self.r[0]))) % N

        self.t2 = self.l[1].inner_product(self.r[1])

        # we have constructed the polynomials l(x) r(x) and t(x) upto here
        self.tau1 = self.get_blinding_value()
        self.tau2 = self.get_blinding_value()
        self.T1 = PC(self.t1, blinding=self.tau1)
        self.T2 = PC(self.t2, blinding=self.tau2)

        # Since we know the values of we must also send commiments to remaining polynomial.
        # this is similar to what I did in vecotrs proving dot product

        # After commiting to the value we get the next challenge x66
        self.x_1 = self.fiat_shamir(
            [self.T1.get_commitment(),
             self.T2.get_commitment()], nret=1)[0]

        self.mu = (self.alpha + self.rho * self.x_1) % N
        self.tau_x = (self.tau1 * self.x_1 + self.tau2 * self.x_1 * self.x_1 + \
                      self.z2 * decode(self.gamma, 256)) % N
        #lx and rx are vector-valued first degree polynomials evaluated at
        #the challenge value self.x_1
        self.lx = self.l[0].add(self.l[1].scalar_mult(self.x_1))
        self.rx = self.r[0].add(self.r[1].scalar_mult(self.x_1))
        self.t = (self.t0 + self.t1 * self.x_1 +
                  self.t2 * self.x_1 * self.x_1) % N
        assert self.t == self.lx.inner_product(self.rx)
        #Prover will now send tau_x, mu and t to verifier, and inner product argument
        #can be verified from this data.
        self.hprime = []
        self.yinv = modinv(self.y, N)
        for i in range(1, self.bitlength + 1):
            self.hprime.append(
                ecmult(pow(self.yinv, i - 1, N), self.A.h[i - 1], False))
        self.uchallenge = self.fiat_shamir([self.tau_x, self.mu, self.t],
                                           nret=1)[0]
        self.U = ecmult(self.uchallenge, getG(True), False)
        #On the prover side, need to construct an inner product argument:
        self.iproof = IPC(self.lx.v,
                          self.rx.v,
                          vtype="int",
                          h=self.hprime,
                          u=self.U)
        self.proof = self.iproof.generate_proof()
        #At this point we have a valid data set, but here is included a
        #sanity check that the inner product proof we've generated, actually verifies:
        self.iproof2 = IPC([1] * self.bitlength, [2] * self.bitlength,
                           vtype="int",
                           h=self.hprime,
                           u=self.U)
        ak, bk, lk, rk = self.proof
        assert self.iproof2.verify_proof(ak, bk, self.iproof.get_commitment(),
                                         lk, rk)
Ejemplo n.º 4
0
    def verify(self, Ap, Sp, T1p, T2p, tau_x, mu, t, proof, V):
        """Takes as input an already-deserialized rangeproof, along
        with the pedersen commitment V to the value (not here known),
        and checks if the proof verifies.
        """
        #wipe FS state:
        self.fsstate = ""
        #compute the challenges to find y, z, x
        self.y, self.z = self.fiat_shamir([V, Ap, Sp])
        self.z2 = (self.z * self.z) % N
        self.zv = Vector([self.z] * self.bitlength)
        self.x_1 = self.fiat_shamir([T1p, T2p], nret=1)[0]
        self.hprime = []
        self.yinv = modinv(self.y, N)
        for i in range(1, self.bitlength + 1):
            self.hprime.append(
                ecmult(pow(self.yinv, i - 1, N),
                       getNUMS(self.bitlength + i).serialize(), False))
        #construction of verification equation (61)

        #cmopute the dangling term
        onen = PowerVector(1, self.bitlength)
        twon = PowerVector(2, self.bitlength)
        yn = PowerVector(self.y, self.bitlength)
        self.k = (yn.inner_product(onen) * -self.z2) % N
        self.k = (self.k - (onen.inner_product(twon) *
                            (pow(self.z, 3, N)))) % N
        self.gexp = (self.k + self.z * onen.inner_product(yn)) % N

        # this computes PC of <l,r> with t_x
        self.lhs = PC(t, blinding=tau_x).get_commitment()
        self.rhs = ecmult(self.gexp, getG(True), False)
        self.vz2 = ecmult((self.z * self.z) % N, V, False)
        self.rhs = ecadd_pubkeys([self.rhs, self.vz2], False)
        self.rhs = ecadd_pubkeys(
            [self.rhs, ecmult(self.x_1, T1p, False)], False)
        self.rhs = ecadd_pubkeys(
            [self.rhs, ecmult((self.x_1 * self.x_1) % N, T2p, False)], False)
        if not self.lhs == self.rhs:
            print("(61) verification check failed")
            print(binascii.hexlify(self.lhs))
            print(binascii.hexlify(self.rhs))
            return False
        #reconstruct P (62)
        # standard commitment check
        self.P = Ap
        self.P = ecadd_pubkeys([ecmult(self.x_1, Sp, False), self.P], False)
        # upto here P = A + x*S
        #now add g*^(-z)
        for i in range(self.bitlength):
            self.P = ecadd_pubkeys([
                ecmult(-self.z % N,
                       getNUMS(i + 1).serialize(), False), self.P
            ], False)
        # upto here P = A + x*S - g^(-z)
        #zynz22n is the exponent of hprime
        self.zynz22n = yn.scalar_mult(self.z).add(
            PowerVector(2, self.bitlength).scalar_mult(self.z2))
        for i in range(self.bitlength):
            self.P = ecadd_pubkeys(
                [ecmult(self.zynz22n.v[i], self.hprime[i], False), self.P],
                False)
        # Here P value is computed correctly
        self.uchallenge = self.fiat_shamir([tau_x, mu, t], nret=1)[0]
        self.U = ecmult(self.uchallenge, getG(True), False)
        self.P = ecadd_pubkeys([ecmult(t, self.U, False), self.P], False)
        #P should now be : A + xS + -zG* + (zy^n+z^2.2^n)H'* + tU
        #One can show algebraically (the working is omitted from the paper)
        #that this will be the same as an inner product commitment to
        #(lx, rx) vectors (whose inner product is t), thus the variable 'proof'
        #can be passed into the IPC verify call, which should pass.
        #input to inner product proof is P.h^-(mu)
        self.Pprime = ecadd_pubkeys(
            [self.P, ecmult(-mu % N,
                            getNUMS(255).serialize(), False)], False)
        #Now we can verify the inner product proof
        a, b, L, R = proof
        #dummy vals for constructor of verifier IPC
        self.iproof = IPC(["\x01"] * self.bitlength, ["\x02"] * self.bitlength,
                          h=self.hprime,
                          u=self.U)
        #self.iproof.P = self.Pprime
        if not self.iproof.verify_proof(a, b, self.Pprime, L, R):
            return False
        return True
Ejemplo n.º 5
0
class RangeProof(object):
    def fiat_shamir(self, data, nret=2):
        """Generates nret integer challenge values from the current interaction
        (data) and the previous challenge values (self.fsstate), thus fulfilling
        the requirement of basing the challenge on the transcript of the prover-verifier
        communication up to this point.
        """
        xb = hashlib.sha256("".join([self.fsstate] +
                                    [str(_) for _ in data])).digest()
        challenges = []
        for i in range(nret):
            challenges.append(decode(xb, 256))
            xb = hashlib.sha256(xb).digest()
        self.fsstate = xb
        return challenges

    def get_blinding_vector(self):
        """Returns a vector of random elements in the group Zn,
        length of vector is the bitlength of our value to be rangeproofed.
        """
        randints = [self.get_blinding_value() for _ in range(self.bitlength)]
        return Vector(randints)

    def get_blinding_value(self):
        return decode(os.urandom(32), 256)

    def __init__(self, bitlength):
        self.fsstate = ""
        assert bitlength in [2, 4, 8, 16, 32, 64,
                             128], "Bitlength must be power of 2 <= 128"
        self.bitlength = bitlength

    def generate_proof(self, value):
        """Given the value value, follow the algorithm laid out
        on p.16, 17 (section 4.2) of paper for prover side.
        """

        # generate Pederson commitment for value
        self.fsstate = ""
        self.value = value
        self.gamma = os.urandom(32)
        pc = PC(encode(self.value, 256, minlen=32), blinding=self.gamma)

        # generate the 3 conditions
        self.V = pc.get_commitment()
        self.aL = Vector(value, self.bitlength)
        self.aR = self.aL.subtract([1] * self.bitlength)

        # assert checks
        assert self.aL.hadamard(self.aR).v == Vector([0] * self.bitlength).v
        assert self.aL.inner_product(PowerVector(2, self.bitlength)) == value

        # Get the commitment A
        self.alpha = self.get_blinding_value()
        # print("Maybe")
        self.A = VPC(self.aL.v,
                     self.aR.v,
                     vtype="int",
                     u=getNUMS(255).serialize())
        self.A.set_blinding(c=self.alpha)
        self.A.get_commitment()

        # get the 3 corresponding blinding vectors/values to convert proof into zero knowledge
        self.rho = self.get_blinding_value()
        self.sL = self.get_blinding_vector()
        self.sR = self.get_blinding_vector()

        # create a commitment to the blinding vector
        self.S = VPC(self.sL.v,
                     self.sR.v,
                     vtype="int",
                     u=getNUMS(255).serialize())
        self.S.set_blinding(c=self.rho)
        self.S.get_commitment()

        # generate the challenges y and z as per fiat shamir hueristic
        self.y, self.z = self.fiat_shamir([self.V, self.A.P, self.S.P])
        self.z2 = (self.z * self.z) % N
        self.zv = Vector([self.z] * self.bitlength)

        #construct l(X) and r(X) coefficients; l[0] = constant term, l[1] linear term,
        #same for r(X)
        self.l = []
        self.l.append(self.aL.subtract(self.zv))
        self.l.append(self.sL)
        self.yn = PowerVector(self.y, self.bitlength)
        self.r = []
        #0th coeff is y^n o (aR + z.1^n) + z^2 . 2^n
        self.r.append(
            self.yn.hadamard(self.aR.add(self.zv)).add(
                PowerVector(2, self.bitlength).scalar_mult(self.z2)))
        self.r.append(self.yn.hadamard(self.sR))
        #constant term of t(X) = <l(X), r(X)> is the inner product of the
        #constant terms of l(X) and r(X)
        self.t0 = self.l[0].inner_product(self.r[0])

        self.t1 = (self.l[0].inner_product(self.r[1]) +
                   (self.l[1].inner_product(self.r[0]))) % N

        self.t2 = self.l[1].inner_product(self.r[1])

        # we have constructed the polynomials l(x) r(x) and t(x) upto here
        self.tau1 = self.get_blinding_value()
        self.tau2 = self.get_blinding_value()
        self.T1 = PC(self.t1, blinding=self.tau1)
        self.T2 = PC(self.t2, blinding=self.tau2)

        # Since we know the values of we must also send commiments to remaining polynomial.
        # this is similar to what I did in vecotrs proving dot product

        # After commiting to the value we get the next challenge x66
        self.x_1 = self.fiat_shamir(
            [self.T1.get_commitment(),
             self.T2.get_commitment()], nret=1)[0]

        self.mu = (self.alpha + self.rho * self.x_1) % N
        self.tau_x = (self.tau1 * self.x_1 + self.tau2 * self.x_1 * self.x_1 + \
                      self.z2 * decode(self.gamma, 256)) % N
        #lx and rx are vector-valued first degree polynomials evaluated at
        #the challenge value self.x_1
        self.lx = self.l[0].add(self.l[1].scalar_mult(self.x_1))
        self.rx = self.r[0].add(self.r[1].scalar_mult(self.x_1))
        self.t = (self.t0 + self.t1 * self.x_1 +
                  self.t2 * self.x_1 * self.x_1) % N
        assert self.t == self.lx.inner_product(self.rx)
        #Prover will now send tau_x, mu and t to verifier, and inner product argument
        #can be verified from this data.
        self.hprime = []
        self.yinv = modinv(self.y, N)
        for i in range(1, self.bitlength + 1):
            self.hprime.append(
                ecmult(pow(self.yinv, i - 1, N), self.A.h[i - 1], False))
        self.uchallenge = self.fiat_shamir([self.tau_x, self.mu, self.t],
                                           nret=1)[0]
        self.U = ecmult(self.uchallenge, getG(True), False)
        #On the prover side, need to construct an inner product argument:
        self.iproof = IPC(self.lx.v,
                          self.rx.v,
                          vtype="int",
                          h=self.hprime,
                          u=self.U)
        self.proof = self.iproof.generate_proof()
        #At this point we have a valid data set, but here is included a
        #sanity check that the inner product proof we've generated, actually verifies:
        self.iproof2 = IPC([1] * self.bitlength, [2] * self.bitlength,
                           vtype="int",
                           h=self.hprime,
                           u=self.U)
        ak, bk, lk, rk = self.proof
        assert self.iproof2.verify_proof(ak, bk, self.iproof.get_commitment(),
                                         lk, rk)

    def get_proof_serialized(self):
        """Returns the serialization of the rangeproof that's been created.
        Note that all points are compressed EC points so fixed length 33 bytes
        and all scalars are fixed length 32 bytes, including the (a,b)
        components of the inner product proof. The exception is L, R which are
        arrays of EC points, length log_2(bitlength).
        So total size of proof is: 33*4 + 32*3 + (32*2 + 33*2*log_2(bitlength)).
        This agrees with the last sentence of 4.2 in the paper.
        """
        a, b, Ls, Rs = self.proof
        tau_x_ser, mu_ser, t_ser = [
            encode(x, 256, 32) for x in [self.tau_x, self.mu, self.t]
        ]
        return "".join([
            self.A.P, self.S.P,
            self.T1.get_commitment(),
            self.T2.get_commitment(), tau_x_ser, mu_ser, t_ser, a, b
        ] + Ls + Rs)

    def deserialize_proof(self, proofstr):
        """Extract the points and scalars as per comments
        to get_proof_serialized; this is obviously dumb and
        no appropriate sanity checking; TODO
        """
        Ap = proofstr[:33]
        Sp = proofstr[33:66]
        T1p = proofstr[66:99]
        T2p = proofstr[99:132]
        #these are to be passed in as integers:
        tau_x = decode(proofstr[132:164], 256)
        mu = decode(proofstr[164:196], 256)
        t = decode(proofstr[196:228], 256)
        a = proofstr[228:260]
        b = proofstr[260:292]
        import math
        arraylen = int(math.log(self.bitlength, 2))
        ctr = 292
        Ls = []
        Rs = []
        for i in range(arraylen):
            Ls.append(proofstr[ctr:ctr + 33])
            ctr += 33
        for i in range(arraylen):
            Rs.append(proofstr[ctr:ctr + 33])
            ctr += 33
        return (Ap, Sp, T1p, T2p, tau_x, mu, t, (a, b, Ls, Rs))

    def verify(self, Ap, Sp, T1p, T2p, tau_x, mu, t, proof, V):
        """Takes as input an already-deserialized rangeproof, along
        with the pedersen commitment V to the value (not here known),
        and checks if the proof verifies.
        """
        #wipe FS state:
        self.fsstate = ""
        #compute the challenges to find y, z, x
        self.y, self.z = self.fiat_shamir([V, Ap, Sp])
        self.z2 = (self.z * self.z) % N
        self.zv = Vector([self.z] * self.bitlength)
        self.x_1 = self.fiat_shamir([T1p, T2p], nret=1)[0]
        self.hprime = []
        self.yinv = modinv(self.y, N)
        for i in range(1, self.bitlength + 1):
            self.hprime.append(
                ecmult(pow(self.yinv, i - 1, N),
                       getNUMS(self.bitlength + i).serialize(), False))
        #construction of verification equation (61)

        #cmopute the dangling term
        onen = PowerVector(1, self.bitlength)
        twon = PowerVector(2, self.bitlength)
        yn = PowerVector(self.y, self.bitlength)
        self.k = (yn.inner_product(onen) * -self.z2) % N
        self.k = (self.k - (onen.inner_product(twon) *
                            (pow(self.z, 3, N)))) % N
        self.gexp = (self.k + self.z * onen.inner_product(yn)) % N

        # this computes PC of <l,r> with t_x
        self.lhs = PC(t, blinding=tau_x).get_commitment()
        self.rhs = ecmult(self.gexp, getG(True), False)
        self.vz2 = ecmult((self.z * self.z) % N, V, False)
        self.rhs = ecadd_pubkeys([self.rhs, self.vz2], False)
        self.rhs = ecadd_pubkeys(
            [self.rhs, ecmult(self.x_1, T1p, False)], False)
        self.rhs = ecadd_pubkeys(
            [self.rhs, ecmult((self.x_1 * self.x_1) % N, T2p, False)], False)
        if not self.lhs == self.rhs:
            print("(61) verification check failed")
            print(binascii.hexlify(self.lhs))
            print(binascii.hexlify(self.rhs))
            return False
        #reconstruct P (62)
        # standard commitment check
        self.P = Ap
        self.P = ecadd_pubkeys([ecmult(self.x_1, Sp, False), self.P], False)
        # upto here P = A + x*S
        #now add g*^(-z)
        for i in range(self.bitlength):
            self.P = ecadd_pubkeys([
                ecmult(-self.z % N,
                       getNUMS(i + 1).serialize(), False), self.P
            ], False)
        # upto here P = A + x*S - g^(-z)
        #zynz22n is the exponent of hprime
        self.zynz22n = yn.scalar_mult(self.z).add(
            PowerVector(2, self.bitlength).scalar_mult(self.z2))
        for i in range(self.bitlength):
            self.P = ecadd_pubkeys(
                [ecmult(self.zynz22n.v[i], self.hprime[i], False), self.P],
                False)
        # Here P value is computed correctly
        self.uchallenge = self.fiat_shamir([tau_x, mu, t], nret=1)[0]
        self.U = ecmult(self.uchallenge, getG(True), False)
        self.P = ecadd_pubkeys([ecmult(t, self.U, False), self.P], False)
        #P should now be : A + xS + -zG* + (zy^n+z^2.2^n)H'* + tU
        #One can show algebraically (the working is omitted from the paper)
        #that this will be the same as an inner product commitment to
        #(lx, rx) vectors (whose inner product is t), thus the variable 'proof'
        #can be passed into the IPC verify call, which should pass.
        #input to inner product proof is P.h^-(mu)
        self.Pprime = ecadd_pubkeys(
            [self.P, ecmult(-mu % N,
                            getNUMS(255).serialize(), False)], False)
        #Now we can verify the inner product proof
        a, b, L, R = proof
        #dummy vals for constructor of verifier IPC
        self.iproof = IPC(["\x01"] * self.bitlength, ["\x02"] * self.bitlength,
                          h=self.hprime,
                          u=self.U)
        #self.iproof.P = self.Pprime
        if not self.iproof.verify_proof(a, b, self.Pprime, L, R):
            return False
        return True