I am wondering how the precompiled contract at address 5 (introduced by EIP-198) can actually be used to do RSA signature verification in Solidity, i.e., how it can be called by another contract (implemented in Solidity) with big integers (larger than 32 byte), e.g., a 4096-bit RSA modulus.
I am aware of the code provided in https://ethereum.stackexchange.com/a/71590. However, the solution focuses on modular exponentiation in which each component (base, exponent, modulus) can be represented with a variable of type uint256. With the RSA modulus typically being of size 1,024 or 2,048 or 4,096 (bits), this solution does not seem to be sufficient to do RSA signature verification. Hence, I am wondering how the solution can be extended to send and receive big integers (represented as bytes) to the precompiled contract. (Note: As RSA verification in practice usually uses an exponent of 3 or 65537, the exponent does not need to be of type bytes)
I would imagine a function for modular exponentation with a 4,096-bit RSA modulus to look (more or less) like this:
function modExp(bytes memory _b, uint _e, bytes memory _m) public returns (bytes memory result) {
assembly {
// Free memory pointer
let pointer := mload(0x40)
// Define length of base, exponent and modulus. Exponent = 32 bytes (0x20), base and modulus = 4096 bit (0x1000)
mstore(pointer, 0x1000)
mstore(add(pointer, 0x20), 0x20)
mstore(add(pointer, 0x40), 0x1000)
// Define variables base, exponent and modulus
mstore(add(pointer, 0x60), _b)
mstore(add(pointer, 0x1060), _e) //position increments by 0x1000 as _b is of size 0x1000
mstore(add(pointer, 0x1080), _m) //position increments by 0x20 as _e is of size 0x20
// Store the result
let value := mload(0x2080) //position increments by 0x1000 as _m is of size 0x1000
// Call the precompiled contract 0x05 = bigModExp
if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) {
revert(0, 0)
}
result := mload(value)
}
}
Thanks!
_bis longer you have to iterate over the memory pointer. – Ismael Aug 16 '22 at 04:09