Esempio n. 1
0
 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))
Esempio n. 2
0
    def get_proof_recursive(self, a, b, P, g, h, n):
        """The prover starts with the full a*, b*, then recursively
        constructs the case n=1 where the proof is output in the form a', b',
        these are scalars, and c' = a' * b'. This will be checked by the verifier
        against the modified P', which the verifier can calculate independently,
        and it should satisfy P' = a'*G_1 + b'*H_1 + c'*U.
        So the prover must provide (L[], R[], a', b') as output to the verifier.
        The verifier checks against the pre-known P and c.
        """
        if n == 1:
            #return the tuple: a', b', L[], R[]
            #note total size is 2 * scalar_size + log(n) * 2 * point_size
            return (a[0], b[0], self.L, self.R)
        #Split the existing vectors into halves
        aL, aR = halves(a)
        bL, bR = halves(b)
        gL, gR = halves(g)
        hL, hR = halves(h)
        self.L.append(IPC(aL, bR, g=gR, h=hL, u=self.U).get_commitment())
        self.R.append(IPC(aR, bL, g=gL, h=hR, u=self.U).get_commitment())
        x, xb, x_sq, x_sqb, xinv, xinvb, x_sq_inv, x_sq_invb = self.fiat_shamir(
            self.L[-1], self.R[-1], P)
        #Construct change of coordinates for base points, and for vector terms
        gprime = []
        hprime = []
        aprime = []
        bprime = []
        for i in range(n / 2):
            gprime.append(
                add_pubkeys([
                    multiply(xinvb, g[i], False),
                    multiply(xb, g[i + n / 2], False)
                ], False))
            hprime.append(
                add_pubkeys([
                    multiply(xb, h[i], False),
                    multiply(xinvb, h[i + n / 2], False)
                ], False))
            aprime.append(
                encode(
                    (x * decode(a[i], 256) + xinv * decode(a[i + n / 2], 256))
                    % N, 256, 32))
            bprime.append(
                encode(
                    (xinv * decode(b[i], 256) + x * decode(b[i + n / 2], 256))
                    % N, 256, 32))

        Pprime = add_pubkeys([
            P,
            multiply(x_sqb, self.L[-1], False),
            multiply(x_sq_invb, self.R[-1], False)
        ], False)
        return self.get_proof_recursive(aprime, bprime, Pprime, gprime, hprime,
                                        n / 2)
Esempio n. 3
0
def inner_product(a, b, vtype="bin"):
    assert len(a) == len(b)
    assert isinstance(a, list)
    assert isinstance(b, list)
    c = 0
    for i in range(len(a)):
        if vtype == "bin":
            c += decode(a[i], 256) * decode(b[i], 256)
        else:
            c += a[i] * b[i]
        c = c % N
    if vtype == "bin":
        c = encode(c, 256, 32)
    return c
Esempio n. 4
0
 def verify(self, commitment, index_range):
     """For an object created without a private key,
     check that the opened commitment verifies for at least
     one NUMS point as defined by the range in index_range
     """
     if not all([self.P, self.P2, self.s, self.e]):
         raise PoDLEError("Verify called without sufficient data")
     if not self.get_commitment() == commitment:
         return False
     for J in [getNUMS(i) for i in index_range]:
         sig_priv = podle_PrivateKey(self.s)
         sG = sig_priv.public_key
         sJ = multiply(self.s, J.format(), False)
         e_int = decode(self.e, 256)
         minus_e = encode(-e_int % N, 256, minlen=32)
         minus_e_P = multiply(minus_e, self.P.format(), False)
         minus_e_P2 = multiply(minus_e, self.P2.format(), False)
         KGser = add_pubkeys([sG.format(), minus_e_P], False)
         KJser = add_pubkeys([sJ, minus_e_P2], False)
         #check 2: e =?= H(K_G || K_J || P || P2)
         e_check = hashlib.sha256(KGser + KJser + self.P.format() +
                                  self.P2.format()).digest()
         if e_check == self.e:
             return True
     #commitment fails for any NUMS in the provided range
     return False
Esempio n. 5
0
def range_verifier(proof, negetive, V, rangebits):
    rp2 = RangeProof(rangebits)
    A, S, T1, T2, tau_x, mu, t, iproof = rp2.deserialize_proof(proof)
    print("Now attempting to verify a proof in range: 0 -", 2**rangebits)
    if negetive:
        #As mentioned in comments above, here create a Pedersen commitment
        #to our actual value, which is out of range, with the same blinding
        #value.
        Varg = PC(encode(2**128 + decode(os.urandom(32), 256), 256, minlen=32),
                  blinding=os.urandom(32)).get_commitment()
    else:
        Varg = V
    if not rp2.verify(A, S, T1, T2, tau_x, mu, t, iproof, Varg):
        if not negetive:
            print('Rangeproof should have verified but is invalid; bug.')
            return False
        else:
            print(
                "Rangeproof fail, as it should because value is not in range.")
            return True
    else:
        if not negetive:
            print('Rangeproof verified correctly, as expected.')
            return False
        else:
            print(
                "Rangeproof succeeded but it should not have, value is not in range; bug."
            )
            return True
    return negetive
