def _wrap(point): if len(point) == 2: x, y = point return bn128.FQ(x), bn128.FQ(y) if len(point) == 4: ai, a, bi, b = point return bn128.FQ2([a, ai]), bn128.FQ2([b, bi]) raise ValueError(f"Invalid argument point: {point}")
def hash_to_G1_old(msg: Any) -> PointG1: i = 0 while True: h = hashlib.sha3_256(f"{i} || {msg}".encode()).digest() x = int.from_bytes(h, "big") % bn128.field_modulus y = sympy.sqrt_mod(x**3 + 3, bn128.field_modulus) if y: assert y**2 % bn128.field_modulus == (x**3 + 3) % bn128.field_modulus return _unwrap((bn128.FQ(x), bn128.FQ(y))) i += 1
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
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 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 evaluate(self, x): result = 0 i = 0 for coefficient in self.coefficients: result = (result + (coefficient.n * pow(x, i, bn128.curve_order)) ) % bn128.curve_order i += 1 return bn128.FQ(result % bn128.curve_order)
def H_from_address(address): if type(address) == bytes: x = bn128.FQ(int.from_bytes(keccak_256(address).digest(), 'big')) else: x = bn128.FQ( int.from_bytes( keccak_256(address.to_bytes(20, 'big')).digest(), 'big')) on_curve = False while not on_curve: y2 = x**3 + bn128.b y = y2**((bn128.field_modulus + 1) // 4) if (y**2 == y2): on_curve = True else: x += 1 return (x, y)
def hashPointsToCurve(points): hashableString = "" for point in points: hashableString += repr(point[0]) + repr(point[1]) hashableString = hashableString.encode('utf-8') return bn128.FQ((int(hashlib.sha256(hashableString).hexdigest(), 16) % bn128.curve_order))
async def constructPartyPart(senderAddress, ciphertext, challenge, secretKeyPart, x, client, attemptID): psi = getRandomElement() c0I = bn128.multiply(bn128.multiply(ciphertext.first, psi.n), secretKeyPart.n) k_i = bn128.multiply(bn128.multiply(bn128.G2, challenge.n), inv(psi.n, bn128.curve_order)) com = SecondNIZKP.generateCommitment(ciphertext.first) challenge = bn128.FQ( client.getChallengeNZIK2(attemptID, com[1], com[2], bn128.FQ(x))) nzik2 = SecondNIZKP.generateProof(com[0], com[1], com[2], secretKeyPart, challenge) cost = client.verifyNZIK2(attemptID, senderAddress, nzik2.c_0_tilde_r, nzik2.g_r, nzik2.proof) return (c0I, k_i, nzik2, cost)
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 getLagrange(x, others): product = 1 for xOther in others: if x != xOther.n: upperTerm = (-(xOther.n) + bn128.curve_order) % bn128.curve_order lowerTerm = inv( ((x - xOther.n) + bn128.curve_order) % bn128.curve_order, bn128.curve_order) product = (product * ((upperTerm * lowerTerm) % bn128.curve_order) % bn128.curve_order) return bn128.FQ(product)
def computeProof(commitment, challenge): # we calculate the proof depending on which encryption we have if commitment.isZeroEncryption: commitment.d2 = bn128.FQ( (challenge.n - commitment.d1.n + bn128.curve_order) % bn128.curve_order) commitment.r2 = bn128.FQ( ((commitment.w.n - ((commitment.secretRandomness.n * commitment.d2.n) % bn128.curve_order)) + bn128.curve_order) % bn128.curve_order) else: commitment.d1 = bn128.FQ( ((challenge.n - commitment.d2.n) + bn128.curve_order) % bn128.curve_order) commitment.r1 = bn128.FQ( ((commitment.w.n - ((commitment.secretRandomness.n * commitment.d1.n) % bn128.curve_order)) + bn128.curve_order) % bn128.curve_order) # now holds the proof as well return commitment
def fromBlockchain(array): return Ciphertext((bn128.FQ(array[0][0]), bn128.FQ(array[0][1])), (bn128.FQ(array[1][0]), bn128.FQ(array[1][1])))
def generateProof(r, c_0_tilde_r, g_r, secretKey, challenge): z = (((secretKey.n * challenge.n) % bn128.curve_order) + r.n) % bn128.curve_order return SecondNIZKP(c_0_tilde_r, g_r, bn128.FQ(z))
from random import SystemRandom from py_ecc import bn128 from sha3 import keccak_256 H = (bn128.FQ( 0x231c7944cd500565013d56c25cc8c77a6613cb6b2ccd0831240d1e8d3eea33e3), bn128.FQ( 0x909c50f22cfb8da32dc5a2ad0380e1c0f5b0d9860dd49a566da7f77c600d03c)) def Gen(): sk = SystemRandom().getrandbits(256) pk = bn128.multiply(bn128.G1, sk) return (sk, pk) 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) 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
def getRandomElement(): newElement = 0 while (newElement == 0 or newElement == 1): newElement = secrets.randbelow(bn128.curve_order) return bn128.FQ(newElement)
def hashToCurve(message): return bn128.FQ( (int(hashlib.sha256(message).hexdigest(), 16) % bn128.curve_order))
async def run(threshold, amount, runID, contractAddress): runtimeInfo = {} accounts = BlockchainProvider.getAccounts(providerURL) secretKeys = [] members = [] client = BlockchainProvider(providerURL, contractABIPath, contractAddress, accounts[10 + runID]) # Setup secret sharing and generate a sharing for the parties secretKey = getRandomElement() publicKey = bn128.multiply(bn128.G1, secretKey.n) shares = generateSharing(secretKey, threshold, amount) p = getRandomElement() # a is the input string a user would give, mapped into FQ. For this prototype we just use a random value. a = getRandomElement() elGamalInstance = ElGamal(publicKey) dCipher = elGamalInstance.encrypt(p) cCipher = elGamalInstance.encryptC(a, p) for i in range(amount): members.append(toChecksum(accounts[i + 1])) secretKeys.append(shares[i].y) # Create the group runtimeInfo['GroupCreation'] = client.createCommittee( members, amount, cCipher, dCipher, None) print("Group with ", amount, " members created!") runtimeInfo['AddKey'] = 0 runtimeInfo['AddPart'] = 0 runtimeInfo['PoK1'] = 0 runtimeInfo['PoK2'] = 0 runtimeInfo['Validation'] = 0 # Each party posts its public keys for i in range(amount): cost = client.addKey(bn128.multiply(bn128.G1, secretKeys[i].n), members[i]) runtimeInfo['AddKey'] += cost runtimeInfo['GroupCreation'] += cost print("Constructing query. This will take a while ...") # For now we only want to send one attempt attemptIDAsBytes = bytes('0x' + str(1), 'utf8') # Construct the query as encryption of the binary encoding encodedQuery = await constructBinaryRepresentation(client, attemptIDAsBytes, elGamalInstance, dCipher, a, p, secretKey) # Add up the binary encoding and calculate c0_tilde and c1_tilde addedCiphertexts = encodedQuery[0][0] for i in range(len(encodedQuery[0])): if i != 0: addedCiphertexts *= encodedQuery[0][i] cTilde = cCipher * addedCiphertexts challenge = bn128.FQ(client.getKScalar(attemptIDAsBytes)) k = bn128.multiply(bn128.G2, challenge.n) runtimeInfo['Query'] = client.query(attemptIDAsBytes, encodedQuery[0], encodedQuery[1], cTilde.first, cTilde.second, k) print("Query sent") xOthers = [] for x in range(1, amount + 1): xOthers.append(bn128.FQ(x)) # each party now calculates its parts based on its secret key for i in range(amount): partyPartSingle = await constructPartyPart(members[i], cTilde, challenge, shares[i].y, i + 1, client, attemptIDAsBytes) cost = client.addPart(attemptIDAsBytes, members[i], partyPartSingle[0], partyPartSingle[1]) runtimeInfo['AddPart'] += cost runtimeInfo['Validation'] += cost + partyPartSingle[3] print("Parties have submitted their parts") await asyncio.sleep(1) runtimeInfo['Verify'] = client.verdict(attemptIDAsBytes) return runtimeInfo