Skip to content

Commit 9ac0946

Browse files
authored
EIP-7823 --- xbs bounds tests for Osaka MODEXP (#2523)
* first commit * ras * wip * feat: tests made parametric * spotless * bug fix * bug fix * feat: nighly (full) and partial randomized tests * ras: renaming * fix: skip tests prior to Osaka + remove obsolete test * spotless
1 parent fc82da8 commit 9ac0946

File tree

5 files changed

+369
-3
lines changed

5 files changed

+369
-3
lines changed

arithmetization/src/main/java/net/consensys/linea/zktracer/module/exp/ExpOperation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public ExpOperation(ExpCall expCall) {
5454
final ModexpLogExpCall modexplogExpCall = (ModexpLogExpCall) expCall;
5555
// Extract inputs
5656
final ModexpMetadata modexpMetadata = modexplogExpCall.getModexpMetadata();
57-
final int bbsInt = modexpMetadata.bbsInt();
58-
final int ebsInt = modexpMetadata.ebsInt();
57+
final int bbsInt = modexpMetadata.normalizedBbsInt();
58+
final int ebsInt = modexpMetadata.normalizedEbsInt();
5959
checkArgument(
6060
modexpMetadata.callData().size() - BASE_MIN_OFFSET - bbsInt >= 0,
6161
"MODEXP call data unexpectedly short");

arithmetization/src/main/java/net/consensys/linea/zktracer/module/hub/precompiles/modexpMetadata/ModexpMetadata.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public EWord rawLeadingWord() {
217217
return EWord.of(
218218
rightPaddedSlice(
219219
callDataRange.getRawData(),
220-
safeLongToInt(callDataRange.offset()) + BASE_MIN_OFFSET + bbsInt(),
220+
safeLongToInt(callDataRange.offset()) + BASE_MIN_OFFSET + normalizedBbsInt(),
221221
WORD_SIZE));
222222
}
223223

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright Consensys Software Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package net.consensys.linea.zktracer.precompiles.osakaModexpTests;
16+
17+
import static net.consensys.linea.zktracer.precompiles.osakaModexpTests.BbsEbsMbsBoundsScenario.BoundsScenario.OUT_OF_BOUNDS;
18+
import static net.consensys.linea.zktracer.precompiles.osakaModexpTests.BbsEbsMbsBoundsScenario.BoundsScenario.WITHIN_BOUNDS;
19+
20+
enum BbsEbsMbsBoundsScenario {
21+
BBS_OUT_OF_BOUNDS(OUT_OF_BOUNDS, WITHIN_BOUNDS, WITHIN_BOUNDS),
22+
EBS_OUT_OF_BOUNDS(WITHIN_BOUNDS, OUT_OF_BOUNDS, WITHIN_BOUNDS),
23+
MBS_OUT_OF_BOUNDS(WITHIN_BOUNDS, WITHIN_BOUNDS, OUT_OF_BOUNDS),
24+
25+
BBS_AND_EBS_OUT_OF_BOUNDS(OUT_OF_BOUNDS, OUT_OF_BOUNDS, WITHIN_BOUNDS),
26+
EBS_AND_MBS_OUT_OF_BOUNDS(WITHIN_BOUNDS, OUT_OF_BOUNDS, OUT_OF_BOUNDS),
27+
BBS_AND_MBS_OUT_OF_BOUNDS(OUT_OF_BOUNDS, WITHIN_BOUNDS, OUT_OF_BOUNDS),
28+
29+
ALL_XBS_OUT_OF_BOUNDS(OUT_OF_BOUNDS, OUT_OF_BOUNDS, OUT_OF_BOUNDS);
30+
31+
final BoundsScenario bbsBoundsScenario;
32+
final BoundsScenario ebsBoundsScenario;
33+
final BoundsScenario mbsBoundsScenario;
34+
35+
BbsEbsMbsBoundsScenario(
36+
BoundsScenario bbsBoundsScenario,
37+
BoundsScenario ebsBoundsScenario,
38+
BoundsScenario mbsBoundsScenario) {
39+
this.bbsBoundsScenario = bbsBoundsScenario;
40+
this.ebsBoundsScenario = ebsBoundsScenario;
41+
this.mbsBoundsScenario = mbsBoundsScenario;
42+
}
43+
44+
enum BoundsScenario {
45+
WITHIN_BOUNDS,
46+
OUT_OF_BOUNDS
47+
}
48+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* Copyright Consensys Software Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package net.consensys.linea.zktracer.precompiles.osakaModexpTests;
16+
17+
import static net.consensys.linea.zktracer.Fork.forkPredatesOsaka;
18+
import static net.consensys.linea.zktracer.TraceOsaka.EIP_7823_MODEXP_UPPER_BYTE_SIZE_BOUND;
19+
import static net.consensys.linea.zktracer.opcode.OpCode.*;
20+
import static net.consensys.linea.zktracer.precompiles.osakaModexpTests.XbsValueType.GIBBERISH;
21+
import static net.consensys.linea.zktracer.precompiles.osakaModexpTests.XbsValueType.getListOfInputs;
22+
23+
import java.time.LocalDate;
24+
import java.util.*;
25+
import java.util.stream.Collectors;
26+
import java.util.stream.Stream;
27+
28+
import net.consensys.linea.reporting.TracerTestBase;
29+
import net.consensys.linea.testing.*;
30+
import org.apache.tuweni.bytes.Bytes;
31+
import org.hyperledger.besu.crypto.KeyPair;
32+
import org.hyperledger.besu.crypto.SECP256K1;
33+
import org.hyperledger.besu.datatypes.Address;
34+
import org.hyperledger.besu.datatypes.Hash;
35+
import org.hyperledger.besu.datatypes.Wei;
36+
import org.hyperledger.besu.ethereum.core.Transaction;
37+
import org.junit.jupiter.api.Tag;
38+
import org.junit.jupiter.api.TestInfo;
39+
import org.junit.jupiter.params.ParameterizedTest;
40+
import org.junit.jupiter.params.provider.Arguments;
41+
import org.junit.jupiter.params.provider.MethodSource;
42+
43+
public class XbsLimitsTests extends TracerTestBase {
44+
45+
final KeyPair keyPair = new SECP256K1().generateKeyPair();
46+
final Address senderAddress =
47+
Address.extract(Hash.hash(keyPair.getPublicKey().getEncodedBytes()));
48+
49+
final ToyAccount senderAccount =
50+
ToyAccount.builder().balance(Wei.fromEth(1900)).nonce(420).address(senderAddress).build();
51+
52+
/**
53+
* Returns code calling the <b>MODEXP</b> precompile with the transaction's call data as inputs.
54+
*
55+
* @param cds
56+
* @return
57+
*/
58+
final BytecodeCompiler modexpCallerCode(int cds) {
59+
return BytecodeCompiler.newProgram(chainConfig)
60+
// full copy of call data
61+
.op(CALLDATASIZE)
62+
.op(PUSH0)
63+
.op(PUSH0)
64+
.op(CALLDATACOPY)
65+
// call MODEXP precompile
66+
.push(EIP_7823_MODEXP_UPPER_BYTE_SIZE_BOUND) // r@c
67+
.push(3 * 32 + 3 * EIP_7823_MODEXP_UPPER_BYTE_SIZE_BOUND) // r@o
68+
.push(cds) // cds
69+
.push(0) // cdo
70+
.push("0000000000000000000000000000000000000005")
71+
.op(GAS)
72+
.op(STATICCALL)
73+
// append 32 JUMPDESTs for sanity
74+
.op(JUMPDEST, 32);
75+
}
76+
77+
final ToyAccount.ToyAccountBuilder receiverAccountBuilder =
78+
ToyAccount.builder()
79+
.balance(Wei.ONE)
80+
.nonce(6)
81+
.address(Address.fromHexString("11223344aaaaffff000000000000000000000001"));
82+
83+
@ParameterizedTest
84+
@MethodSource("modexpXbsLimitTestsSource")
85+
public void modexpXbsLimitTests(
86+
XbsValueType.BbsEbsMbsScenario scenario, String bbsEbsMbsString, TestInfo testInfo) {
87+
88+
if (forkPredatesOsaka(fork)) return;
89+
body(scenario, bbsEbsMbsString, testInfo);
90+
}
91+
92+
@Tag("nightly")
93+
@ParameterizedTest
94+
@MethodSource("modexpXbsLimitsTestsNighlySource")
95+
public void modexpXbsLimitTestsNightly(
96+
XbsValueType.BbsEbsMbsScenario scenario, String bbsEbsMbsString, TestInfo testInfo) {
97+
98+
if (forkPredatesOsaka(fork)) return;
99+
body(scenario, bbsEbsMbsString, testInfo);
100+
}
101+
102+
private void body(
103+
XbsValueType.BbsEbsMbsScenario scenario, String bbsEbsMbsString, TestInfo testInfo) {
104+
final int cds = scenario.callDataSize();
105+
String transactionCallData = bbsEbsMbsString + GIBBERISH;
106+
107+
ToyAccount targetAccount = receiverAccountBuilder.code(modexpCallerCode(cds).compile()).build();
108+
109+
Transaction tx =
110+
ToyTransaction.builder()
111+
.sender(senderAccount)
112+
.to(targetAccount)
113+
.keyPair(keyPair)
114+
.payload(Bytes.fromHexString(transactionCallData))
115+
.gasLimit((long) (1 << 24))
116+
.build();
117+
118+
ToyExecutionEnvironmentV2.builder(chainConfig, testInfo)
119+
.accounts(List.of(senderAccount, targetAccount))
120+
.transaction(tx)
121+
.build()
122+
.run();
123+
}
124+
125+
static Map<XbsValueType.BbsEbsMbsScenario, List<String>> allParameters =
126+
Arrays.stream(XbsValueType.values())
127+
.flatMap(
128+
bbsType ->
129+
Arrays.stream(XbsValueType.values())
130+
.flatMap(
131+
ebsType ->
132+
Arrays.stream(XbsValueType.values())
133+
.map(
134+
mbsType ->
135+
Map.entry(
136+
new XbsValueType.BbsEbsMbsScenario(
137+
bbsType, ebsType, mbsType),
138+
getParameters(
139+
new XbsValueType.BbsEbsMbsScenario(
140+
bbsType, ebsType, mbsType))))))
141+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
142+
143+
static Stream<Arguments> modexpXbsLimitsTestsNighlySource() {
144+
145+
List<Arguments> arguments = new ArrayList<>();
146+
for (Map.Entry<XbsValueType.BbsEbsMbsScenario, List<String>> entry : allParameters.entrySet()) {
147+
XbsValueType.BbsEbsMbsScenario scenario = entry.getKey();
148+
List<String> parametersList = entry.getValue();
149+
150+
for (String parameter : parametersList) {
151+
arguments.add(Arguments.of(scenario, parameter));
152+
}
153+
}
154+
155+
return arguments.stream();
156+
}
157+
158+
static Stream<Arguments> modexpXbsLimitTestsSource() {
159+
List<Arguments> arguments = new ArrayList<>(modexpXbsLimitsTestsNighlySource().toList());
160+
Collections.shuffle(arguments, new Random(LocalDate.now().toEpochDay()));
161+
return arguments.stream().limit(arguments.size() / 40); // Execute 2.5 % of the tests
162+
}
163+
164+
static List<String> getParameters(XbsValueType.BbsEbsMbsScenario bbsEbsMbsScenario) {
165+
166+
List<String> parameters = new ArrayList<>();
167+
168+
for (String bbs : getListOfInputs(bbsEbsMbsScenario.bbsValueType())) {
169+
for (String ebs : getListOfInputs(bbsEbsMbsScenario.ebsValueType())) {
170+
for (String mbs : getListOfInputs(bbsEbsMbsScenario.mbsValueType())) {
171+
parameters.add(bbs + ebs + mbs);
172+
}
173+
}
174+
}
175+
176+
return parameters;
177+
}
178+
}

0 commit comments

Comments
 (0)