Exemplo n.º 1
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)
Exemplo n.º 2
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
Exemplo n.º 3
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
Exemplo n.º 4
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)
Exemplo n.º 5
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
Exemplo n.º 6
0
def run_test_rangeproof(value, rangebits):
    print("Starting rangeproof test for value: ", value,
          " in range from 0 to 2^", rangebits)
    fail = False
    if not (0 < value and value < 2**rangebits):
        print("Value is NOT in range; we want verification to FAIL.")
        fail = True
        #To attempt to forge a rangeproof for a not-in-range value,
        #we'll do the following: make a *valid* proof for the truncated
        #bits of our overflowed value, and then apply a V pedersen commitment
        #to our actual value, which will (should!) fail.
        #Obviously, there are a near-infinite number of ways to create
        #invalid proofs, TODO look into others.
        proofval = value & (2**rangebits - 1)
        print("Using truncated bits, value: ", proofval,
              " to create fake proof.")
    else:
        proofval = value
    rp = RangeProof(rangebits)
    rp.generate_proof(proofval)
    proof = rp.get_proof_serialized()
    #now simulating: the serialized proof passed to the validator/receiver;
    #note that it is tacitly assumed that in the expected application (CT
    #or similar), the V value is a pedersen commitment which already exists
    #in the transaction; it's what we're validating *against*, so it's not
    #part of the proof itself. Hence we just pass rp.V into the verify call,
    #for the case of valid rangeproofs.
    print("Got rangeproof: ", binascii.hexlify(proof))
    print("Its length is: ", len(proof))
    #Note this is a new RangeProof object:
    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 fail:
        #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(value, 256, minlen=32),
                  blinding=rp.gamma).get_commitment()
    else:
        Varg = rp.V
    if not rp2.verify(A, S, T1, T2, tau_x, mu, t, iproof, Varg):
        if not fail:
            print('Rangeproof should have verified but is invalid; bug.')
        else:
            print(
                "Rangeproof failed, as it should because value is not in range."
            )
    else:
        if not fail:
            print('Rangeproof verified correctly, as expected.')
        else:
            print(
                "Rangeproof succeeded but it should not have, value is not in range; bug."
            )
Exemplo n.º 7
0
 def __init__(self, a, b, g=None, h=None, u=None, vtype="bin"):
     assert self.is_vector(a)
     assert self.is_vector(b)
     if g:
         assert all([len(_) == len(a) for _ in [g, h]])
     self.vlen = len(a)
     assert vtype in ["bin", "int"]
     if vtype == "int":
         #Convert to binary for EC operations
         a = [encode(x % N, 256, 32) for x in a]
         b = [encode(x % N, 256, 32) for x in b]
     self.a = a
     self.b = b
     #the blinding is not initialized; it
     #will be created on-the-fly when the commitment
     #is requested, if it is not yet initialized at that point.
     #This allows subclasses to customize (specifically,
     #for the inner product case).
     self.c = None
     self.set_base_points(g, h, u)
Exemplo n.º 8
0
 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)
Exemplo n.º 9
0
def run_test_IPC():
    a = [encode(x, 256, 32) for x in range(1, 9)]
    b = [encode(x, 256, 32) for x in range(9, 17)]
    ipc1 = IPC(a, b)
    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]))
    print('Length of L, R array: ', len(L))
    print("**NOW ATTEMPTING TO VERIFY: **")
    #Note that the 'a' and 'b' vectors in the following constructor are dummy
    #values, they only set the length:
    verifier_ipc = IPC(["\x01"] * 8, ["\x02"] * 8)
    result = verifier_ipc.verify_proof(a, b, comm1, L, R)
    print("Verification result: ", result)
Exemplo n.º 10
0
 def set_blinding(self, c=None):
     """The blinding value is kept as binary
     not integer since this is format is used by
     the scalar ecmult function.
     Optionally can set it explicitly, useful for
     forming homomorphic commitments.
     """
     if not c:
         if not self.c:
             self.c = os.urandom(32)
     else:
         if isinstance(c, (int, long)):
             c = encode(c, 256, minlen=32)
         self.c = c
Exemplo n.º 11
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
Exemplo n.º 12
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()
Exemplo n.º 13
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)
Exemplo n.º 14
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")
Exemplo n.º 15
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)
Exemplo n.º 16
0
def _test(value, rangebits):
    # self.value = value
    gamma = os.urandom(32)
    pc = PC(encode(value, 256, minlen=32), blinding=gamma)
    print(pc.serialize())