def __init__(self, a: Vector, b: Vector, c: Union[None, Scalar] = None, G: List[Point] = [], H: List[Point] = [], U: Union[None, Point] = None): assert len(a) == len(b) self.a = a self.b = b self.c: Scalar = c if c is not None else a @ b self.vlen = len(a) self.U = U if U is not None else getNUMS(0) self.G = G if len(G) > 0 else [ getNUMS(i + 1) for i in range(self.vlen) ] self.H = H if len(H) > 0 else [ getNUMS(i + 1) for i in range(self.vlen, 2 * self.vlen) ] self.L = [] self.R = []
def __init__(self, v: Scalar, b: Union[None, Scalar] = None, h: Point = getNUMS(255)): self.g: Point = B.getG() self.h: Point = h # Value to hide self.v: Scalar = v # Blinding Factor self.b: Scalar = b if isinstance(b, int) else get_blinding_value()
def generate_proof(self, value: Scalar): """ Given a value, follow the algorithm laid out on p.16, 17 (section 4.2) of paper for prover side """ fs_state = b'' # Vector of all 1's or 0's # Mainly for readability zeros = Vector([0] * self.bitlength) ones = Vector([1] * self.bitlength) twos = Vector([2] * self.bitlength) power_of_twos = to_powervector(2, self.bitlength) aL = to_bitvector(value, self.bitlength) aR = aL - ones assert aL * aR == zeros assert aL @ power_of_twos == value # Pederson Commitment to fulfill the hiding and binding properties # of bulletproof. Binding value is automatically created gamma = get_blinding_value() pc = PedersonCommitment(value, b=gamma) V: Point = pc.get_commitment() alpha: Scalar = get_blinding_value() A = InnerProductCommitment(aL, aR, c=alpha, U=getNUMS(255)) P_a: Point = A.get_commitment() sL = get_blinding_vector(self.bitlength) sR = get_blinding_vector(self.bitlength) rho = get_blinding_value() S = InnerProductCommitment(sL, sR, c=rho, U=getNUMS(255)) P_s: Point = S.get_commitment() fs_state, fs_challanges = fiat_shamir(fs_state, [V, P_a, P_s]) y: Point = fs_challanges[0] z: Point = fs_challanges[1] z2 = pow(z, 2, B.N) zv = Vector([z] * self.bitlength) # Construct l(x) and r(x) coefficients; # l[0] = constant term # l[1] = linear term # same for r(x) l: List[Vector] = [aL - zv, sL] yn: Vector = to_powervector(y, self.bitlength) # 0th coeff is y^n ⋅ (aR + z ⋅ 1^n) + (z^2 ⋅ 2^n) # operators have been overloaded, so all good r: List[Vector] = [ # operator overloading works if vector is first (yn * (aR + zv)) + (power_of_twos * z2), yn * sR ] # Constant term of t(x) = <l(x), r(x)> is the inner product # of the constant terms of l(x)and r(x) t0: Scalar = l[0] @ r[0] t2: Scalar = l[1] @ r[1] t1: Scalar = (((l[0] + l[1]) @ (r[0] + r[1])) - t0 - t2) % B.N tau1 = get_blinding_value() T1 = PedersonCommitment(t1, b=tau1) tau2 = get_blinding_value() T2 = PedersonCommitment(t2, b=tau2) fs_state, fs_challanges = fiat_shamir( fs_state, [T1.get_commitment(), T2.get_commitment()], nret=1) x_1: Scalar = fs_challanges[0] mu = (alpha + rho * x_1) % B.N tau_x = (z2 * gamma + tau1 * x_1 + tau2 * x_1 * x_1) % B.N # lx and rx are vetor-value first degree polynomials evaluated at # the challenge value x_1 lx: Vector = l[0] + (l[1] * x_1) rx: Vector = r[0] + (r[1] * x_1) t: Scalar = (t0 + t1 * x_1 + t2 * x_1 * x_1) % B.N assert t == lx @ rx # Prover can new send tau_x, mu and t to verifier # inner product argument can be verified from this data hprime = [] yinv = modinv(y, B.N) for i in range(self.bitlength): hprime.append(B.multiply(A.H[i], pow(yinv, i, B.N))) fs_state, fs_challanges = fiat_shamir(fs_state, [tau_x, mu, t], nret=1) uchallenge = fs_challanges[0] U = B.multiply(B.G, uchallenge) # On the prover side, need to construct an inner product argument iproof = InnerProductCommitment(lx, rx, U=U, H=hprime) proof = iproof.generate_proof() ak: Scalar = proof[0] bk: Scalar = proof[1] lk: List[Point] = proof[2] rk: List[Point] = proof[3] # 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 iproof2 = InnerProductCommitment(ones, twos, H=hprime, U=U) assert iproof2.verify_proof(ak, bk, iproof.get_commitment(), lk, rk) self.proof = proof self.tau_x = tau_x self.gamma = gamma self.mu = mu self.T1 = T1 self.T2 = T2 self.A = A self.S = S self.t = t self.V = V
def verify(self, Ap, Sp, T1p, T2p, tau_x, mu, t, proof, V): fs_state = b'' # Compute challenges to find x, y, z fs_state, fs_challenge = fiat_shamir(fs_state, [V, Ap, Sp]) y: Scalar = fs_challenge[0] z: Scalar = fs_challenge[1] z2 = pow(z, 2, B.N) fs_state, fs_challenge = fiat_shamir(fs_state, [T1p, T2p], nret=1) x_1 = fs_challenge[0] # Construct verification equation (61) power_of_ones = to_powervector(1, self.bitlength) power_of_twos = to_powervector(2, self.bitlength) yn = to_powervector(y, self.bitlength) k: Scalar = ((yn @ power_of_ones) * (-z2)) % B.N k = (k - (power_of_ones @ power_of_twos) * pow(z, 3, B.N)) % B.N gexp: Scalar = (k + z * (power_of_ones @ yn)) % B.N lhs = PedersonCommitment(t, b=tau_x).get_commitment() rhs = B.multiply(B.G, gexp) rhs = B.add_pubkeys(rhs, B.multiply(V, z2)) rhs = B.add_pubkeys(rhs, B.multiply(T1p, x_1)) rhs = B.add_pubkeys(rhs, B.multiply(T2p, pow(x_1, 2, B.N))) if not lhs == rhs: print('(61) verification check failed') return False # HPrime hprime = [] yinv = modinv(y, B.N) for i in range(1, self.bitlength + 1): hprime.append( B.multiply(getNUMS(self.bitlength + i), pow(yinv, i - 1, B.N))) # Reconstruct P P = B.add_pubkeys(B.multiply(Sp, x_1), Ap) # Add g*^(-z) for i in range(self.bitlength): P = B.add_pubkeys(B.multiply(getNUMS(i + 1), -z % B.N), P) # zynz22n is the exponent of hprime zynz22n = (yn * z) + (power_of_twos * z2) for i in range(self.bitlength): P = B.add_pubkeys(B.multiply(hprime[i], zynz22n[i]), P) fs_state, fs_challenge = fiat_shamir(fs_state, [tau_x, mu, t], nret=1) uchallenge: Scalar = fs_challenge[0] U = B.multiply(B.G, uchallenge) P = B.add_pubkeys(B.multiply(U, t), P) # 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) p_prime = B.add_pubkeys(P, B.multiply(getNUMS(255), -mu % B.N)) a, b, L, R = proof iproof = InnerProductCommitment(power_of_ones, power_of_twos, H=hprime, U=U) return iproof.verify_proof(a, b, p_prime, L, R)
import pybitcointools as B from pybp.pederson import PedersonCommitment from pybp.vectors import to_powervector, Vector from pybp.utils import get_blinding_value, get_blinding_vector, getNUMS """ Section 3: A zero knowledge argument of knowledge of a set of vectors """ H = getNUMS(255) N = 4 # P -> V: C_0 r = get_blinding_vector(N) x = get_blinding_vector(N) commitments = [ PedersonCommitment(x[i], b=r[i]).get_commitment() for i in range(N) ] # V -> P: e e = get_blinding_value() ev = to_powervector(e, N) # P -> V (z, s) # P P = commitments[0] for i in range(1, N): P = B.add_pubkeys(B.multiply(commitments[i], ev[i]), P)