Example #1
0
def getNUMS(index=0):
    """Taking secp256k1's G as a seed,
    either in compressed or uncompressed form,
    append "index" as a byte, and append a second byte "counter"
    try to create a new NUMS base point from the sha256 of that
    bytestring. Loop counter and alternate compressed/uncompressed
    until finding a valid curve point. The first such point is
    considered as "the" NUMS base point alternative for this index value.

    The search process is of course deterministic/repeatable, so
    it's fine to just store a list of all the correct values for
    each index, but for transparency left in code for initialization
    by any user.
    
    The NUMS generator generated is returned as a secp256k1.PublicKey.
    """

    assert index in range(256)
    nums_point = None
    for G in [getG(True), getG(False)]:
        seed = G + struct.pack(b'B', index)
        for counter in range(256):
            seed_c = seed + struct.pack(b'B', counter)
            hashed_seed = hashlib.sha256(seed_c).digest()
            #Every x-coord on the curve has two y-values, encoded
            #in compressed form with 02/03 parity byte. We just
            #choose the former.
            claimed_point = b"\x02" + hashed_seed
            try:
                nums_point = podle_PublicKey(claimed_point)
                return nums_point
            except:
                continue
    assert False, "It seems inconceivable, doesn't it?"  # pragma: no cover
Example #2
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)
Example #3
0
 def __init__(self, v, g=None, h=None, blinding=None):
     self.v = v
     self.g = getG(True) if not g else g
     self.h = getNUMS(255).serialize() if not h else h
     self.set_blinding(blinding)
     self.get_commitment()
Example #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