|
| 1 | +// Copyright 2024 The Erigon Authors |
| 2 | +// This file is part of Erigon. |
| 3 | +// |
| 4 | +// Erigon 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 | +// Erigon 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 Erigon. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + |
| 17 | +package vm |
| 18 | + |
| 19 | +import ( |
| 20 | + "encoding/binary" |
| 21 | + |
| 22 | + "github.com/erigontech/erigon/execution/protocol/params" |
| 23 | +) |
| 24 | + |
| 25 | +// Precompile gas override key constants. |
| 26 | +// Fixed-gas precompiles use PC_<name> as a single total key. |
| 27 | +// Variable-gas precompiles use PC_<name>_<param> for each formula parameter. |
| 28 | +const ( |
| 29 | + GasKeyPCEcrec = "PC_ECREC" |
| 30 | + GasKeyPCBn254Add = "PC_BN254_ADD" |
| 31 | + GasKeyPCBn254Mul = "PC_BN254_MUL" |
| 32 | + GasKeyPCBls12G1Add = "PC_BLS12_G1ADD" |
| 33 | + GasKeyPCBls12G2Add = "PC_BLS12_G2ADD" |
| 34 | + GasKeyPCBls12MapFpToG1 = "PC_BLS12_MAP_FP_TO_G1" |
| 35 | + GasKeyPCBls12MapFp2ToG2 = "PC_BLS12_MAP_FP2_TO_G2" |
| 36 | + GasKeyPCKzgPointEvaluation = "PC_KZG_POINT_EVALUATION" |
| 37 | + GasKeyPCP256Verify = "PC_P256VERIFY" |
| 38 | + |
| 39 | + GasKeyPCSha256Base = "PC_SHA256_BASE" |
| 40 | + GasKeyPCSha256PerWord = "PC_SHA256_PER_WORD" |
| 41 | + |
| 42 | + GasKeyPCRipemd160Base = "PC_RIPEMD160_BASE" |
| 43 | + GasKeyPCRipemd160PerWord = "PC_RIPEMD160_PER_WORD" |
| 44 | + |
| 45 | + GasKeyPCIdBase = "PC_ID_BASE" |
| 46 | + GasKeyPCIdPerWord = "PC_ID_PER_WORD" |
| 47 | + |
| 48 | + GasKeyPCModexpMinGas = "PC_MODEXP_MIN_GAS" |
| 49 | + |
| 50 | + GasKeyPCBn254PairingBase = "PC_BN254_PAIRING_BASE" |
| 51 | + GasKeyPCBn254PairingPerPair = "PC_BN254_PAIRING_PER_PAIR" |
| 52 | + |
| 53 | + GasKeyPCBlake2fPerRound = "PC_BLAKE2F_PER_ROUND" |
| 54 | + |
| 55 | + GasKeyPCBls12PairingBase = "PC_BLS12_PAIRING_CHECK_BASE" |
| 56 | + GasKeyPCBls12PairingPerPair = "PC_BLS12_PAIRING_CHECK_PER_PAIR" |
| 57 | + |
| 58 | + GasKeyPCBls12G1MsmMulGas = "PC_BLS12_G1MSM_MUL_GAS" |
| 59 | + GasKeyPCBls12G2MsmMulGas = "PC_BLS12_G2MSM_MUL_GAS" |
| 60 | +) |
| 61 | + |
| 62 | +// PrecompileGasWithOverrides calculates precompile gas cost with optional overrides. |
| 63 | +// Fixed-gas precompiles: single key (PC_<name>) overrides the flat cost. |
| 64 | +// Variable-gas precompiles: parameter keys (PC_<name>_BASE, etc.) override formula inputs. |
| 65 | +func PrecompileGasWithOverrides(schedule *GasSchedule, name string, input []byte, defaultGas uint64) uint64 { |
| 66 | + if schedule == nil { |
| 67 | + return defaultGas |
| 68 | + } |
| 69 | + |
| 70 | + switch name { |
| 71 | + // Fixed-gas precompiles — single total key |
| 72 | + case "ECREC", "BN254_ADD", "BN254_MUL", "BLS12_G1ADD", "BLS12_G2ADD", |
| 73 | + "BLS12_MAP_FP_TO_G1", "BLS12_MAP_FP2_TO_G2", "KZG_POINT_EVALUATION", "P256VERIFY": |
| 74 | + return schedule.GetOr("PC_"+name, defaultGas) |
| 75 | + |
| 76 | + // Variable-gas precompiles — parameter overrides |
| 77 | + case "SHA256": |
| 78 | + return precompileBasePerWord(schedule, GasKeyPCSha256Base, GasKeyPCSha256PerWord, input, params.Sha256BaseGas, params.Sha256PerWordGas) |
| 79 | + case "RIPEMD160": |
| 80 | + return precompileBasePerWord(schedule, GasKeyPCRipemd160Base, GasKeyPCRipemd160PerWord, input, params.Ripemd160BaseGas, params.Ripemd160PerWordGas) |
| 81 | + case "ID": |
| 82 | + return precompileBasePerWord(schedule, GasKeyPCIdBase, GasKeyPCIdPerWord, input, params.IdentityBaseGas, params.IdentityPerWordGas) |
| 83 | + case "MODEXP": |
| 84 | + return precompileModexp(schedule, defaultGas) |
| 85 | + case "BN254_PAIRING": |
| 86 | + return precompileBasePerPair(schedule, GasKeyPCBn254PairingBase, GasKeyPCBn254PairingPerPair, input, 192, params.Bn254PairingBaseGasIstanbul, params.Bn254PairingPerPointGasIstanbul) |
| 87 | + case "BLAKE2F": |
| 88 | + return precompileBlake2f(schedule, input) |
| 89 | + case "BLS12_PAIRING_CHECK": |
| 90 | + return precompileBasePerPair(schedule, GasKeyPCBls12PairingBase, GasKeyPCBls12PairingPerPair, input, 384, params.Bls12381PairingBaseGas, params.Bls12381PairingPerPairGas) |
| 91 | + case "BLS12_G1MSM": |
| 92 | + return precompileMsm(schedule, GasKeyPCBls12G1MsmMulGas, input, 160, params.Bls12381G1MulGas) |
| 93 | + case "BLS12_G2MSM": |
| 94 | + return precompileMsm(schedule, GasKeyPCBls12G2MsmMulGas, input, 288, params.Bls12381G2MulGas) |
| 95 | + } |
| 96 | + |
| 97 | + return defaultGas |
| 98 | +} |
| 99 | + |
| 100 | +// precompileBasePerWord computes base + perWord * ceil(len(input)/32). |
| 101 | +// Used by SHA256, RIPEMD160, IDENTITY. |
| 102 | +func precompileBasePerWord(schedule *GasSchedule, baseKey, perWordKey string, input []byte, defaultBase, defaultPerWord uint64) uint64 { |
| 103 | + base := schedule.GetOr(baseKey, defaultBase) |
| 104 | + perWord := schedule.GetOr(perWordKey, defaultPerWord) |
| 105 | + words := uint64(len(input)+31) / 32 |
| 106 | + return base + perWord*words |
| 107 | +} |
| 108 | + |
| 109 | +// precompileBasePerPair computes base + perPair * (len(input) / pairSize). |
| 110 | +// Used by BN254_PAIRING (pairSize=192), BLS12_PAIRING_CHECK (pairSize=384). |
| 111 | +func precompileBasePerPair(schedule *GasSchedule, baseKey, perPairKey string, input []byte, pairSize int, defaultBase, defaultPerPair uint64) uint64 { |
| 112 | + base := schedule.GetOr(baseKey, defaultBase) |
| 113 | + perPair := schedule.GetOr(perPairKey, defaultPerPair) |
| 114 | + pairs := uint64(len(input) / pairSize) |
| 115 | + return base + perPair*pairs |
| 116 | +} |
| 117 | + |
| 118 | +// precompileBlake2f computes perRound * rounds, where rounds is read from input[0:4]. |
| 119 | +func precompileBlake2f(schedule *GasSchedule, input []byte) uint64 { |
| 120 | + if len(input) != 213 { |
| 121 | + return 0 |
| 122 | + } |
| 123 | + rounds := uint64(binary.BigEndian.Uint32(input[0:4])) |
| 124 | + perRound := schedule.GetOr(GasKeyPCBlake2fPerRound, 1) |
| 125 | + return perRound * rounds |
| 126 | +} |
| 127 | + |
| 128 | +// precompileMsm computes k * mulGas * discount[k] / 1000. |
| 129 | +// The discount table is not overridable — only the per-point mulGas is. |
| 130 | +func precompileMsm(schedule *GasSchedule, mulGasKey string, input []byte, pointSize int, defaultMulGas uint64) uint64 { |
| 131 | + k := len(input) / pointSize |
| 132 | + if k == 0 { |
| 133 | + return 0 |
| 134 | + } |
| 135 | + mulGas := schedule.GetOr(mulGasKey, defaultMulGas) |
| 136 | + |
| 137 | + // Use the correct discount table based on point size |
| 138 | + var discount uint64 |
| 139 | + if pointSize == 160 { |
| 140 | + if dLen := len(params.Bls12381MSMDiscountTableG1); k < dLen { |
| 141 | + discount = params.Bls12381MSMDiscountTableG1[k-1] |
| 142 | + } else { |
| 143 | + discount = params.Bls12381MSMDiscountTableG1[dLen-1] |
| 144 | + } |
| 145 | + } else { |
| 146 | + if dLen := len(params.Bls12381MSMDiscountTableG2); k < dLen { |
| 147 | + discount = params.Bls12381MSMDiscountTableG2[k-1] |
| 148 | + } else { |
| 149 | + discount = params.Bls12381MSMDiscountTableG2[dLen-1] |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + return (uint64(k) * mulGas * discount) / 1000 |
| 154 | +} |
| 155 | + |
| 156 | +// precompileModexp applies the MODEXP min gas override. |
| 157 | +// The complex EIP-2565/7883 formula itself is not overridable — only the floor value is. |
| 158 | +func precompileModexp(schedule *GasSchedule, defaultGas uint64) uint64 { |
| 159 | + minGas := schedule.GetOr(GasKeyPCModexpMinGas, 200) |
| 160 | + if defaultGas < minGas { |
| 161 | + return minGas |
| 162 | + } |
| 163 | + return defaultGas |
| 164 | +} |
0 commit comments