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.

200 lines
5.1 KiB

  1. package r1csqap
  2. import (
  3. "math/big"
  4. "github.com/arnaucube/go-snark/fields"
  5. )
  6. // Transpose transposes the *big.Int matrix
  7. func Transpose(matrix [][]*big.Int) [][]*big.Int {
  8. var r [][]*big.Int
  9. for i := 0; i < len(matrix[0]); i++ {
  10. var row []*big.Int
  11. for j := 0; j < len(matrix); j++ {
  12. row = append(row, matrix[j][i])
  13. }
  14. r = append(r, row)
  15. }
  16. return r
  17. }
  18. // ArrayOfBigZeros creates a *big.Int array with n elements to zero
  19. func ArrayOfBigZeros(num int) []*big.Int {
  20. bigZero := big.NewInt(int64(0))
  21. var r []*big.Int
  22. for i := 0; i < num; i++ {
  23. r = append(r, bigZero)
  24. }
  25. return r
  26. }
  27. // PolynomialField is the Polynomial over a Finite Field where the polynomial operations are performed
  28. type PolynomialField struct {
  29. F fields.Fq
  30. }
  31. // NewPolynomialField creates a new PolynomialField with the given FiniteField
  32. func NewPolynomialField(f fields.Fq) PolynomialField {
  33. return PolynomialField{
  34. f,
  35. }
  36. }
  37. // Mul multiplies two polinomials over the Finite Field
  38. func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int {
  39. r := ArrayOfBigZeros(len(a) + len(b) - 1)
  40. for i := 0; i < len(a); i++ {
  41. for j := 0; j < len(b); j++ {
  42. r[i+j] = pf.F.Add(
  43. r[i+j],
  44. pf.F.Mul(a[i], b[j]))
  45. }
  46. }
  47. return r
  48. }
  49. // Div divides two polinomials over the Finite Field, returning the result and the remainder
  50. func (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. func max(a, b int) int {
  66. if a > b {
  67. return a
  68. }
  69. return b
  70. }
  71. // Add adds two polinomials over the Finite Field
  72. func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int {
  73. r := ArrayOfBigZeros(max(len(a), len(b)))
  74. for i := 0; i < len(a); i++ {
  75. r[i] = pf.F.Add(r[i], a[i])
  76. }
  77. for i := 0; i < len(b); i++ {
  78. r[i] = pf.F.Add(r[i], b[i])
  79. }
  80. return r
  81. }
  82. // Sub substracts two polinomials over the Finite Field
  83. func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
  84. r := ArrayOfBigZeros(max(len(a), len(b)))
  85. for i := 0; i < len(a); i++ {
  86. r[i] = pf.F.Add(r[i], a[i])
  87. }
  88. for i := 0; i < len(b); i++ {
  89. r[i] = pf.F.Sub(r[i], b[i])
  90. }
  91. return r
  92. }
  93. // Eval evaluates the polinomial over the Finite Field at the given value x
  94. func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int {
  95. r := big.NewInt(int64(0))
  96. for i := 0; i < len(v); 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. // NewPolZeroAt generates a new polynomial that has value zero at the given value
  104. func (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. // LagrangeInterpolation performs the Lagrange Interpolation / Lagrange Polynomials operation
  124. func (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. // R1CSToQAP converts the R1CS values to the QAP values
  134. func (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 alphas [][]*big.Int
  139. for i := 0; i < len(aT); i++ {
  140. alphas = append(alphas, pf.LagrangeInterpolation(aT[i]))
  141. }
  142. var betas [][]*big.Int
  143. for i := 0; i < len(bT); i++ {
  144. betas = append(betas, pf.LagrangeInterpolation(bT[i]))
  145. }
  146. var gammas [][]*big.Int
  147. for i := 0; i < len(cT); i++ {
  148. gammas = append(gammas, 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 alphas, betas, gammas, z
  157. }
  158. // CombinePolynomials combine the given polynomials arrays into one, also returns the P(x)
  159. func (pf PolynomialField) CombinePolynomials(r []*big.Int, ap, bp, cp [][]*big.Int) ([]*big.Int, []*big.Int, []*big.Int, []*big.Int) {
  160. var alpha []*big.Int
  161. for i := 0; i < len(r); i++ {
  162. m := pf.Mul([]*big.Int{r[i]}, ap[i])
  163. alpha = pf.Add(alpha, m)
  164. }
  165. var beta []*big.Int
  166. for i := 0; i < len(r); i++ {
  167. m := pf.Mul([]*big.Int{r[i]}, bp[i])
  168. beta = pf.Add(beta, m)
  169. }
  170. var gamma []*big.Int
  171. for i := 0; i < len(r); i++ {
  172. m := pf.Mul([]*big.Int{r[i]}, cp[i])
  173. gamma = pf.Add(gamma, m)
  174. }
  175. px := pf.Sub(pf.Mul(alpha, beta), gamma)
  176. return alpha, beta, gamma, px
  177. }
  178. // DivisorPolynomial returns the divisor polynomial given two polynomials
  179. func (pf PolynomialField) DivisorPolinomial(px, z []*big.Int) []*big.Int {
  180. quo, _ := pf.Div(px, z)
  181. return quo
  182. }