#!/usr/bin/env sage """ Implements the simplified Nova scheme introduced in [1] Section 5.1 [1] Nova: Recursive Zero-Knowledge Arguments from Folding Schemes https://eprint.iacr.org/2021/370.pdf [2] Nova: The ZK Bug of the Year (by Wilson Nguyen) https://www.youtube.com/watch?v=SOAQCL1NaYY """ q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 K = GF(q) hash_table = {} def hash(key): if key in hash_table: return hash_table[key] c = K.random_element() while c > 2**250 - 1: c = K.random_element() hash_table[key] = c return c def fold(U, u): return U + (u,) z0 = 5 F = lambda z, ω: 5*z i = 0 ω0 = () z1 = F(z0, ω0) u1 = hash((1, z0, z1, ())) U1 = () # ZK proof assert u1 == hash((1, z0, z1, ())) assert z1 == F(z0, ω0) i = 1 ω1 = () U2 = fold(U1, u1) z2 = F(z1, ω1) u2 = hash((i+1, z0, z2, U2)) assert u1 == hash((i, z0, z1, U1)) assert U2 == fold(U1, u1) assert z2 == F(z1, ω1) assert u2 == hash((i+1, z0, z2, U2)) i = 2 ω2 = () U3 = fold(U2, u2) z3 = F(z2, ω2) u3 = hash((i+1, z0, z3, U3)) assert u2 == hash((i, z0, z2, U2)) assert U3 == fold(U2, u2) assert z3 == F(z2, ω2) assert u3 == hash((i+1, z0, z3, U3)) # By folding proofs, we simultaneously verify all the asserts # when verifying U3 with u3. # Although there is no connection between u2 in i=1, and u2 in i=2, # by including the satisfying accumulator U2, and proving U3 = fold(U2, u2), # we guarantee the recursive nature of the circuit. # We've now made a proof of what 5^4 is assert z0 == 5 assert z1 == 5*5 assert z2 == 5*5*5 assert z3 == 5^(i+2)