Skip to content

Commit f93e772

Browse files
committed
Merge branch 'main' of github.com:scroll-tech/scroll-revm into feat/enable_eip7939_clz
2 parents 6357cf3 + 205ec3e commit f93e772

File tree

3 files changed

+166
-1
lines changed

3 files changed

+166
-1
lines changed

src/precompile/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ impl ScrollPrecompileProvider {
3131
ScrollSpecId::BERNOULLI | ScrollSpecId::CURIE | ScrollSpecId::DARWIN => bernoulli(),
3232
ScrollSpecId::EUCLID => euclid(),
3333
ScrollSpecId::FEYNMAN => feynman(),
34+
ScrollSpecId::GALILEO => galileo(),
3435
};
3536
Self { precompile_provider: EthPrecompiles { precompiles, spec: SpecId::default() }, spec }
3637
}
@@ -102,6 +103,15 @@ pub(crate) fn feynman() -> &'static Precompiles {
102103
})
103104
}
104105

106+
pub(crate) fn galileo() -> &'static Precompiles {
107+
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
108+
INSTANCE.get_or_init(|| {
109+
let mut precompiles = feynman().clone();
110+
precompiles.extend([modexp::GALILEO, secp256r1::P256VERIFY_OSAKA]);
111+
Box::new(precompiles)
112+
})
113+
}
114+
105115
impl<CTX> PrecompileProvider<CTX> for ScrollPrecompileProvider
106116
where
107117
CTX: ContextTr<Cfg: Cfg<Spec = ScrollSpecId>>,

src/precompile/modexp.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use revm::{
22
precompile::{
3+
modexp,
34
modexp::{berlin_gas_calc, run_inner},
45
u64_to_address,
56
utilities::right_pad_with_offset,
@@ -17,6 +18,9 @@ pub const BERNOULLI_LEN_LIMIT: U256 = U256::from_limbs([32, 0, 0, 0]);
1718
/// The MODEXP precompile with BERNOULLI length limit rule.
1819
pub const BERNOULLI: Precompile = Precompile::new(PrecompileId::ModExp, ADDRESS, bernoulli_run);
1920

21+
/// The Galileo MODEXP precompile.
22+
pub const GALILEO: Precompile = Precompile::new(PrecompileId::ModExp, ADDRESS, modexp::osaka_run);
23+
2024
/// The bernoulli MODEXP precompile implementation.
2125
///
2226
/// # Errors
@@ -45,3 +49,149 @@ pub fn bernoulli_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
4549
const OSAKA: bool = false;
4650
run_inner::<_, OSAKA>(input, gas_limit, 200, berlin_gas_calc)
4751
}
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use super::*;
56+
use revm::primitives::hex;
57+
use std::vec;
58+
59+
#[test]
60+
fn test_galileo_modexp_backward_compatibility() {
61+
// Test case: verify that Galileo modexp doesn't affect behavior before FEYNMAN
62+
// Using a standard modexp test case: base=3, exp=5, mod=7
63+
// Expected result: 3^5 mod 7 = 243 mod 7 = 5
64+
65+
// Input format: [base_len(32 bytes)][exp_len(32 bytes)][mod_len(32 bytes)][base][exp][mod]
66+
// base_len = 1, exp_len = 1, mod_len = 1
67+
// base = 3, exp = 5, mod = 7
68+
let input = hex::decode(
69+
"0000000000000000000000000000000000000000000000000000000000000001\
70+
0000000000000000000000000000000000000000000000000000000000000001\
71+
0000000000000000000000000000000000000000000000000000000000000001\
72+
03\
73+
05\
74+
07",
75+
)
76+
.unwrap();
77+
78+
let gas_limit = 100000u64;
79+
80+
// Test BERNOULLI behavior
81+
let bernoulli_result = bernoulli_run(&input, gas_limit);
82+
assert!(bernoulli_result.is_ok(), "BERNOULLI modexp should succeed");
83+
let bernoulli_output = bernoulli_result.unwrap();
84+
85+
// Test Galileo behavior
86+
let galileo_result = modexp::osaka_run(&input, gas_limit);
87+
assert!(galileo_result.is_ok(), "GALILEO modexp should succeed");
88+
let galileo_output = galileo_result.unwrap();
89+
90+
// Verify both produce the same result
91+
assert_eq!(
92+
bernoulli_output.bytes, galileo_output.bytes,
93+
"Galileo modexp should produce the same result as BERNOULLI for valid inputs"
94+
);
95+
96+
// Verify that Galileo uses more gas (OSAKA gas rules vs Berlin gas rules)
97+
assert!(
98+
galileo_output.gas_used >= bernoulli_output.gas_used,
99+
"Galileo should use at least as much gas as BERNOULLI (OSAKA gas rules)"
100+
);
101+
102+
// Expected result: 3^5 mod 7 = 5
103+
let expected = vec![5u8];
104+
assert_eq!(bernoulli_output.bytes.as_ref(), &expected);
105+
assert_eq!(galileo_output.bytes.as_ref(), &expected);
106+
}
107+
108+
#[test]
109+
fn test_galileo_modexp_with_32_byte_limit() {
110+
// Test that Galileo handles the 32-byte limit differently than BERNOULLI
111+
// Input with base_len = 33 (exceeds BERNOULLI limit)
112+
let input = hex::decode(
113+
"0000000000000000000000000000000000000000000000000000000000000021\
114+
0000000000000000000000000000000000000000000000000000000000000001\
115+
0000000000000000000000000000000000000000000000000000000000000001\
116+
030303030303030303030303030303030303030303030303030303030303030303\
117+
05\
118+
07",
119+
)
120+
.unwrap();
121+
122+
let gas_limit = 100000u64;
123+
124+
// BERNOULLI should reject this (base length > 32)
125+
let bernoulli_result = bernoulli_run(&input, gas_limit);
126+
assert!(bernoulli_result.is_err(), "BERNOULLI should reject base_len > 32");
127+
assert!(
128+
matches!(bernoulli_result.unwrap_err(), PrecompileError::Other(msg) if msg.contains("ModexpBaseOverflow")),
129+
"BERNOULLI should return ModexpBaseOverflow error"
130+
);
131+
132+
// Galileo should accept this (no 32-byte limit)
133+
let galileo_result = modexp::osaka_run(&input, gas_limit);
134+
assert!(galileo_result.is_ok(), "Galileo should accept base_len > 32");
135+
136+
// Verify the computed result is correct
137+
// (0x030303...0303)^5 mod 7 = 0
138+
let galileo_output = galileo_result.unwrap();
139+
let expected = vec![0u8];
140+
assert_eq!(
141+
galileo_output.bytes.as_ref(),
142+
&expected,
143+
"Galileo should compute correct modexp result"
144+
);
145+
}
146+
147+
#[test]
148+
fn test_galileo_modexp_preserves_feynman_behavior() {
149+
// Test with inputs that should work in all versions
150+
// This ensures Galileo doesn't break existing functionality
151+
let test_cases = vec![
152+
// Small values
153+
(
154+
"0000000000000000000000000000000000000000000000000000000000000001\
155+
0000000000000000000000000000000000000000000000000000000000000001\
156+
0000000000000000000000000000000000000000000000000000000000000001\
157+
02\
158+
03\
159+
05",
160+
vec![3u8], // 2^3 mod 5 = 8 mod 5 = 3
161+
),
162+
// Zero exponent (should return 1)
163+
(
164+
"0000000000000000000000000000000000000000000000000000000000000001\
165+
0000000000000000000000000000000000000000000000000000000000000001\
166+
0000000000000000000000000000000000000000000000000000000000000001\
167+
05\
168+
00\
169+
0d",
170+
vec![1u8], // 5^0 mod 13 = 1
171+
),
172+
];
173+
174+
for (input_hex, expected) in test_cases {
175+
let input = hex::decode(input_hex).unwrap();
176+
let gas_limit = 100000u64;
177+
178+
let bernoulli_result = bernoulli_run(&input, gas_limit).unwrap();
179+
let galileo_result = modexp::osaka_run(&input, gas_limit).unwrap();
180+
181+
assert_eq!(
182+
bernoulli_result.bytes.as_ref(),
183+
&expected,
184+
"BERNOULLI should produce expected result"
185+
);
186+
assert_eq!(
187+
galileo_result.bytes.as_ref(),
188+
&expected,
189+
"Galileo should produce expected result"
190+
);
191+
assert_eq!(
192+
bernoulli_result.bytes, galileo_result.bytes,
193+
"Galileo and BERNOULLI should produce identical results for valid inputs"
194+
);
195+
}
196+
}
197+
}

