def pedersen_prover(C, X, x, r, rnd_bytes=os.urandom, RO=sha2): """ Params: x and r are elements of Fp C,X are Points Returns: prf, of the form (KX,KC,sx,sr) """ assert X == x * G assert C == x * G + r * H # TODO: fill in your code here (10 points) # blinding factor kx = uint256_from_str(rnd_bytes(32)) % order kr = uint256_from_str(rnd_bytes(32)) % order # commitment KX = kx * G KC = kx * G + kr * H # receive challenge from random oracle c = uint256_from_str(RO(ser(KX) + ser(KC))) # responses sx = Fp(kx + c * x) sr = Fp(kr + c * r) return (KX, KC, sx, sr)
def arith_prover(a, b, A, B, C, rnd_bytes=os.urandom, RO=sha2): """ Params: a and b are elements of Fp A, B, C are Points Returns: prf, of the form (KA,KB,KC,sa,sb) Must satisfy verify_proof2(A, B, C, prf) Must be zero-knowledge """ assert a * G == A assert b * G == B assert (a * (b - 3)) * G == C # TODO: fill in your code here (10 points) ka = uint256_from_str(rnd_bytes(32)) % order kb = uint256_from_str(rnd_bytes(32)) % order KA = ka * G KB = kb * G KC = kb * A c = uint256_from_str(RO(ser(KA) + ser(KB) + ser(KC))) sa = Fp(ka + a * c) sb = Fp(kb + b * c) return (KA, KB, KC, sa, sb)
def dlog_extractor(A, Adv): assert type(A) is Point ## Step 1: run the adversary to generate a proof while recording ## the random bits and oracle queries # TODO: Fill your code in here i = 0 l = {} found = False found2 = False mapping = {} def RO1(s): assert type(s) is str nonlocal mapping if not s in mapping: mapping[s] = os.urandom(32) return mapping[s] def RO2(s): assert type(s) is str nonlocal mapping if not found2: mapping[s] = os.urandom(32) return mapping[s] def rand(x): nonlocal i, l, found if x == 32 and found: return l[i] elif x == 32 and not found: i += 1 r = os.urandom(x) l[i] = r return r else: return os.urandom(x) (K1, s1) = Adv(A, rnd_bytes=rand, RO=RO1) found = True c1 = uint256_from_str(RO1(ser(K1))) # print("c1",c1,"\n","K1",K1) ## Step 2: run the adversary again, replaying the random bits, ## and intercepting the call to the random oracle # TODO: Fill your code in here (5 points) (K2, s2) = Adv(A, rnd_bytes=rand, RO=RO2) found2 = True c2 = uint256_from_str(RO2(ser(K2))) # print("c2",c2,"\n","K2",K2) ## Step 3: Extract a witness from the two proofs and oracle queries # TODO: Fill your code in here (5 points) return Fp(s1 - s2) / Fp(c1 - c2)
def pedersen_verifier(C, X, prf, RO=sha2): (KX, KC, sx, sr) = prf assert type(KX) == type(KC) == Point assert type(sx) == type(sr) == Fp # Recompute c w/ the information given c = uint256_from_str(RO(ser(KX) + ser(KC))) assert sx.n * G == KX + c * X assert sx.n * G + sr.n * H == KC + c * C return True
def arith_verifier(A, B, C, prf, rnd_bytes=os.urandom, RO=sha2): (KA, KB, KC, sa, sb) = prf assert type(KA) == type(KB) == type(KC) == Point assert type(sa) == type(sb) == Fp # TODO: fill in your code here (10 points) c = uint256_from_str(RO(ser(KA) + ser(KB) + ser(KC))) assert sa.n * G == KA + c * A assert sb.n * G == KB + c * B assert sb.n * A == KC + c * (C + 3 * A) return True
def OR_verifier(A, B, prf, RO=sha2): (KA, KB, sa, sb, ca, cb) = prf assert type(KA) is type(KB) is Point assert type(sa) is type(sb) is Fp # Check the challenges are correctly constrained c = uint256_from_str(RO(ser(KA) + ser(KB))) assert (ca + cb) % p == c # Check each proof the same way assert sa.n * G == KA + ca * A assert sb.n * G == KB + cb * B return True
def pedersen_test(): x = uint256_from_str(os.urandom(32)) X = x * G C, r = make_pedersen_commitment(x) prf = pedersen_prover(C, X, x, r) (KX, KC, sx, sr) = prf print( repr((ser(C), ser(KX), ser(KC), uint256_to_str(sx.n).encode('latin'), uint256_to_str(sr.n).encode('latin')))) assert pedersen_verifier(C, X, prf) print("Pedersen correctness test complete!")
def schnorr_verify(X, m, sig, RO=sha2): assert type(X) is Point assert type(sig) is bytes and len(sig) is 65 (K, s) = deser(sig[:33].hex()), uint256_from_str(sig[33:]) c = uint256_from_str(RO(ser(K) + sha2(m).hex())) assert s * G == K + c * X return True
def pedersen_vector_prover(C_arr, x_arr, r_arr, rnd_bytes=os.urandom, RO=sha2): """ Params: x_arr, r_arr are arrays of elements in Fp C_arr are arrays of Points Returns: prf, of the form (K,sx,sr) where K is points and sx and sr are points in Fp Note that here you are able to prove that knowledge of n points with only communicating 1 ppints and 2 scalars. """ # Make sure all commitments are correct for C_elem, x_elem, r_elem in zip(C_arr, x_arr, r_arr): assert C_elem == x_elem * G + r_elem * H # TODO: Your code goes here: 10 points # commitment K = C_arr[0] c = Fp(uint256_from_str(RO(ser(K)))) sx = x_arr[0] sr = r_arr[0] e = c # responses for i in range(len(C_arr)): sx = Fp(sx + e.n * x_arr[i]) sr = Fp(sr + e.n * r_arr[i]) e = Fp(e * c) # print(e.n) return (K, sx, sr)
def schnorr_sign(x, m, rnd_bytes=os.urandom, RO=sha2): assert type(x) is bytes assert type(m) is str # TODO: Your code goes here (10 points) k = uint256_from_str(rnd_bytes(32)) % order K = k * G c = uint256_from_str(RO(ser(K) + sha2(m).hex())) x = uint256_from_str(x) s = Fp(k + c * x) return bytes.fromhex(ser(K)) + uint256_to_str(s.n)
def sender_round3(M0, M1, a, B, RO=sha2): """ Inputs: M0 and M1, each an element in Fp kR: the secret saved from sender_round1 Returns: (e0,e1), the two ciphertexts """ assert type(a) is Fp assert type(M0) is str and type(M1) is str assert len(M0) == len(M1) == 16 # TODO: your code goes here k0 = RO(ser(a.n * B)) k1 = RO(ser(a.n * (B - a.n * G))) e0 = encrypt(k0, M0) e1 = encrypt(k1, M1) return e0, e1
def dlog_verifier(A, prf, RO=sha2): (K, s) = prf assert type(A) is type(K) is Point assert type(s) is Fp # Recompute c w/ the information given c = uint256_from_str(RO(ser(K))) # Check the verification condition assert s.n * G == K + c * A return True
def OR_prover(A, B, x, rnd_bytes=os.urandom, RO=sha2): assert x * G == A or x * G == B # TODO: Fill your code in here (20 points) ka = uint256_from_str(rnd_bytes(32)) % order kb = uint256_from_str(rnd_bytes(32)) % order KA = ka * G KB = kb * G c = uint256_from_str(RO(ser(KA) + ser(KB))) if x * G != B: ca = c cb = x * order else: ca = x * order cb = c sa = Fp(ka + x * ca) sb = Fp(kb + x * cb) return (KA, KB, sa, sb, ca, cb)
def dlog_prover(A, a, rnd_bytes=os.urandom, RO=sha2): assert a * G == A # blinding factor k = uint256_from_str(rnd_bytes(32)) % order # commitment K = k * G # Invoke the random oracle to receive a challenge c = uint256_from_str(RO(ser(K))) # response s = Fp(k + c * 124213421) return (K, s)
def dlog_prover(A, a, k=uint256_from_str(os.urandom(32)) % order, rnd_bytes=os.urandom, RO=sha2): assert a * G == A # commitment K = k * G # Invoke the random oracle to receive a challenge c = uint256_from_str(RO(ser(K))) # response s = Fp(k + c * a) return (K, s)
def pedersen_vector_verifier(C_arr, prf, rnd_bytes=os.urandom, RO=sha2): (C0, sx, sr) = prf assert type(C0) == Point assert type(sx) == type(sr) == Fp c = Fp(uint256_from_str(RO(ser(C0)))) e = c C_final = C0 for C_elem in C_arr: C_final = C_final + e.n * C_elem e = Fp(e * c) assert C_final == sx.n * G + sr.n * H return True
def receiver_round2(c, A, rnd_bytes=os.urandom, RO=sha2): """ Inputs: c a bit 0 or 1 A the round1 message from the sender Returns: (kR, B) B is sent to the sender, kR is the decryption key, stored and passed to sender_round4 """ assert c in (0, 1) assert type(A) is Point # TODO: Your code goes here b = Fp(uint256_from_str(rnd_bytes(32)) % order) B = b.n * G if c == 0 else A + b.n * G kR = RO(ser(b.n * A)) return kR, B
def Adv(A, rnd_bytes, RO): assert A == a * G while True: # The "picky" prover loops until it is happy # Make a whimsical decision coin = rnd_bytes(1) if ord(coin) < 128: continue k = uint256_from_str(rnd_bytes(32)) % order K = k * G c = uint256_from_str(RO(ser(K))) # I only like challenges that end with 3 zero bits if c & 0b111 != 0: continue # OK I'm satisfied s = Fp(k + c * a) return (K, s)
def dlog_simulator(A, rnd_bytes): """ Returns: - (prf, transcript) - prf, a tuple of the form (K,s), where K is a Point and s is an element of Fp - transcript is an array consisting of elements of the form [...(q,h)...] where each q is a query (a string) and each h is the response (a 32-byte string) """ # TODO: Fill in your code here (10 points) transcript = [] h = rnd_bytes(32) c = uint256_from_str(h) s = uint256_from_str(rnd_bytes(32)) % order K = s * G - c * A q = ser(K) transcript.append((q, h)) return ((K, Fp(s)), transcript)
def dlog_test_simulator(): rnd_bytes = os.urandom # Test with a randomly generated point on curve A = random_point(rnd_bytes=rnd_bytes) (prf, transcript) = dlog_simulator(A, rnd_bytes) # Unpack the proof K, s = prf assert type(K) is Point assert type(s) is Fp # Unpack oracle transcript (there should be just one query) assert len(transcript) == 1 (q, h) = transcript[0] assert q == ser(K) c = uint256_from_str(h) # Check the verification condition assert s.n * G == K + c * A print("DLOG simulator test complete!")