Skip to content

Commit 06f3281

Browse files
authored
feat: add BLS precompile size limits for Isthmus (#490)
* feat: add Isthmus precompiles Make sure g1 add implemented * feat: add BLS precompile size limits for Isthmus * Fix * Fix tests * Update definition order
1 parent 0d597e5 commit 06f3281

File tree

3 files changed

+128
-20
lines changed

3 files changed

+128
-20
lines changed

core/vm/contracts.go

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ var PrecompiledContractsPrague = PrecompiledContracts{
130130
common.BytesToAddress([]byte{0x09}): &blake2F{},
131131
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
132132
common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{},
133-
common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExp{},
133+
common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExpPrague{},
134134
common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{},
135-
common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExp{},
136-
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
135+
common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExpPrague{},
136+
common.BytesToAddress([]byte{0x0f}): &bls12381PairingPrague{},
137137
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
138138
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
139139
}
@@ -174,7 +174,29 @@ var PrecompiledContractsGranite = map[common.Address]PrecompiledContract{
174174
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
175175
}
176176

177+
var PrecompiledContractsIsthmus = map[common.Address]PrecompiledContract{
178+
common.BytesToAddress([]byte{1}): &ecrecover{},
179+
common.BytesToAddress([]byte{2}): &sha256hash{},
180+
common.BytesToAddress([]byte{3}): &ripemd160hash{},
181+
common.BytesToAddress([]byte{4}): &dataCopy{},
182+
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
183+
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
184+
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
185+
common.BytesToAddress([]byte{8}): &bn256PairingGranite{},
186+
common.BytesToAddress([]byte{9}): &blake2F{},
187+
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
188+
common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{},
189+
common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExpIsthmus{},
190+
common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{},
191+
common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExpIsthmus{},
192+
common.BytesToAddress([]byte{0x0f}): &bls12381PairingIsthmus{},
193+
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
194+
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
195+
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
196+
}
197+
177198
var (
199+
PrecompiledAddressesIsthmus []common.Address
178200
PrecompiledAddressesGranite []common.Address
179201
PrecompiledAddressesFjord []common.Address
180202
PrecompiledAddressesPrague []common.Address
@@ -210,10 +232,16 @@ func init() {
210232
for k := range PrecompiledContractsGranite {
211233
PrecompiledAddressesGranite = append(PrecompiledAddressesGranite, k)
212234
}
235+
for k := range PrecompiledContractsIsthmus {
236+
PrecompiledAddressesIsthmus = append(PrecompiledAddressesIsthmus, k)
237+
}
213238
}
214239

215240
func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
241+
// note: the order of these switch cases is important
216242
switch {
243+
case rules.IsOptimismIsthmus:
244+
return PrecompiledContractsIsthmus
217245
case rules.IsOptimismGranite:
218246
return PrecompiledContractsGranite
219247
case rules.IsOptimismFjord:
@@ -243,6 +271,8 @@ func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts {
243271
// ActivePrecompiles returns the precompile addresses enabled with the current configuration.
244272
func ActivePrecompiles(rules params.Rules) []common.Address {
245273
switch {
274+
case rules.IsOptimismIsthmus:
275+
return PrecompiledAddressesIsthmus
246276
case rules.IsOptimismGranite:
247277
return PrecompiledAddressesGranite
248278
case rules.IsOptimismFjord:
@@ -778,6 +808,9 @@ var (
778808
errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes")
779809
errBLS12381G1PointSubgroup = errors.New("g1 point is not on correct subgroup")
780810
errBLS12381G2PointSubgroup = errors.New("g2 point is not on correct subgroup")
811+
errBLS12381MaxG1Size = errors.New("g1 msm input size exceeds maximum")
812+
errBLS12381MaxG2Size = errors.New("g2 msm input size exceeds maximum")
813+
errBLS12381MaxPairingSize = errors.New("pairing input size exceeds maximum")
781814
)
782815

783816
// bls12381G1Add implements EIP-2537 G1Add precompile.
@@ -816,11 +849,26 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
816849
return encodePointG1(p0), nil
817850
}
818851

819-
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
820-
type bls12381G1MultiExp struct{}
852+
type bls12381G1MultiExpIsthmus struct {
853+
}
854+
855+
func (c *bls12381G1MultiExpIsthmus) RequiredGas(input []byte) uint64 {
856+
return new(bls12381G1MultiExpPrague).RequiredGas(input)
857+
}
858+
859+
func (c *bls12381G1MultiExpIsthmus) Run(input []byte) ([]byte, error) {
860+
if len(input) > int(params.Bls12381G1MulMaxInputSizeIsthmus) {
861+
return nil, errBLS12381MaxG1Size
862+
}
863+
864+
return new(bls12381G1MultiExpPrague).Run(input)
865+
}
866+
867+
// bls12381G1MultiExpPrague implements EIP-2537 G1MultiExp precompile for Prague (no size limits).
868+
type bls12381G1MultiExpPrague struct{}
821869

822870
// RequiredGas returns the gas required to execute the pre-compiled contract.
823-
func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
871+
func (c *bls12381G1MultiExpPrague) RequiredGas(input []byte) uint64 {
824872
// Calculate G1 point, scalar value pair length
825873
k := len(input) / 160
826874
if k == 0 {
@@ -838,7 +886,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
838886
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
839887
}
840888

841-
func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
889+
func (c *bls12381G1MultiExpPrague) Run(input []byte) ([]byte, error) {
842890
// Implements EIP-2537 G1MultiExp precompile.
843891
// G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
844892
// Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
@@ -913,11 +961,26 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
913961
return encodePointG2(r), nil
914962
}
915963

916-
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
917-
type bls12381G2MultiExp struct{}
964+
type bls12381G2MultiExpIsthmus struct {
965+
}
966+
967+
func (c *bls12381G2MultiExpIsthmus) RequiredGas(input []byte) uint64 {
968+
return new(bls12381G2MultiExpPrague).RequiredGas(input)
969+
}
970+
971+
func (c *bls12381G2MultiExpIsthmus) Run(input []byte) ([]byte, error) {
972+
if len(input) > int(params.Bls12381G2MulMaxInputSizeIsthmus) {
973+
return nil, errBLS12381MaxG2Size
974+
}
975+
976+
return new(bls12381G2MultiExpPrague).Run(input)
977+
}
978+
979+
// bls12381G2MultiExpPrague implements EIP-2537 G2MultiExp precompile.
980+
type bls12381G2MultiExpPrague struct{}
918981

919982
// RequiredGas returns the gas required to execute the pre-compiled contract.
920-
func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
983+
func (c *bls12381G2MultiExpPrague) RequiredGas(input []byte) uint64 {
921984
// Calculate G2 point, scalar value pair length
922985
k := len(input) / 288
923986
if k == 0 {
@@ -935,7 +998,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
935998
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
936999
}
9371000

938-
func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
1001+
func (c *bls12381G2MultiExpPrague) Run(input []byte) ([]byte, error) {
9391002
// Implements EIP-2537 G2MultiExp precompile logic
9401003
// > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
9411004
// > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
@@ -973,15 +1036,30 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
9731036
return encodePointG2(r), nil
9741037
}
9751038

976-
// bls12381Pairing implements EIP-2537 Pairing precompile.
977-
type bls12381Pairing struct{}
1039+
type bls12381PairingIsthmus struct {
1040+
}
1041+
1042+
func (c *bls12381PairingIsthmus) RequiredGas(input []byte) uint64 {
1043+
return new(bls12381PairingPrague).RequiredGas(input)
1044+
}
1045+
1046+
func (c *bls12381PairingIsthmus) Run(input []byte) ([]byte, error) {
1047+
if len(input) > int(params.Bls12381PairingMaxInputSizeIsthmus) {
1048+
return nil, errBLS12381MaxPairingSize
1049+
}
1050+
1051+
return new(bls12381PairingPrague).Run(input)
1052+
}
1053+
1054+
// bls12381PairingPrague implements EIP-2537 Pairing precompile.
1055+
type bls12381PairingPrague struct{}
9781056

9791057
// RequiredGas returns the gas required to execute the pre-compiled contract.
980-
func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
1058+
func (c *bls12381PairingPrague) RequiredGas(input []byte) uint64 {
9811059
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
9821060
}
9831061

984-
func (c *bls12381Pairing) Run(input []byte) ([]byte, error) {
1062+
func (c *bls12381PairingPrague) Run(input []byte) ([]byte, error) {
9851063
// Implements EIP-2537 Pairing precompile logic.
9861064
// > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
9871065
// > - `128` bytes of G1 point encoding

core/vm/contracts_test.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,18 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
5959
common.BytesToAddress([]byte{9}): &blake2F{},
6060
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
6161

62-
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
63-
6462
common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{},
65-
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1MultiExp{},
63+
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1MultiExpPrague{},
64+
common.BytesToAddress([]byte{0x1f, 0x0b}): &bls12381G1MultiExpIsthmus{},
6665
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G2Add{},
67-
common.BytesToAddress([]byte{0x0f, 0x0d}): &bls12381G2MultiExp{},
68-
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381Pairing{},
66+
common.BytesToAddress([]byte{0x0f, 0x0d}): &bls12381G2MultiExpPrague{},
67+
common.BytesToAddress([]byte{0x1f, 0x0d}): &bls12381G2MultiExpIsthmus{},
68+
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381PairingPrague{},
69+
common.BytesToAddress([]byte{0x1f, 0x0e}): &bls12381PairingIsthmus{},
6970
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381MapG1{},
7071
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381MapG2{},
72+
73+
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
7174
}
7275

7376
// EIP-152 test vectors
@@ -282,6 +285,29 @@ func TestPrecompileBn256PairingTooLargeInput(t *testing.T) {
282285
}, t)
283286
}
284287

288+
func TestPrecompileBlsInputSize(t *testing.T) {
289+
big := make([]byte, params.Bls12381G1MulMaxInputSizeIsthmus+1)
290+
testPrecompiledFailure("1f0b", precompiledFailureTest{
291+
Input: common.Bytes2Hex(big),
292+
ExpectedError: "g1 msm input size exceeds maximum",
293+
Name: "bls12381G1MSM_input_too_big",
294+
}, t)
295+
296+
big = make([]byte, params.Bls12381G2MulMaxInputSizeIsthmus+1)
297+
testPrecompiledFailure("1f0d", precompiledFailureTest{
298+
Input: common.Bytes2Hex(big),
299+
ExpectedError: "g2 msm input size exceeds maximum",
300+
Name: "bls12381G2MSM_input_too_big",
301+
}, t)
302+
303+
big = make([]byte, params.Bls12381PairingMaxInputSizeIsthmus+1)
304+
testPrecompiledFailure("1f0e", precompiledFailureTest{
305+
Input: common.Bytes2Hex(big),
306+
ExpectedError: "pairing input size exceeds maximum",
307+
Name: "bls12381Pairing_input_too_big",
308+
}, t)
309+
}
310+
285311
func TestPrecompiledEcrecover(t *testing.T) { testJson("ecRecover", "01", t) }
286312

287313
func testJson(name, addr string, t *testing.T) {

params/protocol_params.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ const (
172172
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
173173
Bls12381MapG2Gas uint64 = 23800 // Gas price for BLS12-381 mapping field element to G2 operation
174174

175+
Bls12381G1MulMaxInputSizeIsthmus uint64 = 513760 // Maximum input size for BLS12-381 G1 multiple-scalar-multiply operation
176+
Bls12381G2MulMaxInputSizeIsthmus uint64 = 488448 // Maximum input size for BLS12-381 G2 multiple-scalar-multiply operation
177+
Bls12381PairingMaxInputSizeIsthmus uint64 = 235008 // Maximum input size for BLS12-381 pairing check
178+
175179
P256VerifyGas uint64 = 3450 // secp256r1 elliptic curve signature verifier gas price
176180

177181
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,

0 commit comments

Comments
 (0)