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.

238 lines
4.9 KiB

  1. package kzg
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "fmt"
  6. "math/big"
  7. "strconv"
  8. bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
  9. )
  10. // Q is the order of the integer field (Zq) that fits inside the snark
  11. var Q, _ = new(big.Int).SetString(
  12. "21888242871839275222246405745257275088696311157297823662689037894645226208583", 10)
  13. // R is the mod of the finite field
  14. var R, _ = new(big.Int).SetString(
  15. "21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
  16. func randBigInt() (*big.Int, error) {
  17. maxbits := R.BitLen()
  18. b := make([]byte, (maxbits/8)-1)
  19. _, err := rand.Read(b)
  20. if err != nil {
  21. return nil, err
  22. }
  23. r := new(big.Int).SetBytes(b)
  24. rq := new(big.Int).Mod(r, R)
  25. return rq, nil
  26. }
  27. func arrayOfZeroes(n int) []*big.Int {
  28. r := make([]*big.Int, n)
  29. for i := 0; i < n; i++ {
  30. r[i] = new(big.Int).SetInt64(0)
  31. }
  32. return r[:]
  33. }
  34. //nolint:deadcode,unused
  35. func arrayOfZeroesG1(n int) []*bn256.G1 {
  36. r := make([]*bn256.G1, n)
  37. for i := 0; i < n; i++ {
  38. r[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
  39. }
  40. return r[:]
  41. }
  42. //nolint:deadcode,unused
  43. func arrayOfZeroesG2(n int) []*bn256.G2 {
  44. r := make([]*bn256.G2, n)
  45. for i := 0; i < n; i++ {
  46. r[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
  47. }
  48. return r[:]
  49. }
  50. func compareBigIntArray(a, b []*big.Int) bool {
  51. if len(a) != len(b) {
  52. return false
  53. }
  54. for i := 0; i < len(a); i++ {
  55. if a[i] != b[i] {
  56. return false
  57. }
  58. }
  59. return true
  60. }
  61. func fAdd(a, b *big.Int) *big.Int {
  62. ab := new(big.Int).Add(a, b)
  63. return ab.Mod(ab, R)
  64. }
  65. func fSub(a, b *big.Int) *big.Int {
  66. ab := new(big.Int).Sub(a, b)
  67. return new(big.Int).Mod(ab, R)
  68. }
  69. func fMul(a, b *big.Int) *big.Int {
  70. ab := new(big.Int).Mul(a, b)
  71. return ab.Mod(ab, R)
  72. }
  73. func fDiv(a, b *big.Int) *big.Int {
  74. ab := new(big.Int).Mul(a, new(big.Int).ModInverse(b, R))
  75. return new(big.Int).Mod(ab, R)
  76. }
  77. //nolint:unused,deadcode // TODO check
  78. func fNeg(a *big.Int) *big.Int {
  79. return new(big.Int).Mod(new(big.Int).Neg(a), R)
  80. }
  81. //nolint:deadcode,unused
  82. func fInv(a *big.Int) *big.Int {
  83. return new(big.Int).ModInverse(a, R)
  84. }
  85. func fExp(base *big.Int, e *big.Int) *big.Int {
  86. res := big.NewInt(1)
  87. rem := new(big.Int).Set(e)
  88. exp := base
  89. for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
  90. // if BigIsOdd(rem) {
  91. if rem.Bit(0) == 1 { // .Bit(0) returns 1 when is odd
  92. res = fMul(res, exp)
  93. }
  94. exp = fMul(exp, exp)
  95. rem.Rsh(rem, 1)
  96. }
  97. return res
  98. }
  99. func max(a, b int) int {
  100. if a > b {
  101. return a
  102. }
  103. return b
  104. }
  105. func polynomialAdd(a, b []*big.Int) []*big.Int {
  106. r := arrayOfZeroes(max(len(a), len(b)))
  107. for i := 0; i < len(a); i++ {
  108. r[i] = fAdd(r[i], a[i])
  109. }
  110. for i := 0; i < len(b); i++ {
  111. r[i] = fAdd(r[i], b[i])
  112. }
  113. return r
  114. }
  115. func polynomialSub(a, b []*big.Int) []*big.Int {
  116. r := arrayOfZeroes(max(len(a), len(b)))
  117. for i := 0; i < len(a); i++ {
  118. r[i] = fAdd(r[i], a[i])
  119. }
  120. for i := 0; i < len(b); i++ {
  121. r[i] = fSub(r[i], b[i])
  122. }
  123. return r
  124. }
  125. func polynomialMul(a, b []*big.Int) []*big.Int {
  126. r := arrayOfZeroes(len(a) + len(b) - 1)
  127. for i := 0; i < len(a); i++ {
  128. for j := 0; j < len(b); j++ {
  129. r[i+j] = fAdd(r[i+j], fMul(a[i], b[j]))
  130. }
  131. }
  132. return r
  133. }
  134. func polynomialDiv(a, b []*big.Int) ([]*big.Int, []*big.Int) {
  135. // https://en.wikipedia.org/wiki/Division_algorithm
  136. r := arrayOfZeroes(len(a) - len(b) + 1)
  137. rem := a
  138. for len(rem) >= len(b) {
  139. l := fDiv(rem[len(rem)-1], b[len(b)-1])
  140. pos := len(rem) - len(b)
  141. r[pos] = l
  142. aux := arrayOfZeroes(pos)
  143. aux1 := append(aux, l)
  144. aux2 := polynomialSub(rem, polynomialMul(b, aux1))
  145. rem = aux2[:len(aux2)-1]
  146. }
  147. return r, rem
  148. }
  149. // polynomialEval evaluates the polinomial over the Finite Field at the given value x
  150. func polynomialEval(p []*big.Int, x *big.Int) *big.Int {
  151. r := big.NewInt(int64(0))
  152. for i := 0; i < len(p); i++ {
  153. xi := fExp(x, big.NewInt(int64(i)))
  154. elem := fMul(p[i], xi)
  155. r = fAdd(r, elem)
  156. }
  157. return r
  158. }
  159. // newPolZeroAt generates a new polynomial that has value zero at the given value
  160. func newPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int {
  161. fac := 1
  162. for i := 1; i < totalPoints+1; i++ {
  163. if i != pointPos {
  164. fac = fac * (pointPos - i)
  165. }
  166. }
  167. facBig := big.NewInt(int64(fac))
  168. hf := fDiv(height, facBig)
  169. r := []*big.Int{hf}
  170. for i := 1; i < totalPoints+1; i++ {
  171. if i != pointPos {
  172. ineg := big.NewInt(int64(-i))
  173. b1 := big.NewInt(int64(1))
  174. r = polynomialMul(r, []*big.Int{ineg, b1})
  175. }
  176. }
  177. return r
  178. }
  179. var sNums = map[string]string{
  180. "0": "⁰",
  181. "1": "¹",
  182. "2": "²",
  183. "3": "³",
  184. "4": "⁴",
  185. "5": "⁵",
  186. "6": "⁶",
  187. "7": "⁷",
  188. "8": "⁸",
  189. "9": "⁹",
  190. }
  191. func intToSNum(n int) string {
  192. s := strconv.Itoa(n)
  193. sN := ""
  194. for i := 0; i < len(s); i++ {
  195. sN += sNums[string(s[i])]
  196. }
  197. return sN
  198. }
  199. func polynomialToString(p []*big.Int) string {
  200. s := ""
  201. for i := len(p) - 1; i >= 1; i-- {
  202. if !bytes.Equal(p[i].Bytes(), big.NewInt(0).Bytes()) {
  203. s += fmt.Sprintf("%sx%s + ", p[i], intToSNum(i))
  204. }
  205. }
  206. s += p[0].String()
  207. return s
  208. }
  209. // TODO add method to 'clean' the polynomial, to remove right-zeroes