| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- import numpy as np
- # Lets prove we know the answer to x**3 + x + 5 == 35 (x = 5)
- # We break it down into these statements:
- # L1: s1 = x * x
- # L2: y = s1 * x
- # L3: s2 = y + x
- # L4: out = s2 + 5
- # Statements are of the form:
- # a * b = c
- # s1 = x * x
- # OR a * b = c, where a = x, b = x and c = s1
- L1 = np.array([
- # a b c
- [0, 0, 0], # 1
- [1, 1, 0], # x
- [0, 0, 0], # out
- [0, 0, 1], # s1
- [0, 0, 0], # y
- [0, 0, 0] # s2
- ])
- # y = s1 * x
- L2 = np.array([
- # a b c
- [0, 0, 0], # 1
- [0, 1, 0], # x
- [0, 0, 0], # out
- [1, 0, 0], # s1
- [0, 0, 1], # y
- [0, 0, 0] # s2
- ])
- # s2 = y + x
- L3 = np.array([
- # a b c
- [0, 1, 0], # 1
- [1, 0, 0], # x
- [0, 0, 0], # out
- [0, 0, 0], # s1
- [1, 0, 0], # y
- [0, 0, 1] # s2
- ])
- # out = s2 + 5
- L4 = np.array([
- # a b c
- [5, 1, 0], # 1
- [0, 0, 0], # x
- [0, 0, 1], # out
- [0, 0, 0], # s1
- [0, 0, 0], # y
- [1, 0, 0] # s2
- ])
- a = np.array([L.transpose()[0] for L in (L1, L2, L3, L4)])
- b = np.array([L.transpose()[1] for L in (L1, L2, L3, L4)])
- c = np.array([L.transpose()[2] for L in (L1, L2, L3, L4)])
- print("A")
- print(a)
- print("B")
- print(b)
- print("C")
- print(c)
- # The witness
- s = np.array([
- 1,
- 3,
- 35,
- 9,
- 27,
- 30
- ])
- print()
- #print(s * a * s * b - s * c)
- for a_i, b_i, c_i in zip(a, b, c):
- assert sum(s * a_i) * sum(s * b_i) - sum(s * c_i) == 0
- print("R1CS done.")
- print()
- def factorial(x):
- r = 1
- for x_i in range(2, x + 1):
- r *= x_i
- return r
- def combinations(n, r):
- return factorial(n) / (factorial(n - r) * factorial(r))
- def lagrange(points):
- result = np.poly1d([0])
- for i, (x_i, y_i) in enumerate(points):
- poly = np.poly1d([y_i])
- for j, (x_j, y_j) in enumerate(points):
- if i == j:
- continue
- poly *= np.poly1d([1, -x_j]) / (x_i - x_j)
- #print(poly)
- #print(poly(1), poly(2), poly(3))
- result += poly
- return result
- # 1.5, -5.5, 7
- #poly = lagrange([(1, 3), (2, 2), (3, 4)])
- #print(poly)
- def make_qap(a):
- a_qap = []
- a_polys = []
- for a_i in a.transpose():
- poly = lagrange(list(enumerate(a_i, start=1)))
- coeffs = poly.c.tolist()
- if len(coeffs) < 4:
- coeffs = [0] * (4 - len(coeffs)) + coeffs
- a_qap.append(coeffs)
- a_polys.append(poly)
- a_qap = np.array(a_qap)
- print(a_qap)
- return a_polys
- print("A")
- a_polys = make_qap(a)
- print("B")
- b_polys = make_qap(b)
- print("C")
- c_polys = make_qap(c)
- def check(polys, x):
- results = []
- for poly in polys:
- results.append(int(poly(x)))
- return results
- print()
- print("A results at x", check(a_polys, 1))
- print()
- print("B results at x", check(b_polys, 1))
- print()
- print("C results at x", check(c_polys, 1))
- def combine_polys(polys):
- r = np.poly1d([0])
- for s_i, p_i in zip(s, polys):
- r += s_i * p_i
- return r
- print()
- print()
- A = combine_polys(a_polys)
- print("A =")
- print(A)
- B = combine_polys(b_polys)
- print("B =")
- print(B)
- C = combine_polys(c_polys)
- print("C =")
- print(C)
- print()
- t = A * B - C
- print("t =")
- print(t)
- # 4 statements in our R1CS: L1, L2, L3, L4
- divisor_poly = np.poly1d([1])
- for x in range(1, 4 + 1):
- divisor_poly *= np.poly1d([1, -x])
- quot, remainder = np.polydiv(t, divisor_poly)
- assert len(remainder.c) == 1
- print()
- print("Result of QAP:")
- print(int(remainder.c[0]))
|