arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/r1csqap/r1csqap.go
r1csqap/r1csqap.goRaw
  1package r1csqap
  2
  3import (
  4	"math/big"
  5
  6	"github.com/arnaucube/go-snark/fields"
  7)
  8
  9// Transpose transposes the *big.Int matrix
 10func Transpose(matrix [][]*big.Int) [][]*big.Int {
 11	var r [][]*big.Int
 12	for i := 0; i < len(matrix[0]); i++ {
 13		var row []*big.Int
 14		for j := 0; j < len(matrix); j++ {
 15			row = append(row, matrix[j][i])
 16		}
 17		r = append(r, row)
 18	}
 19	return r
 20}
 21
 22// ArrayOfBigZeros creates a *big.Int array with n elements to zero
 23func ArrayOfBigZeros(num int) []*big.Int {
 24	bigZero := big.NewInt(int64(0))
 25	var r []*big.Int
 26	for i := 0; i < num; i++ {
 27		r = append(r, bigZero)
 28	}
 29	return r
 30}
 31
 32// PolynomialField is the Polynomial over a Finite Field where the polynomial operations are performed
 33type PolynomialField struct {
 34	F fields.Fq
 35}
 36
 37// NewPolynomialField creates a new PolynomialField with the given FiniteField
 38func NewPolynomialField(f fields.Fq) PolynomialField {
 39	return PolynomialField{
 40		f,
 41	}
 42}
 43
 44// Mul multiplies two polinomials over the Finite Field
 45func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int {
 46	r := ArrayOfBigZeros(len(a) + len(b) - 1)
 47	for i := 0; i < len(a); i++ {
 48		for j := 0; j < len(b); j++ {
 49			r[i+j] = pf.F.Add(
 50				r[i+j],
 51				pf.F.Mul(a[i], b[j]))
 52		}
 53	}
 54	return r
 55}
 56
 57// Div divides two polinomials over the Finite Field, returning the result and the remainder
 58func (pf PolynomialField) Div(a, b []*big.Int) ([]*big.Int, []*big.Int) {
 59	// https://en.wikipedia.org/wiki/Division_algorithm
 60	r := ArrayOfBigZeros(len(a) - len(b) + 1)
 61	rem := a
 62	for len(rem) >= len(b) {
 63		l := pf.F.Div(rem[len(rem)-1], b[len(b)-1])
 64		pos := len(rem) - len(b)
 65		r[pos] = l
 66		aux := ArrayOfBigZeros(pos)
 67		aux1 := append(aux, l)
 68		aux2 := pf.Sub(rem, pf.Mul(b, aux1))
 69		rem = aux2[:len(aux2)-1]
 70	}
 71	return r, rem
 72}
 73
 74func max(a, b int) int {
 75	if a > b {
 76		return a
 77	}
 78	return b
 79}
 80
 81// Add adds two polinomials over the Finite Field
 82func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int {
 83	r := ArrayOfBigZeros(max(len(a), len(b)))
 84	for i := 0; i < len(a); i++ {
 85		r[i] = pf.F.Add(r[i], a[i])
 86	}
 87	for i := 0; i < len(b); i++ {
 88		r[i] = pf.F.Add(r[i], b[i])
 89	}
 90	return r
 91}
 92
 93// Sub subtracts two polinomials over the Finite Field
 94func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
 95	r := ArrayOfBigZeros(max(len(a), len(b)))
 96	for i := 0; i < len(a); i++ {
 97		r[i] = pf.F.Add(r[i], a[i])
 98	}
 99	for i := 0; i < len(b); i++ {
100		r[i] = pf.F.Sub(r[i], b[i])
101	}
102	return r
103}
104
105// Eval evaluates the polinomial over the Finite Field at the given value x
106func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int {
107	r := big.NewInt(int64(0))
108	for i := 0; i < len(v); i++ {
109		xi := pf.F.Exp(x, big.NewInt(int64(i)))
110		elem := pf.F.Mul(v[i], xi)
111		r = pf.F.Add(r, elem)
112	}
113	return r
114}
115
116// NewPolZeroAt generates a new polynomial that has value zero at the given value
117func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int {
118	fac := 1
119	for i := 1; i < totalPoints+1; i++ {
120		if i != pointPos {
121			fac = fac * (pointPos - i)
122		}
123	}
124	facBig := big.NewInt(int64(fac))
125	hf := pf.F.Div(height, facBig)
126	r := []*big.Int{hf}
127	for i := 1; i < totalPoints+1; i++ {
128		if i != pointPos {
129			ineg := big.NewInt(int64(-i))
130			b1 := big.NewInt(int64(1))
131			r = pf.Mul(r, []*big.Int{ineg, b1})
132		}
133	}
134	return r
135}
136
137// LagrangeInterpolation performs the Lagrange Interpolation / Lagrange Polynomials operation
138func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int {
139	// https://en.wikipedia.org/wiki/Lagrange_polynomial
140	var r []*big.Int
141	for i := 0; i < len(v); i++ {
142		r = pf.Add(r, pf.NewPolZeroAt(i+1, len(v), v[i]))
143	}
144	//
145	return r
146}
147
148// R1CSToQAP converts the R1CS values to the QAP values
149func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*big.Int, [][]*big.Int, []*big.Int) {
150	aT := Transpose(a)
151	bT := Transpose(b)
152	cT := Transpose(c)
153	var alphas [][]*big.Int
154	for i := 0; i < len(aT); i++ {
155		alphas = append(alphas, pf.LagrangeInterpolation(aT[i]))
156	}
157	var betas [][]*big.Int
158	for i := 0; i < len(bT); i++ {
159		betas = append(betas, pf.LagrangeInterpolation(bT[i]))
160	}
161	var gammas [][]*big.Int
162	for i := 0; i < len(cT); i++ {
163		gammas = append(gammas, pf.LagrangeInterpolation(cT[i]))
164	}
165	z := []*big.Int{big.NewInt(int64(1))}
166	for i := 1; i < len(aT[0])+1; i++ {
167		ineg := big.NewInt(int64(-i))
168		b1 := big.NewInt(int64(1))
169		z = pf.Mul(z, []*big.Int{ineg, b1})
170	}
171	return alphas, betas, gammas, z
172}
173
174// CombinePolynomials combine the given polynomials arrays into one, also returns the P(x)
175func (pf PolynomialField) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.Int) ([]*big.Int, []*big.Int, []*big.Int, []*big.Int) {
176	var alpha []*big.Int
177	for i := 0; i < len(r); i++ {
178		m := pf.Mul([]*big.Int{r[i]}, ap[i])
179		alpha = pf.Add(alpha, m)
180	}
181	var beta []*big.Int
182	for i := 0; i < len(r); i++ {
183		m := pf.Mul([]*big.Int{r[i]}, bp[i])
184		beta = pf.Add(beta, m)
185	}
186	var gamma []*big.Int
187	for i := 0; i < len(r); i++ {
188		m := pf.Mul([]*big.Int{r[i]}, cp[i])
189		gamma = pf.Add(gamma, m)
190	}
191
192	px := pf.Sub(pf.Mul(alpha, beta), gamma)
193	return alpha, beta, gamma, px
194}
195
196// DivisorPolynomial returns the divisor polynomial given two polynomials
197func (pf PolynomialField) DivisorPolynomial(px, z []*big.Int) []*big.Int {
198	quo, _ := pf.Div(px, z)
199	return quo
200}