You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
5.9 KiB

5 years ago
5 years ago
  1. package r1csqap
  2. import (
  3. "math/big"
  4. "github.com/arnaucube/go-snark/fields"
  5. )
  6. var bigZero = big.NewInt(int64(0))
  7. // Transpose transposes the *big.Int matrix
  8. func Transpose(matrix [][]*big.Int) [][]*big.Int {
  9. r := make([][]*big.Int, len(matrix[0]))
  10. for x, _ := range r {
  11. r[x] = make([]*big.Int, len(matrix))
  12. }
  13. for y, s := range matrix {
  14. for x, e := range s {
  15. r[x][y] = e
  16. }
  17. }
  18. return r
  19. }
  20. // ArrayOfBigZeros creates a *big.Int array with n elements to zero
  21. func ArrayOfBigZeros(num int) []*big.Int {
  22. var r = make([]*big.Int, num, num)
  23. for i := 0; i < num; i++ {
  24. r[i] = bigZero
  25. }
  26. return r
  27. }
  28. func BigArraysEqual(a, b []*big.Int) bool {
  29. if len(a) != len(b) {
  30. return false
  31. }
  32. for i := 0; i < len(a); i++ {
  33. if a[i].Cmp(b[i]) != 0 {
  34. return false
  35. }
  36. }
  37. return true
  38. }
  39. // PolynomialField is the Polynomial over a Finite Field where the polynomial operations are performed
  40. type PolynomialField struct {
  41. F fields.Fq
  42. }
  43. // NewPolynomialField creates a new PolynomialField with the given FiniteField
  44. func NewPolynomialField(f fields.Fq) PolynomialField {
  45. return PolynomialField{
  46. f,
  47. }
  48. }
  49. // Mul multiplies two polinomials over the Finite Field
  50. func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int {
  51. r := ArrayOfBigZeros(len(a) + len(b) - 1)
  52. for i := 0; i < len(a); i++ {
  53. for j := 0; j < len(b); j++ {
  54. r[i+j] = pf.F.Add(
  55. r[i+j],
  56. pf.F.Mul(a[i], b[j]))
  57. }
  58. }
  59. return r
  60. }
  61. // Div divides two polinomials over the Finite Field, returning the result and the remainder
  62. func (pf PolynomialField) Div(a, b []*big.Int) ([]*big.Int, []*big.Int) {
  63. // https://en.wikipedia.org/wiki/Division_algorithm
  64. r := ArrayOfBigZeros(len(a) - len(b) + 1)
  65. rem := a
  66. for len(rem) >= len(b) {
  67. l := pf.F.Div(rem[len(rem)-1], b[len(b)-1])
  68. pos := len(rem) - len(b)
  69. r[pos] = l
  70. aux := ArrayOfBigZeros(pos)
  71. aux1 := append(aux, l)
  72. aux2 := pf.Sub(rem, pf.Mul(b, aux1))
  73. rem = aux2[:len(aux2)-1]
  74. }
  75. return r, rem
  76. }
  77. func max(a, b int) int {
  78. if a > b {
  79. return a
  80. }
  81. return b
  82. }
  83. // Add adds two polinomials over the Finite Field
  84. func (pf PolynomialField) Add(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.Add(r[i], b[i])
  91. }
  92. return r
  93. }
  94. // Sub subtracts two polinomials over the Finite Field
  95. func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
  96. r := ArrayOfBigZeros(max(len(a), len(b)))
  97. for i := 0; i < len(a); i++ {
  98. r[i] = pf.F.Add(r[i], a[i])
  99. }
  100. for i := 0; i < len(b); i++ {
  101. r[i] = pf.F.Sub(r[i], b[i])
  102. }
  103. return r
  104. }
  105. // Eval evaluates the polinomial over the Finite Field at the given value x
  106. func (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. // NewPolZeroAt generates a new polynomial that has value zero at the given value
  116. func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int {
  117. //todo note that this will blow up. big may be necessary
  118. fac := 1
  119. //(xj-x0)(xj-x1)..(xj-x_j-1)(xj-x_j+1)..(x_j-x_k)
  120. for i := 1; i < totalPoints+1; i++ {
  121. if i != pointPos {
  122. fac = fac * (pointPos - i)
  123. }
  124. }
  125. facBig := big.NewInt(int64(fac))
  126. hf := pf.F.Div(height, facBig)
  127. r := []*big.Int{hf}
  128. for i := 1; i < totalPoints+1; i++ {
  129. if i != pointPos {
  130. ineg := big.NewInt(int64(-i))
  131. //is b1 necessary?
  132. b1 := big.NewInt(int64(1))
  133. r = pf.Mul(r, []*big.Int{ineg, b1})
  134. }
  135. }
  136. return r
  137. }
  138. // LagrangeInterpolation performs the Lagrange Interpolation / Lagrange Polynomials operation
  139. func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int {
  140. // https://en.wikipedia.org/wiki/Lagrange_polynomial
  141. var r []*big.Int
  142. for i := 0; i < len(v); i++ {
  143. //NOTE this comparison gives a huge performance boost
  144. if v[i].Cmp(bigZero) != 0 {
  145. r = pf.Add(r, pf.NewPolZeroAt(i+1, len(v), v[i]))
  146. }
  147. //r = pf.Mul(v[i], pf.NewPolZeroAt(i+1, len(v), v[i]))
  148. }
  149. //
  150. return r
  151. }
  152. // R1CSToQAP converts the R1CS values to the QAP values
  153. //it uses Lagrange interpolation to to fit a polynomial through each slice. The x coordinate
  154. //is simply a linear increment starting at 1
  155. //within this process, the polynomial is evaluated at position 0
  156. //so an alpha/beta/gamma value is the polynomial evaluated at 0
  157. // the domain polynomial therefor is (-1+x)(-2+x)...(-n+x)
  158. func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) (alphas [][]*big.Int, betas [][]*big.Int, gammas [][]*big.Int, domain []*big.Int) {
  159. aT := Transpose(a)
  160. bT := Transpose(b)
  161. cT := Transpose(c)
  162. for i := 0; i < len(aT); i++ {
  163. alphas = append(alphas, pf.LagrangeInterpolation(aT[i]))
  164. }
  165. for i := 0; i < len(bT); i++ {
  166. betas = append(betas, pf.LagrangeInterpolation(bT[i]))
  167. }
  168. for i := 0; i < len(cT); i++ {
  169. gammas = append(gammas, pf.LagrangeInterpolation(cT[i]))
  170. }
  171. //it used to range till len(alphas)-1, but this was wrong.
  172. z := []*big.Int{big.NewInt(int64(1))}
  173. for i := 1; i < len(a); i++ {
  174. z = pf.Mul(
  175. z,
  176. []*big.Int{
  177. pf.F.Neg(
  178. big.NewInt(int64(i))),
  179. big.NewInt(int64(1)),
  180. })
  181. }
  182. return alphas, betas, gammas, z
  183. }
  184. // CombinePolynomials combine the given polynomials arrays into one, also returns the P(x)
  185. func (pf PolynomialField) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.Int) ([]*big.Int, []*big.Int, []*big.Int, []*big.Int) {
  186. var ax []*big.Int
  187. for i := 0; i < len(r); i++ {
  188. m := pf.Mul([]*big.Int{r[i]}, ap[i])
  189. ax = pf.Add(ax, m)
  190. }
  191. var bx []*big.Int
  192. for i := 0; i < len(r); i++ {
  193. m := pf.Mul([]*big.Int{r[i]}, bp[i])
  194. bx = pf.Add(bx, m)
  195. }
  196. var cx []*big.Int
  197. for i := 0; i < len(r); i++ {
  198. m := pf.Mul([]*big.Int{r[i]}, cp[i])
  199. cx = pf.Add(cx, m)
  200. }
  201. px := pf.Sub(pf.Mul(ax, bx), cx)
  202. return ax, bx, cx, px
  203. }
  204. // DivisorPolynomial returns the divisor polynomial given two polynomials
  205. func (pf PolynomialField) DivisorPolynomial(px, z []*big.Int) []*big.Int {
  206. quo, _ := pf.Div(px, z)
  207. return quo
  208. }