Esempio n. 6
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
Esempio n. 7
0
def ecmult(scalar, point, usehex, rawpub=True, return_serialized=True):
    if isinstance(scalar, (int, long)):
        scalar = encode(scalar, 256, minlen=32)
    if decode(scalar, 256) == 0:
        return None
    return multiply(scalar, point, usehex, rawpub=rawpub,
                    return_serialized=return_serialized)
Esempio n. 8
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
Esempio n. 9
0
    def generate_podle(self, index=0, k=None):
        """Given a raw private key, in hex format,
        construct a commitment sha256(P2), which is
        the hash of the value x*J, where x is the private
        key as a raw scalar, and J is a NUMS alternative
        basepoint on the Elliptic Curve; we use J(i) where i
        is an index, so as to be able to create multiple
        commitments against the same privkey. The procedure
        for generating the J(i) value is shown in getNUMS().
        Also construct a signature (s,e) of Schnorr type,
        which will serve as a zero knowledge proof that the
        private key of P2 is the same as the private key of P (=x*G).
        Signature is constructed as:
        s = k + x*e
        where k is a standard 32 byte nonce and:
        e = sha256(k*G || k*J || P || P2)

        Possibly Joinmarket specific comment:
        Users *should* generate with lower indices first,
        since verifiers will give preference to lower indices
        (each verifier may have their own policy about how high
        an index to allow, which really means how many reuses of utxos
        to allow in Joinmarket).

        Returns a commitment of form H(P2) which, note, will depend
        on the index choice. Repeated calls will reset the commitment
        and the associated signature data that can be used to open
        the commitment.
        """
        #TODO nonce could be rfc6979?
        if not k:
            k = os.urandom(32)
        J = getNUMS(index)
        KG = podle_PrivateKey(k).public_key
        KJ = multiply(k, J.format(), False, return_serialized=False)
        self.P2 = getP2(self.priv, J)
        self.get_commitment()
        self.e = hashlib.sha256(b''.join(
            [x.format() for x in [KG, KJ, self.P, self.P2]])).digest()
        k_int = decode(k, 256)
        priv_int = decode(self.priv.secret, 256)
        e_int = decode(self.e, 256)
        sig_int = (k_int + priv_int * e_int) % N
        self.s = encode(sig_int, 256, minlen=32)
        return self.reveal()
Esempio n. 10
0
 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
Esempio n. 11
0
def run_test_VPC():
    rawv = raw_input("Enter a vector cseparated: ")
    v = [int(x) for x in rawv.split(',')]
    vpc = VPC(v, v, vtype="int")
    print("Successfully created the pedersen commitment to: ", rawv)
    C = vpc.get_commitment()
    print("Here is the commitment: ", binascii.hexlify(C))
    rawv2 = raw_input("Test homomorphism: enter second vector: ")
    v2 = [int(x) for x in rawv2.split(',')]
    vpc2 = VPC(v2, v2, vtype="int")
    C2 = vpc2.get_commitment()
    print("Here is the commitment for the second vector: ",
          binascii.hexlify(C2))
    assert len(v2) == len(v), "try again"
    sumv = [x + y for x, y in zip(v, v2)]
    print('here is sumv: ', sumv)
    newc = encode((decode(vpc.c, 256) + decode(vpc2.c, 256)) % N, 256, 32)
    print("here is newc len: ", len(newc))
    sumvpc = VPC(sumv, sumv, vtype="int")
    #reset the blinding value
    sumvpc.set_blinding(c=newc)
    Csum = sumvpc.get_commitment()
    print("Here is the commitment to the sum: ", binascii.hexlify(Csum))
    print("Here is the sum of C and C2: ",
          binascii.hexlify(ecadd_pubkeys([C, C2], False)))
    if Csum == ecadd_pubkeys([C, C2], False):
        print("Successly verified homomorphism")
    else:
        print("Homomorphism failed to verify.")
        exit(0)
    #test out opening commitments
    if not verify_opening(C, vpc.c, v, v, vtype="int"):
        print("V1 did not verify")
    if not verify_opening(C2, vpc2.c, v2, v2, vtype="int"):
        print("V2 did not verify")
    if not verify_opening(Csum, sumvpc.c, sumv, sumv, vtype="int"):
        print("Vsum did not verify")
Esempio n. 12
0
 def fiat_shamir(self, L, R, P):
     """Generates a challenge value x from the "transcript" up to this point,
     using the previous hash, and uses the L and R values from the current
     iteration, and commitment P. Returned is the value of the challenge and its
     modular inverse, as well as the squares of those values, both as
     integers and binary strings, for convenience.
     """
     xb = hashlib.sha256("".join([self.fsstate] +
                                 [str(_) for _ in [L, R, P]])).digest()
     self.fsstate = xb
     x = decode(xb, 256) % N
     x_sq = (x * x) % N
     xinv = modinv(x, N)
     x_sq_inv = (xinv * xinv) % N
     x_sqb, xinvb, x_sq_invb = [
         encode(_, 256, 32) for _ in [x_sq, xinv, x_sq_inv]
     ]
     return (x, xb, x_sq, x_sqb, xinv, xinvb, x_sq_inv, x_sq_invb)
Esempio n. 13
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)
Esempio n. 14
0
 def get_blinding_value(self):
     return decode(os.urandom(32), 256)