bn256_fuzz.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright 2018 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. //go:build gofuzz
  17. // +build gofuzz
  18. package bn256
  19. import (
  20. "bytes"
  21. "fmt"
  22. "io"
  23. "math/big"
  24. "github.com/consensys/gnark-crypto/ecc/bn254"
  25. cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
  26. google "github.com/ethereum/go-ethereum/crypto/bn256/google"
  27. )
  28. func getG1Points(input io.Reader) (*cloudflare.G1, *google.G1, *bn254.G1Affine) {
  29. _, xc, err := cloudflare.RandomG1(input)
  30. if err != nil {
  31. // insufficient input
  32. return nil, nil, nil
  33. }
  34. xg := new(google.G1)
  35. if _, err := xg.Unmarshal(xc.Marshal()); err != nil {
  36. panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err))
  37. }
  38. xs := new(bn254.G1Affine)
  39. if err := xs.Unmarshal(xc.Marshal()); err != nil {
  40. panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err))
  41. }
  42. return xc, xg, xs
  43. }
  44. func getG2Points(input io.Reader) (*cloudflare.G2, *google.G2, *bn254.G2Affine) {
  45. _, xc, err := cloudflare.RandomG2(input)
  46. if err != nil {
  47. // insufficient input
  48. return nil, nil, nil
  49. }
  50. xg := new(google.G2)
  51. if _, err := xg.Unmarshal(xc.Marshal()); err != nil {
  52. panic(fmt.Sprintf("Could not marshal cloudflare -> google: %v", err))
  53. }
  54. xs := new(bn254.G2Affine)
  55. if err := xs.Unmarshal(xc.Marshal()); err != nil {
  56. panic(fmt.Sprintf("Could not marshal cloudflare -> gnark: %v", err))
  57. }
  58. return xc, xg, xs
  59. }
  60. // FuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries.
  61. func FuzzAdd(data []byte) int {
  62. input := bytes.NewReader(data)
  63. xc, xg, xs := getG1Points(input)
  64. if xc == nil {
  65. return 0
  66. }
  67. yc, yg, ys := getG1Points(input)
  68. if yc == nil {
  69. return 0
  70. }
  71. // Ensure both libs can parse the second curve point
  72. // Add the two points and ensure they result in the same output
  73. rc := new(cloudflare.G1)
  74. rc.Add(xc, yc)
  75. rg := new(google.G1)
  76. rg.Add(xg, yg)
  77. tmpX := new(bn254.G1Jac).FromAffine(xs)
  78. tmpY := new(bn254.G1Jac).FromAffine(ys)
  79. rs := new(bn254.G1Affine).FromJacobian(tmpX.AddAssign(tmpY))
  80. if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
  81. panic("add mismatch: cloudflare/google")
  82. }
  83. if !bytes.Equal(rc.Marshal(), rs.Marshal()) {
  84. panic("add mismatch: cloudflare/gnark")
  85. }
  86. return 1
  87. }
  88. // FuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare
  89. // libraries.
  90. func FuzzMul(data []byte) int {
  91. input := bytes.NewReader(data)
  92. pc, pg, ps := getG1Points(input)
  93. if pc == nil {
  94. return 0
  95. }
  96. // Add the two points and ensure they result in the same output
  97. remaining := input.Len()
  98. if remaining == 0 {
  99. return 0
  100. }
  101. if remaining > 128 {
  102. // The evm only ever uses 32 byte integers, we need to cap this otherwise
  103. // we run into slow exec. A 236Kb byte integer cause oss-fuzz to report it as slow.
  104. // 128 bytes should be fine though
  105. return 0
  106. }
  107. buf := make([]byte, remaining)
  108. input.Read(buf)
  109. rc := new(cloudflare.G1)
  110. rc.ScalarMult(pc, new(big.Int).SetBytes(buf))
  111. rg := new(google.G1)
  112. rg.ScalarMult(pg, new(big.Int).SetBytes(buf))
  113. rs := new(bn254.G1Jac)
  114. psJac := new(bn254.G1Jac).FromAffine(ps)
  115. rs.ScalarMultiplication(psJac, new(big.Int).SetBytes(buf))
  116. rsAffine := new(bn254.G1Affine).FromJacobian(rs)
  117. if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
  118. panic("scalar mul mismatch: cloudflare/google")
  119. }
  120. if !bytes.Equal(rc.Marshal(), rsAffine.Marshal()) {
  121. panic("scalar mul mismatch: cloudflare/gnark")
  122. }
  123. return 1
  124. }
  125. func FuzzPair(data []byte) int {
  126. input := bytes.NewReader(data)
  127. pc, pg, ps := getG1Points(input)
  128. if pc == nil {
  129. return 0
  130. }
  131. tc, tg, ts := getG2Points(input)
  132. if tc == nil {
  133. return 0
  134. }
  135. // Pair the two points and ensure they result in the same output
  136. clPair := cloudflare.Pair(pc, tc).Marshal()
  137. gPair := google.Pair(pg, tg).Marshal()
  138. if !bytes.Equal(clPair, gPair) {
  139. panic("pairing mismatch: cloudflare/google")
  140. }
  141. cPair, err := bn254.Pair([]bn254.G1Affine{*ps}, []bn254.G2Affine{*ts})
  142. if err != nil {
  143. panic(fmt.Sprintf("gnark/bn254 encountered error: %v", err))
  144. }
  145. if !bytes.Equal(clPair, cPair.Marshal()) {
  146. panic("pairing mismatch: cloudflare/gnark")
  147. }
  148. return 1
  149. }