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}
50
51func max(a, b int) int {
52 if a > b {
53 return a
54 }
55 return b
56}
57
58func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int {
59 r := ArrayOfBigZeros(max(len(a), len(b)))
60 for i := 0; i < len(a); i++ {
61 r[i] = pf.F.Add(r[i], a[i])
62 }
63 for i := 0; i < len(b); i++ {
64 r[i] = pf.F.Add(r[i], b[i])
65 }
66 return r
67}
68
69func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
70 r := ArrayOfBigZeros(max(len(a), len(b)))
71 for i := 0; i < len(a); i++ {
72 r[i] = pf.F.Add(r[i], a[i])
73 }
74 for i := 0; i < len(b); i++ {
75 // bneg := pf.F.Mul(b[i], big.NewInt(int64(-1)))
76 // r[i] = pf.F.Add(r[i], bneg)
77 r[i] = pf.F.Sub(r[i], b[i])
78 }
79 return r
80}
81
82// func FloatPow(a *big.Int, e int) *big.Int {
83// if e == 0 {
84// return big.NewInt(int64(1))
85// }
86// result := new(big.Int).Copy(a)
87// for i := 0; i < e-1; i++ {
88// result = new(big.Int).Mul(result, a)
89// }
90// return result
91// }
92
93func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int {
94 r := big.NewInt(int64(0))
95 for i := 0; i < len(v); i++ {
96 // xi := FloatPow(x, i)
97 xi := pf.F.Exp(x, big.NewInt(int64(i)))
98 elem := pf.F.Mul(v[i], xi)
99 r = pf.F.Add(r, elem)
100 }
101 return r
102}
103
104func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int {
105 fac := 1
106 for i := 1; i < totalPoints+1; i++ {
107 if i != pointPos {
108 fac = fac * (pointPos - i)
109 }
110 }
111 facBig := big.NewInt(int64(fac))
112 hf := pf.F.Div(height, facBig)
113 r := []*big.Int{hf}
114 for i := 1; i < totalPoints+1; i++ {
115 if i != pointPos {
116 ineg := big.NewInt(int64(-i))
117 b1 := big.NewInt(int64(1))
118 r = pf.Mul(r, []*big.Int{ineg, b1})
119 }
120 }
121 return r
122}
123
124func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int {
125 // https://en.wikipedia.org/wiki/Lagrange_polynomial
126 var r []*big.Int
127 for i := 0; i < len(v); i++ {
128 r = pf.Add(r, pf.NewPolZeroAt(i+1, len(v), v[i]))
129 }
130 //
131 return r
132}
133
134func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*big.Int, [][]*big.Int, []*big.Int) {
135 aT := Transpose(a)
136 bT := Transpose(b)
137 cT := Transpose(c)
138 var alpha [][]*big.Int
139 for i := 0; i < len(aT); i++ {
140 alpha = append(alpha, pf.LagrangeInterpolation(aT[i]))
141 }
142 var beta [][]*big.Int
143 for i := 0; i < len(bT); i++ {
144 beta = append(beta, pf.LagrangeInterpolation(bT[i]))
145 }
146 var gamma [][]*big.Int
147 for i := 0; i < len(cT); i++ {
148 gamma = append(gamma, pf.LagrangeInterpolation(cT[i]))
149 }
150 z := []*big.Int{big.NewInt(int64(1))}
151 for i := 1; i < len(aT[0])+1; i++ {
152 ineg := big.NewInt(int64(-i))
153 b1 := big.NewInt(int64(1))
154 z = pf.Mul(z, []*big.Int{ineg, b1})
155 }
156 return alpha, beta, gamma, z
157}