File tree 8 files changed +118
-2
lines changed
8 files changed +118
-2
lines changed Original file line number Diff line number Diff line change 2
2
src = ' src'
3
3
out = ' artifacts'
4
4
libs = [" node_modules" , " lib" ]
5
+ evm_version = " shanghai"
5
6
ffi =true
6
7
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
Original file line number Diff line number Diff line change 42
42
complete:
43
43
}
44
44
45
-
45
+ #define macro MODEXP() = takes (3) returns (1) {
46
+ dup1
47
+ iszero MODULUS_ZERO jumpi // Compare it to zero
48
+ MODULUS_NOT_ZERO jump
49
+
50
+ MODULUS_NOT_ZERO:
51
+ // Setting up correct memory layout
52
+ 0x20 push1 0x0 mstore // Store length of base (32 bytes) at memory 0x00
53
+ 0x20 0x20 mstore // Store length of exponent (32 bytes) at memory 0x40
54
+ 0x20 0x40 mstore // Store length of modulus (32 bytes) at memory 0x80
55
+
56
+ 0xa0 mstore // Store 'modulus' at memory 0xa0
57
+ 0x80 mstore // Store 'exponent' at memory 0xc0
58
+ 0x60 mstore // Store 'base' at memory 0x60
59
+
60
+ // Prepare staticcall to precompiled contract
61
+
62
+ 0x20 // Output data size (32 bytes)
63
+ push1 0x0 // Output data memory
64
+ 0xc0 // Input data size (192 bytes)
65
+ push1 0x0 // Input data starting position
66
+ 0x05 // Address of the modexp precompiled contract (0x05)
67
+ gas // Gas provided
68
+ staticcall
69
+
70
+ // Verify the call success
71
+ iszero STATIC_CALL_FAILED jumpi // Check if the staticcall was successful
72
+ CALL_SUCCESSFUL jump // If staticcall returned 0 (failure), revert
73
+
74
+ MODULUS_ZERO:
75
+ push1 0x0 mload
76
+ revert // Revert if modulus is zero
77
+
78
+ STATIC_CALL_FAILED:
79
+ push1 0x0 mload
80
+ revert // Revert if staticcall failed
81
+
82
+ // Label for call success
83
+ CALL_SUCCESSFUL:
84
+ push1 0x0 mload // Load the result from memory location 0x00
85
+ END jump // Jump to the end of the macro
86
+
87
+ END:
88
+ // The result of base^exponent % modulus is now on top of the stack
89
+ }
Original file line number Diff line number Diff line change @@ -12,4 +12,6 @@ interface IMath {
12
12
function divideNumbers (uint256 , uint256 ) external view returns (uint256 );
13
13
14
14
function abs (uint256 , uint256 ) external view returns (uint256 );
15
+
16
+ function modExp (uint256 , uint256 , uint256 ) external view returns (uint256 );
15
17
}
Original file line number Diff line number Diff line change 6
6
#define function multiplyNumbers(uint256,uint256) nonpayable returns (uint256)
7
7
#define function divideNumbers(uint256,uint256) nonpayable returns (uint256)
8
8
#define function abs(uint256,uint256) nonpayable returns (uint256)
9
+ #define function modExp(uint256,uint256,uint256) nonpayable returns (uint256)
9
10
10
11
#define macro ADD_WRAPPER() = takes (2) returns (1) {
11
12
0x04 calldataload // [num1]
47
48
0x20 0x00 return // []
48
49
}
49
50
50
-
51
+ #define macro MODEXP_WRAPPER() = takes (3) returns (1) {
52
+ 0x04 calldataload // [base]
53
+ 0x24 calldataload // [exponent, base]
54
+ 0x44 calldataload // [modulus, exponent, base]
55
+ MODEXP() // [base^exponent mod modulus]
56
+ 0x00 mstore // []
57
+ 0x20 0x00 return // []
58
+ }
51
59
52
60
53
61
#define macro MAIN() = takes (0) returns (0) {
63
71
dup1 0xd3f3cd7b eq multiplyNumbers jumpi
64
72
dup1 0x8fce12ed eq divideNumbers jumpi
65
73
dup1 0xe093a157 eq abs jumpi
74
+ dup1 0x3148f14f eq modExp jumpi
66
75
67
76
68
77
addNumbers:
76
85
77
86
divideNumbers:
78
87
DIVIDE_WRAPPER()
88
+
89
+ modExp:
90
+ MODEXP_WRAPPER()
79
91
80
92
abs:
81
93
ABS_WRAPPER()
Original file line number Diff line number Diff line change @@ -93,4 +93,29 @@ contract MathTest is Test {
93
93
uint256 _result = a > b ? a - b : b - a;
94
94
require (math.abs (a, b) == _result);
95
95
}
96
+
97
+ function testModExp () public {
98
+ // Example test: 2^3 % 5 should equal 3
99
+ uint256 base = 2 ;
100
+ uint256 exponent = 3 ;
101
+ uint256 modulus = 5 ;
102
+ uint256 expected = 3 ;
103
+
104
+ uint256 result = math.modExp (base, exponent, modulus);
105
+ assertEq (result, expected, "modExp did not return the expected value " );
106
+ }
107
+
108
+ // function testModExp_fuzz(uint256 b, uint256 e, uint256 m) public {
109
+ // // To avoid testing with modulus zero, which would revert
110
+ // vm.assume(m > 1);
111
+ // // To avoid gas issues, cap the exponent
112
+ // uint256 exponent = e % 256;
113
+
114
+ // // The actual modExp calculation can be complicated to emulate in Solidity due to gas constraints,
115
+ // // so here we just test that the function does not revert and returns a value
116
+ // // less than the modulus.
117
+ // uint256 result = math.modExp(b, exponent, m);
118
+
119
+ // assertLt(result, m, "modExp result should be less than the modulus");
120
+ // }
96
121
}
Original file line number Diff line number Diff line change @@ -36,4 +36,15 @@ contract MathForkTest is Test {
36
36
function testAbs () public view {
37
37
require (math.abs (1 , 10 ) == 9 );
38
38
}
39
+
40
+ function testModExp () public {
41
+ // Example test: 2^3 % 5 should equal 3
42
+ uint256 base = 2 ;
43
+ uint256 exponent = 3 ;
44
+ uint256 modulus = 5 ;
45
+ uint256 expected = 3 ;
46
+
47
+ uint256 result = math.modExp (base, exponent, modulus);
48
+ assertEq (result, expected, "modExp did not return the expected value " );
49
+ }
39
50
}
Original file line number Diff line number Diff line change 75
75
ASSERT_EQ() // [4e18==result]
76
76
}
77
77
78
+ #define test TEST_MODEXP() = {
79
+ // Test case 1: Simple modular exponentiation
80
+ // Using small numbers for easy manual verification: 2^3 % 5 = 3
81
+ 0x02 // [base = 2, exponent, modulus]
82
+ 0x03 // [exponent = 3, modulus]
83
+ 0x05 // [modulus = 5]
84
+ MODEXP() // [result]
85
+ 0x03 // [expected = 3, result]
86
+ ASSERT_EQ() // [3 == result]
87
+
88
+ // Test case 2: Larger numbers
89
+ // We need to choose numbers such that we can calculate the expected result manually or with a tool
90
+ // For example: (0x04)^2 % 0x05 = 0x01
91
+ 0x04 // [base = 4, exponent, modulus]
92
+ 0x02 // [exponent = 2, modulus]
93
+ 0x05 // [modulus = 5]
94
+ MODEXP() // [result]
95
+ 0x01 // [expected = 4, result]
96
+ ASSERT_EQ() // [4 == result]
97
+ }
98
+
You can’t perform that action at this time.
0 commit comments