def Prove(pk1, X1, Y1, pk2, X2, Y2, r1, r2, v): sr = SystemRandom() #Prover Stage 1 a1 = sr.getrandbits(256) a2 = sr.getrandbits(256) b = sr.getrandbits(256) A1 = bn128.multiply(pk1, a1) A2 = bn128.multiply(pk2, a2) B1 = bn128.add(bn128.multiply(bn128.G1, a1), bn128.multiply(H, b)) B2 = bn128.add(bn128.multiply(bn128.G1, a2), bn128.multiply(H, b)) #Fiat Shamir hasher = keccak_256() hasher.update(A1[0].n.to_bytes(32, 'big')) hasher.update(A1[1].n.to_bytes(32, 'big')) hasher.update(A2[0].n.to_bytes(32, 'big')) hasher.update(A2[1].n.to_bytes(32, 'big')) hasher.update(B1[0].n.to_bytes(32, 'big')) hasher.update(B1[1].n.to_bytes(32, 'big')) hasher.update(B2[0].n.to_bytes(32, 'big')) hasher.update(B2[1].n.to_bytes(32, 'big')) e = int.from_bytes(hasher.digest(), 'big') #Prover Stage 2 z1 = (a1 + e * r1) % bn128.curve_order z2 = (a2 + e * r2) % bn128.curve_order z3 = (b + e * v) % bn128.curve_order return (z1, z2, z3)
def BuildCommitmentPublic(public_bit_commitments, indices): C_out = None for i in range(0, len(indices)): if bn128.is_inf(C_out): C_out = public_bit_commitments[indices[i]] C_out = (bn128.FQ(C_out[0]), bn128.FQ(C_out[1])) else: C_out = bn128.add(C_out, C_out) C_out = bn128.add(C_out, public_bit_commitments[indices[i]]) return C_out
def Dec(sk, X, Y): sk_inv = pow(sk, bn128.curve_order - 2, bn128.curve_order) denom = bn128.multiply(X, sk_inv) denom = (denom[0], -denom[1]) Hm = bn128.add(Y, denom) P_test = H m = 1 while not bn128.eq(Hm, P_test): m += 1 P_test = bn128.add(P_test, H) return m
async def constructBinaryRepresentation(client, attemptID, elGamalInstance, dCipher, answerAttempt, p, secretKey): ciphertextArray = [] nizkps = [] publicKey = bn128.multiply(bn128.G1, secretKey.n) # slice leading 0b binaryString = bin(answerAttempt.n)[2:] exponent = [i for i in range(len(binaryString))] exponent.reverse() for index in range(len(binaryString)): random = getRandomElement() if binaryString[index] == '0': # case: beta_i = 0 => Random encryption of 0 encryption = elGamalInstance.encrypt(0, random) proof = FirstNIZKP.generateCommitment(publicKey, encryption.second, encryption.first, random, dCipher.first, dCipher.second, True) challenge = bn128.FQ(client.getChallengeForNIZKP1( attemptID, proof)) proof = FirstNIZKP.computeProof(proof, challenge) ciphertextArray.append(encryption) nizkps.append(proof) else: element = (bn128.FQ(2)**exponent[index]).n # c0,i = d_0 ** (2**i * beta_i) * (g_1 ** r) | case: beta_i = 1 d0pow = bn128.multiply(dCipher.first, element) gr = bn128.multiply(bn128.G1, random.n) c0i = bn128.add(d0pow, gr) # c1,i = d_1 ** (2**i * beta_i) * (h ** r) | case: beta_i = 1 d1pow = bn128.multiply(dCipher.second, element) hr = bn128.multiply(elGamalInstance.publicKey, random.n) c1i = bn128.add(d1pow, hr) proof = FirstNIZKP.generateCommitment(publicKey, c1i, c0i, random, dCipher.first, dCipher.second, False) challenge = bn128.FQ(client.getChallengeForNIZKP1( attemptID, proof)) proof = FirstNIZKP.computeProof(proof, challenge) encryption = Ciphertext(c0i, c1i) ciphertextArray.append(encryption) nizkps.append(proof) return (ciphertextArray, nizkps)
def VerifyRangeProofs(proof_bytes, pct_check=100): sr = SystemRandom() proof_size, proof_count = GetProofSizeAndCount(proof_bytes) #Get asset address and H_neg asset_address = int.from_bytes(proof_bytes[0:20], 'big') G1 = bn128.G1 H_neg = H_from_address(asset_address) H_neg = (H_neg[0], -H_neg[1]) for i in range(0, proof_count): if pct_check == 100 or sr.randint(0, 100) < pct_check: #Extract Proof start = 20 + i * proof_size C = (bn128.FQ(int.from_bytes(proof_bytes[start:start + 32], 'big')), bn128.FQ( int.from_bytes(proof_bytes[start + 32:start + 64], 'big'))) c0 = int.from_bytes(proof_bytes[start + 64:start + 96], 'big') s0 = int.from_bytes(proof_bytes[start + 96:start + 128], 'big') s1 = int.from_bytes(proof_bytes[start + 128:start + 160], 'big') #Segment 1 A = bn128.add(bn128.multiply(C, c0), bn128.multiply(G1, s0)) c1 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Segment 2 A = bn128.add(bn128.multiply(bn128.add(C, H_neg), c1), bn128.multiply(G1, s1)) c0p = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') if (c0 != c0p): return i return -1
def Verify(pk1, X1, Y1, pk2, X2, Y2, A1, A2, B1, B2, z1, z2, z3): #Fiat Shamir hasher = keccak_256() hasher.update(A1[0].n.to_bytes(32, 'big')) hasher.update(A1[1].n.to_bytes(32, 'big')) hasher.update(A2[0].n.to_bytes(32, 'big')) hasher.update(A2[1].n.to_bytes(32, 'big')) hasher.update(B1[0].n.to_bytes(32, 'big')) hasher.update(B1[1].n.to_bytes(32, 'big')) hasher.update(B2[0].n.to_bytes(32, 'big')) hasher.update(B2[1].n.to_bytes(32, 'big')) e = int.from_bytes(hasher.digest(), 'big') #Verifier checks left = bn128.add(A1, bn128.multiply(X1, e)) right = bn128.multiply(pk1, z1) if not eq(left, right): return False left = bn128.add(A2, bn128.multiply(X2, e)) right = bn128.multiply(pk2, z2) if not eq(left, right): return False left = bn128.add(B1, bn128.multiply(Y1, e)) right = bn128.add(bn128.multiply(bn128.G1, z1), bn128.multiply(H, z3)) if not eq(left, right): return False left = bn128.add(B2, bn128.multiply(Y2, e)) right = bn128.add(bn128.multiply(bn128.G1, z2), bn128.multiply(H, z3)) if not eq(left, right): return False return True
def verify(self, proof): """Verify if a proof is correct for the given inputs""" if not isinstance(proof, Proof): raise TypeError("Invalid proof type") # Compute the linear combination vk_x # vk_x = IC[0] + IC[1]^x[0] + ... + IC[n+1]^x[n] vk_x = self.IC[0] for i, x in enumerate(proof.input): IC_mul_x = multiply(self.IC[i + 1], x) vk_x = add(vk_x, IC_mul_x) # e(V_a,P_a) * e(G2,-P_a_p) == 1 if not pairingProd((proof.a, self.a), (neg(proof.a_p), bn128.G2)): raise RuntimeError("Proof step 1 failed") # e(P_b,V_b) * e(G2,-P_b_p) == 1 if not pairingProd((self.b, proof.b), (neg(proof.b_p), bn128.G2)): raise RuntimeError("Proof step 2 failed") # e(V_c,P_c) * e(G2,-P_c_p) == 1 if not pairingProd((proof.c, self.c), (neg(proof.c_p), bn128.G2)): raise RuntimeError("Proof step 3 failed") # e(V_g,P_k) * e(V_gb2,-(vk_x+P_a+P_c)) * e(P_b,-P_gb1) == 1 if not pairingProd( (proof.k, self.g), (neg(add(vk_x, add(proof.a, proof.c))), self.gb2), (neg(self.gb1), proof.b)): raise RuntimeError("Proof step 4 failed") # e(P_b, vk_x+P_a) * e(V_z,-P_h) * e(G2,-P_c) == 1 if not pairingProd( (add(vk_x, proof.a), proof.b), (neg(proof.h), self.z), (neg(proof.c), bn128.G2)): raise RuntimeError("Proof step 5 failed") return True
def verify(self, proof): """Verify if a proof is correct for the given inputs""" if not isinstance(proof, Proof): raise TypeError("Invalid proof type") # Compute the linear combination vk_x # vk_x = gammaABC[0] + gammaABC[1]^x[0] + ... + gammaABC[n+1]^x[n] vk_x = self.gammaABC[0] for i, x in enumerate(proof.input): vk_x = add(vk_x, multiply(self.gammaABC[i + 1], x)) # e(B, A) * e(gamma, -vk_x) * e(delta, -C) * e(beta, -alpha) return pairingProd((proof.A, proof.B), (neg(vk_x), self.gamma), (neg(proof.C), self.delta), (neg(self.alpha), self.beta))
def verify(vk: SigningVerificationKey, m: bytes, sigma: int) -> bool: """ Return true if the signature sigma is valid on message m and vk. We assume here that the message is an hexadecimal string written in less than 256 bits to conform with Ethereum bytes32 type. """ # Encode and hash the verifying key and input hashes challenge_to_hash = g1_to_bytes(vk.spk) + m challenge = int(sha256(challenge_to_hash).hexdigest(), 16) challenge = challenge % ZETH_PRIME left_part = ec.multiply(ec.G1, FQ(sigma).n) right_part = ec.add(vk.spk, ec.multiply(vk.ppk, FQ(challenge).n)) return ec.eq(left_part, right_part)
def MixCommitments(a_bytes, b_bytes): #Fetch individual commitments a_asset, a_commitments = ExtractCommitments(a_bytes) b_asset, b_commitments = ExtractCommitments(b_bytes) #Create Mixture c_bytes = bytes() for i in range(0, len(a_commitments)): A = (bn128.FQ(a_commitments[i][0]), bn128.FQ(a_commitments[i][1])) for j in range(0, len(b_commitments)): B = (bn128.FQ(b_commitments[j][0]), bn128.FQ(b_commitments[j][1])) C = bn128.add(A, B) c_bytes += C[0].n.to_bytes(32, 'big') + C[1].n.to_bytes(32, 'big') return c_bytes
def generateCommitment(publicKey, alpha, beta, secretRandomness, currentD0_2i, currentD1_2i, isZeroEncryption): com = Proof() com.secretRandomness = secretRandomness com.isZeroEncryption = isZeroEncryption com.publicKey = publicKey com.alpha = alpha com.beta = beta com.currentD0_2i = currentD0_2i com.currentD1_2i = currentD1_2i if isZeroEncryption == False: com.r2 = getRandomElement() com.d2 = getRandomElement() com.w = getRandomElement() # a1 = w G # b1 = w H com.a1 = bn128.multiply(bn128.G1, com.w.n) com.b1 = bn128.multiply(publicKey, com.w.n) # a2 = r_2G + d2 beta com.a2 = bn128.add(bn128.multiply(bn128.G1, com.r2.n), bn128.multiply(beta, com.d2.n)) # b2 = r_2H + d2 alpha com.b2 = bn128.add(bn128.multiply(publicKey, com.r2.n), bn128.multiply(alpha, com.d2.n)) else: com.r1 = getRandomElement() com.d1 = getRandomElement() com.w = getRandomElement() # a1 = r_1 G + d1 (beta - 2iD0) inner = bn128.add(beta, bn128.neg(currentD0_2i)) com.a1 = bn128.add(bn128.multiply(bn128.G1, com.r1.n), bn128.multiply(inner, com.d1.n)) # b1 = r_1 H + d1 (alpha - 2i D_1) inner = bn128.add(alpha, bn128.neg(currentD1_2i)) com.b1 = bn128.add(bn128.multiply(publicKey, com.r1.n), bn128.multiply(inner, com.d1.n)) # a2 = w G # b2 = w H com.a2 = bn128.multiply(bn128.G1, com.w.n) com.b2 = bn128.multiply(publicKey, com.w.n) return com
def pedersen_c(v, r=None): if r is None: r = randsn() return add(multiply(G1, v), multiply(H, r)), r
from time import time from py_eth_pairing import curve_add, curve_mul, pairing2, curve_negate from py_ecc.bn128 import G1, G2, add, multiply, curve_order, pairing print("curve_add") t0 = time() actual = curve_add(G1, G1) print(time() - t0) expected = add(G1, G1) assert actual == expected print("curve_mul") sc = curve_order - 10 g1_pk = multiply(G1, sc) t0 = time() actual = curve_mul(g1_pk, sc) print(time() - t0) expected = multiply(g1_pk, sc) assert actual == expected print("pairing2: expect true") sc = 123 g1_pk = multiply(G1, sc) g2_pk = multiply(G2, sc) t0 = time() actual = pairing2(curve_negate(g1_pk), G2, G1, g2_pk) print(time() - t0) expected = True assert actual == expected
def GenerateOneBitRangeProofs( count=16, asset_address=0x0000000000000000000000000000000000000000, compress_proofs=False, print_proof=False): sr = SystemRandom() #Pick values and blinding factors #Pick equal number of each assert (IsPowerOf2(count)) if count == 1: pc = [(sr.randint(0, 1), sr.getrandbits(256))] pcp = [] else: pc = [(sr.randint(0, 1), sr.getrandbits(256)) for i in range(0, count // 2)] pcp = [(1 - pc[i][0], sr.getrandbits(256)) for i in range(0, count // 2)] private_commitments = pc + pcp if (count % 1 == 1): private_commitments += (sr.randint(0, 1), sr.getrandbits(256)) #Get generator points G1 = bn128.G1 H = H_from_address(asset_address) #Initialize proof memory proofs = asset_address.to_bytes(20, 'big') for x in private_commitments: #Calculate Ring C = bn128.multiply(G1, x[1]) if x[0] == 1: C = bn128.add(C, H) #Random Numbers alpha = sr.getrandbits(256) s0 = sr.getrandbits(256) #Begin Ring A = bn128.multiply(G1, alpha) c0 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Segment 0 A = bn128.multiply(C, c0) B = bn128.multiply(G1, s0) A = bn128.add(A, B) c1 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Complete Ring s1 = (alpha - c1 * x[1]) % bn128.curve_order else: #"Random Numbers" alpha = sr.getrandbits(256) s1 = sr.getrandbits(256) #Being Ring A = bn128.multiply(G1, alpha) c1 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Segment 1 Cp = bn128.add(C, (H[0], -H[1])) A = bn128.multiply(Cp, c1) B = bn128.multiply(G1, s1) A = bn128.add(A, B) c0 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Complete Ring s0 = (alpha - c0 * x[1]) % bn128.curve_order #Store proof data if compress_proofs: c_compressed = C[0].n if (C[1].n & 1 == 1): c_compressed |= 0x8000000000000000000000000000000000000000000000000000000000000000 proofs += c_compressed.to_bytes(32, 'big') else: proofs += C[0].n.to_bytes(32, 'big') proofs += C[1].n.to_bytes(32, 'big') proofs += c0.to_bytes(32, 'big') proofs += s0.to_bytes(32, 'big') proofs += s1.to_bytes(32, 'big') if (print_proof): print("Proof:") print("0x" + proofs.hex()) return private_commitments, proofs
def ecAdd(p1: Point, p2: Point) -> Point: p1 = FQ(p1[0]), FQ(p1[1]) p2 = FQ(p2[0]), FQ(p2[1]) return fq2point(add(p1, p2))
s0 = sr.getrandbits(256) G1 = bn128.G1 P = bn128.multiply(G1, p) Q = bn128.multiply(G1, q) #Being Ring A = bn128.multiply(G1, alpha) c0 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Segment 0 A = bn128.multiply(P, c0) B = bn128.multiply(G1, s0) A = bn128.add(A, B) c1 = int.from_bytes( keccak_256(A[0].n.to_bytes(32, 'big') + A[1].n.to_bytes(32, 'big')).digest(), 'big') #Complete Ring s1 = (alpha - c1 * q) % bn128.curve_order #Mix Ring if sr.randrange(0, 2) == 0: P, Q, c0, s0, s1 = Q, P, c1, s1, s0 #Output print(hex(P[0].n)) print(hex(P[1].n)) print(hex(Q[0].n))
# t(x) = 0x^3 + 1x^2 - 3x + 2 t_coefficients = [0, 1, 3, 2][::-1] # h(x) = 0x^3 + 0x^2 - 1x + 0 h_coefficients = [0, 0, 1, 0][::-1] s = randsn() alpha = randsn() ### Setup g_s_i = [multiply(bn128.G2, pow(s, i)) for i in range(polynomial_degree)] g_alpha_s_i = list(map(lambda x: multiply(x, alpha), g_s_i)) g_alpha = multiply(bn128.G1, alpha) g_t_s = reduce(lambda acc, x: add(acc, x), [ multiply(bn128.G1, t_coefficients[i] * pow(s, i)) for i in range(polynomial_degree) ]) ### Proving g_p_s = reduce( lambda acc, x: add(acc, x), [multiply(g_s_i[i], p_coefficients[i]) for i in range(polynomial_degree)]) g_h_s = reduce( lambda acc, x: add(acc, x), [multiply(g_s_i[i], h_coefficients[i]) for i in range(polynomial_degree)]) g_alpha_p_s = reduce(lambda acc, x: add(acc, x), [ multiply(g_alpha_s_i[i], p_coefficients[i])
if __name__ == "__main__": #Open DB db = TinyDB('client_db.json') tbl = db.table('commitments') data = tbl.all() assert (len(data) > 0) #Index private commitments and sort by hidden value bit v = 100 asset_address = 0 private_bit_commitments = data[0]['private'] indices, total_bf = BuildCommitmentPrivate(v, private_bit_commitments, target_bits=64) C_expected = bn128.add(bn128.multiply(bn128.G1, total_bf), bn128.multiply(H_from_address(asset_address), v)) print("Commitment Generated") print("asset_address = 0x" + asset_address.to_bytes(20, 'big').hex()) print("value = " + str(v)) print("bf = " + hex(total_bf)[2:]) print("(" + C_expected[0].n.to_bytes(32, 'big').hex() + ",") print(C_expected[1].n.to_bytes(32, 'big').hex() + ")") print() #Test commitment build _, public_bit_commitments = ExtractCommitments( bytes.fromhex(data[0]['data'])) C_out = BuildCommitmentPublic(public_bit_commitments, indices) print("Assembled Commitment") print("(" + C_out[0].n.to_bytes(32, 'big').hex() + ",") print(C_out[1].n.to_bytes(32, 'big').hex() + ")")
def add(pointA: Point, pointB: Point) -> Point: # wrapper for bn128.add, adding/removing the FQ class return _unwrap(bn128.add(_wrap(pointA), _wrap(pointB)))
def Enc(pk, m, r): X = bn128.multiply(pk, r) Y = bn128.add(bn128.multiply(bn128.G1, r), bn128.multiply(H, m)) return (X, Y)