| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- #!/usr/bin/env sage
- """
- The following code is taken from the examples outlined in the article:
- "R1CS and QAP - From Zero to Hero with Finite Fields & sagemath".
- (https://risencrypto.github.io/R1CSQAP/). The Sage examples begin at the
- end of the section called "Conversion to Arithemetic Circuits & then R1CS".
- Note that this example uses the same polynomial as the file qap.py
- in this directory.
- """
- header = """
- This script demonstrates the conversion of a set of R1CS matrices to QAP form.
- For more information, read the code comments in the file for this script.
- """
- print(header)
- # Define the R1CS matrices over the finite field GF(41)
- F41 = GF(41)
- L = Matrix(F41, [
- [0,1,0,0,0,0],
- [0,0,0,1,0,0],
- [0,1,0,0,1,0],
- [5,0,0,0,0,1],]
- )
- R = Matrix(F41, [
- [0,1,0,0,0,0],
- [0,1,0,0,0,0],
- [1,0,0,0,0,0],
- [1,0,0,0,0,0,],])
- O = Matrix(F41, [
- [0,0,0,1,0,0],
- [0,0,0,0,1,0],
- [0,0,0,0,0,1],
- [0,0,1,0,0,0,],])
- # Print R1CS matrices
- print(L)
- print()
- print(R)
- print()
- print(O)
- print()
- # Debug: this section should print 35*x^3 + 36*x^2 + 16*x + 36
- # It represents the Lagrange interpolation for the first column of matrix L.
- R41.<x> = PolynomialRing(F41)
- points = [(1,0),(2,0),(3,0),(4,5)]
- R41.lagrange_polynomial(points)
- # Convert matrices L, R, and O to QAP form using Lagrange interpolation, i.e.
- # repeat the above lines of code for every column of every matrix.
- M = [L, R, O]
- PolyM = []
- for m in M:
- PolyList = []
- for i in range(m.ncols()):
- points = []
- for j in range(m.nrows()):
- points.append([j+1,m[j,i]])
- Poly = R41.lagrange_polynomial(points).coefficients(sparse=False)
- if(len(Poly) < m.nrows()):
- # if degree of the polynomial is less than 4
- # we add zeroes to represent the missed out terms
- dif = m.nrows() - len(Poly)
- for c in range(dif):
- Poly.append(0);
- PolyList.append(Poly)
- PolyM.append(Matrix(F41, PolyList))
- # Print the new matrices containing QAP form polynomials.
- # Each matrix should have 6 polynomials. This corresponds to the number of elements
- # in the solution vector (which is 6 using the example from the article).
- print(PolyM[0])
- print()
- print(PolyM[1])
- print()
- print(PolyM[2])
- print()
- # Solution vector (defined over the finite field). This is known only to the prover.
- S = vector(F41,[1, 3, 35, 9, 27, 30])
- # Create the L, Rx & Ox polynomials. Perform the dot product of the solution vector
- # with each of the matrices obtained in the previous step.
- Lx = R41(list(S*PolyM[0]))
- Rx = R41(list(S*PolyM[1]))
- Ox = R41(list(S*PolyM[2]))
- print("Lx = " + str(Lx))
- print("Rx = " + str(Rx))
- print("Ox = " + str(Ox))
- # Multiply polynomials Lx and Rx and subtract Ox. This is how we check the
- # constraints of the circuit and corresponds to checking the vectors in
- # the R1CS step.
- # Note: the verifier does not know the polynomial T.
- T = Lx*Rx - Ox
- print("T(x) = ", end="")
- print(T)
- # Check Tx at x = 1, 2, 3, 4. The output of each should be 0.
- print("T(1) = " + str(T(1)))
- print("T(2) = " + str(T(2)))
- print("T(3) = " + str(T(3)))
- print("T(4) = " + str(T(4)))
- # This polynomial is known to both the prover and verifier
- Z = R41((x-1)*(x-2)*(x-3)*(x-4))
- H = T.quo_rem(Z)
- print("Quotient of Z/T = ", end="")
- print(H[0])
- # The remainder here must be 0, indicating that Z exactly divides T.
- print("Remainder of Z/T = ", end="")
- print(H[1])
|