src/spec.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub enum ScrollSpecId {
1212
#[default]
1313
EUCLID = 5,
1414
FEYNMAN = 6,
15+
GALILEO = 7,
1516
}
1617

1718
impl ScrollSpecId {
@@ -41,7 +42,8 @@ impl ScrollSpecId {
4142
Self::CURIE |
4243
Self::DARWIN |
4344
Self::EUCLID |
44-
Self::FEYNMAN => SpecId::SHANGHAI,
45+
Self::FEYNMAN |
46+
Self::GALILEO => SpecId::SHANGHAI,
4547
}
4648
}
4749
}
@@ -62,6 +64,7 @@ pub mod name {
6264
pub const DARWIN: &str = "darwin";
6365
pub const EUCLID: &str = "euclid";
6466
pub const FEYNMAN: &str = "feynman";
67+
pub const GALILEO: &str = "galileo";
6568
}
6669

6770
impl From<&str> for ScrollSpecId {
@@ -73,6 +76,7 @@ impl From<&str> for ScrollSpecId {
7376
name::DARWIN => Self::DARWIN,
7477
name::EUCLID => Self::EUCLID,
7578
name::FEYNMAN => Self::FEYNMAN,
79+
name::GALILEO => Self::GALILEO,
7680
_ => Self::default(),
7781
}
7882
}
@@ -87,6 +91,7 @@ impl From<ScrollSpecId> for &'static str {
8791
ScrollSpecId::DARWIN => name::DARWIN,
8892
ScrollSpecId::EUCLID => name::EUCLID,
8993
ScrollSpecId::FEYNMAN => name::FEYNMAN,
94+
ScrollSpecId::GALILEO => name::GALILEO,
9095
}
9196
}
9297
}

0 commit comments

Comments
 (0)