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
9func Transpose(matrix [][]*big.Int) [][]*big.Int {
10 var r [][]*big.Int
11 for i := 0; i < len(matrix[0]); i++ {
12 var row []*big.Int
13 for j := 0; j < len(matrix); j++ {
14 row = append(row, matrix[j][i])
15 }
16 r = append(r, row)
17 }
18 return r
19}
20
21func ArrayOfBigZeros(num int) []*big.Int {
22 bigZero := big.NewInt(int64(0))
23 var r []*big.Int
24 for i := 0; i < num; i++ {
25 r = append(r, bigZero)
26 }
27 return r
28}
29
30type PolynomialField struct {
31 F fields.Fq
32}
33
34func NewPolynomialField(f fields.Fq) PolynomialField {
35 return PolynomialField{
36 f,
37 }
38}
39func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int {
40 r := ArrayOfBigZeros(len(a) + len(b) - 1)
41 for i := 0; i < len(a); i++ {
42 for j := 0; j < len(b); j++ {
43 r[i+j] = pf.F.Add(
44 r[i+j],
45 pf.F.Mul(a[i], b[j]))
46 }
47 }
48 return r
49}
50func (pf PolynomialField) Div(a, b []*big.Int) ([]*big.Int, []*big.Int) {
51 // https://en.wikipedia.org/wiki/Division_algorithm
52 r := ArrayOfBigZeros(len(a) - len(b) + 1)
53 rem := a
54 for len(rem) >= len(b) {
55 l := pf.F.Div(rem[len(rem)-1], b[len(b)-1])
56 pos := len(rem) - len(b)
57 r[pos] = l
58 aux := ArrayOfBigZeros(pos)
59 aux1 := append(aux, l)
60 aux2 := pf.Sub(rem, pf.Mul(b, aux1))
61 rem = aux2[:len(aux2)-1]
62 }
63 return r, rem
64}
65
66func max(a, b int) int {
67 if a > b {
68 return a
69 }
70 return b
71}
72
73func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int {
74 r := ArrayOfBigZeros(max(len(a), len(b)))
75 for i := 0; i < len(a); i++ {
76 r[i] = pf.F.Add(r[i], a[i])
77 }
78 for i := 0; i < len(b); i++ {
79 r[i] = pf.F.Add(r[i], b[i])
80 }
81 return r
82}
83
84func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
85 r := ArrayOfBigZeros(max(len(a), len(b)))
86 for i := 0; i < len(a); i++ {
87 r[i] = pf.F.Add(r[i], a[i])
88 }
89 for i := 0; i < len(b); i++ {
90 r[i] = pf.F.Sub(r[i], b[i])
91 }
92 return r
93}
94
95func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int {
96 r := big.NewInt(int64(0))
97 for i := 0; i < len(v); i++ {
98 // xi := FloatPow(x, i)
99 xi := pf.F.Exp(x, big.NewInt(int64(i)))
100 elem := pf.F.Mul(v[i], xi)
101 r = pf.F.Add(r, elem)
102 }
103 return r
104}
105
106func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int {
107 fac := 1
108 for i := 1; i < totalPoints+1; i++ {
109 if i != pointPos {
110 fac = fac * (pointPos - i)
111 }
112 }
113 facBig := big.NewInt(int64(fac))
114 hf := pf.F.Div(height, facBig)
115 r := []*big.Int{hf}
116 for i := 1; i < totalPoints+1; i++ {
117 if i != pointPos {
118 ineg := big.NewInt(int64(-i))
119 b1 := big.NewInt(int64(1))
120 r = pf.Mul(r, []*big.Int{ineg, b1})
121 }
122 }
123 return r
124}
125
126func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int {
127 // https://en.wikipedia.org/wiki/Lagrange_polynomial
128 var r []*big.Int
129 for i := 0; i < len(v); i++ {
130 r = pf.Add(r, pf.NewPolZeroAt(i+1, len(v), v[i]))
131 }
132 //
133 return r
134}
135
136func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*big.Int, [][]*big.Int, []*big.Int) {
137 aT := Transpose(a)
138 bT := Transpose(b)
139 cT := Transpose(c)
140 var alphas [][]*big.Int
141 for i := 0; i < len(aT); i++ {
142 alphas = append(alphas, pf.LagrangeInterpolation(aT[i]))
143 }
144 var betas [][]*big.Int
145 for i := 0; i < len(bT); i++ {
146 betas = append(betas, pf.LagrangeInterpolation(bT[i]))
147 }
148 var gammas [][]*big.Int
149 for i := 0; i < len(cT); i++ {
150 gammas = append(gammas, pf.LagrangeInterpolation(cT[i]))
151 }
152 z := []*big.Int{big.NewInt(int64(1))}
153 for i := 1; i < len(aT[0])+1; i++ {
154 ineg := big.NewInt(int64(-i))
155 b1 := big.NewInt(int64(1))
156 z = pf.Mul(z, []*big.Int{ineg, b1})
157 }
158 return alphas, betas, gammas, z
159}
160
161func (pf PolynomialField) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.Int) ([]*big.Int, []*big.Int, []*big.Int, []*big.Int) {
162 var alpha []*big.Int
163 for i := 0; i < len(r); i++ {
164 m := pf.Mul([]*big.Int{r[i]}, ap[i])
165 alpha = pf.Add(alpha, m)
166 }
167 var beta []*big.Int
168 for i := 0; i < len(r); i++ {
169 m := pf.Mul([]*big.Int{r[i]}, bp[i])
170 beta = pf.Add(beta, m)
171 }
172 var gamma []*big.Int
173 for i := 0; i < len(r); i++ {
174 m := pf.Mul([]*big.Int{r[i]}, cp[i])
175 gamma = pf.Add(gamma, m)
176 }
177
178 px := pf.Sub(pf.Mul(alpha, beta), gamma)
179 return alpha, beta, gamma, px
180}
181
182func (pf PolynomialField) DivisorPolinomial(px, z []*big.Int) []*big.Int {
183 quo, _ := pf.Div(px, z)
184 return quo
185}