11use 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.
1819pub 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+ }
0 commit comments