Skip to content

Commit

Permalink
[Feature] modexp precompile (#3)
Browse files Browse the repository at this point in the history
* Add initial implementation for modexp precompile

* Add constants

* Update ModExp

* Move precompile to precompiles/

* Get the calldata & add some checks

* Comment WIP code

* Fix

* modexp MVP
  • Loading branch information
ilitteri authored Jul 28, 2023
1 parent bb2b95f commit f7eae0d
Showing 1 changed file with 102 additions and 0 deletions.
102 changes: 102 additions & 0 deletions precompiles/Modexp.yul
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
object "ModExp" {
code { }
object "ModExp_deployed" {
code {
////////////////////////////////////////////////////////////////
// CONSTANTS
////////////////////////////////////////////////////////////////

function ZERO() -> zero {
zero := 0x0
}

function ONE() -> one {
one := 0x1
}

//////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////

// @dev Packs precompile parameters into one word.
// Note: functions expect to work with 32/64 bits unsigned integers.
// Caller should ensure the type matching before!
function unsafePackPrecompileParams(
uint32_inputOffsetInWords,
uint32_inputLengthInWords,
uint32_outputOffsetInWords,
uint32_outputLengthInWords,
uint64_perPrecompileInterpreted
) -> rawParams {
rawParams := uint32_inputOffsetInWords
rawParams := or(rawParams, shl(32, uint32_inputLengthInWords))
rawParams := or(rawParams, shl(64, uint32_outputOffsetInWords))
rawParams := or(rawParams, shl(96, uint32_outputLengthInWords))
rawParams := or(rawParams, shl(192, uint64_perPrecompileInterpreted))
}

/// @dev Executes the `precompileCall` opcode.
function precompileCall(precompileParams, gasToBurn) -> ret {
// Compiler simulation for calling `precompileCall` opcode
ret := verbatim_2i_1o("precompile", precompileParams, gasToBurn)
}

////////////////////////////////////////////////////////////////
// FALLBACK
////////////////////////////////////////////////////////////////

let base_length := calldataload(0)
mstore(0, base_length)

let exponent_length := calldataload(32)
mstore(32, exponent_length)

let modulus_length := calldataload(64)
mstore(64, modulus_length)

let base_length_pointer := 96
calldatacopy(add(96, sub(32, base_length)), base_length_pointer, base_length)

let exponent_length_pointer := add(base_length_pointer, base_length)
calldatacopy(add(128, sub(32, exponent_length)), exponent_length_pointer, exponent_length)

let modulus_length_pointer := add(exponent_length_pointer, exponent_length)
calldatacopy(add(160, sub(32, modulus_length)), modulus_length_pointer, modulus_length)

let base := mload(96)
let exponent := mload(128)
let modulus := mload(160)

// 1^exponent % modulus = 1
if eq(base, ONE()) {
mstore(196, ONE())
return(196, modulus_length)
}

// base^0 % modulus = 1
if iszero(exponent) {
mstore(196, ONE())
return(196, modulus_length)
}

// base^exponent % 0 = 0
if iszero(modulus) {
mstore(196, ZERO())
return(196, modulus_length)
}

let pow := 1
base := mod(base, modulus)
for { let i := 0 } gt(exponent, ZERO()) { i := add(i, 1) } {
if eq(mod(exponent, 2), ONE()) {
pow := mulmod(pow, base, modulus)
}
exponent := shr(1, exponent)
base := mulmod(base, base, modulus)
}

mstore(196, pow)
return(196, modulus_length)
}
}
}

0 comments on commit f7eae0d

Please sign in to comment.