precompile_fuzzer.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright 2020 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. package bls
  17. import (
  18. "bytes"
  19. "fmt"
  20. "github.com/ethereum/go-ethereum/common"
  21. "github.com/ethereum/go-ethereum/core/vm"
  22. )
  23. const (
  24. blsG1Add = byte(10)
  25. blsG1Mul = byte(11)
  26. blsG1MultiExp = byte(12)
  27. blsG2Add = byte(13)
  28. blsG2Mul = byte(14)
  29. blsG2MultiExp = byte(15)
  30. blsPairing = byte(16)
  31. blsMapG1 = byte(17)
  32. blsMapG2 = byte(18)
  33. )
  34. func FuzzG1Add(data []byte) int { return fuzz(blsG1Add, data) }
  35. func FuzzG1Mul(data []byte) int { return fuzz(blsG1Mul, data) }
  36. func FuzzG1MultiExp(data []byte) int { return fuzz(blsG1MultiExp, data) }
  37. func FuzzG2Add(data []byte) int { return fuzz(blsG2Add, data) }
  38. func FuzzG2Mul(data []byte) int { return fuzz(blsG2Mul, data) }
  39. func FuzzG2MultiExp(data []byte) int { return fuzz(blsG2MultiExp, data) }
  40. func FuzzPairing(data []byte) int { return fuzz(blsPairing, data) }
  41. func FuzzMapG1(data []byte) int { return fuzz(blsMapG1, data) }
  42. func FuzzMapG2(data []byte) int { return fuzz(blsMapG2, data) }
  43. func checkInput(id byte, inputLen int) bool {
  44. switch id {
  45. case blsG1Add:
  46. return inputLen == 256
  47. case blsG1Mul:
  48. return inputLen == 160
  49. case blsG1MultiExp:
  50. return inputLen%160 == 0
  51. case blsG2Add:
  52. return inputLen == 512
  53. case blsG2Mul:
  54. return inputLen == 288
  55. case blsG2MultiExp:
  56. return inputLen%288 == 0
  57. case blsPairing:
  58. return inputLen%384 == 0
  59. case blsMapG1:
  60. return inputLen == 64
  61. case blsMapG2:
  62. return inputLen == 128
  63. }
  64. panic("programmer error")
  65. }
  66. // The fuzzer functions must return
  67. // 1 if the fuzzer should increase priority of the
  68. // given input during subsequent fuzzing (for example, the input is lexically
  69. // correct and was parsed successfully);
  70. // -1 if the input must not be added to corpus even if gives new coverage; and
  71. // 0 otherwise
  72. // other values are reserved for future use.
  73. func fuzz(id byte, data []byte) int {
  74. // Even on bad input, it should not crash, so we still test the gas calc
  75. precompile := vm.PrecompiledContractsBLS[common.BytesToAddress([]byte{id})]
  76. gas := precompile.RequiredGas(data)
  77. if !checkInput(id, len(data)) {
  78. return 0
  79. }
  80. // If the gas cost is too large (25M), bail out
  81. if gas > 25*1000*1000 {
  82. return 0
  83. }
  84. cpy := make([]byte, len(data))
  85. copy(cpy, data)
  86. _, err := precompile.Run(cpy)
  87. if !bytes.Equal(cpy, data) {
  88. panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy))
  89. }
  90. if err != nil {
  91. return 0
  92. }
  93. return 1
  94. }