Skip to content

Commit

Permalink
evm: add sha512-256 precompile
Browse files Browse the repository at this point in the history
  • Loading branch information
ptrus committed Jul 10, 2023
1 parent ca630e7 commit 029a936
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 20 deletions.
44 changes: 44 additions & 0 deletions runtime-sdk/modules/evm/src/precompile/auxiliary.rs
@@ -0,0 +1,44 @@
//! Implements additional precompiles that are not part of the EVM specification.
use evm::{
executor::stack::{PrecompileHandle, PrecompileOutput},
ExitSucceed,
};
use ripemd160::Digest as _;
use sha2::Sha512Trunc256;

use super::{record_linear_cost, PrecompileResult};

pub(super) fn call_sha512_256(handle: &mut impl PrecompileHandle) -> PrecompileResult {
record_linear_cost(handle, handle.input().len() as u64, 60, 12)?; // TODO: sensible gas costs, not sure what to set.

let mut hasher = Sha512Trunc256::new();
hasher.update(handle.input());
let digest = hasher.finalize();

Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
output: digest.to_vec(),
})
}

#[cfg(test)]
mod test {
use super::super::test::*;

#[test]
fn test_sha512_256() {
let input = "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02";
let ret = call_contract(
H160([
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0x01,
]),
&hex::decode(input).unwrap(),
3000,
)
.unwrap();
assert_eq!(
hex::encode(ret.unwrap().output),
"41f7883fc8df1d31b1b1f7c0379f7b5a990d457347d997fdd76a2f4bb5812342"
);
}
}
1 change: 1 addition & 0 deletions runtime-sdk/modules/evm/src/precompile/confidential.rs
@@ -1,3 +1,4 @@
//! Implements the confidential precompiles.
use std::{collections::HashMap, convert::TryInto};

use ethabi::{ParamType, Token};
Expand Down
48 changes: 28 additions & 20 deletions runtime-sdk/modules/evm/src/precompile/mod.rs
Expand Up @@ -10,6 +10,7 @@ use primitive_types::H160;

use crate::{backend::EVMBackendExt, Config};

mod auxiliary;
mod confidential;
mod standard;

Expand Down Expand Up @@ -80,33 +81,40 @@ impl<Cfg: Config, B: EVMBackendExt> PrecompileSet for Precompiles<'_, Cfg, B> {
if !self.is_precompile(address) {
return None;
}
Some(match (address[0], address[19]) {
(0, 1) => standard::call_ecrecover(handle),
(0, 2) => standard::call_sha256(handle),
(0, 3) => standard::call_ripemd160(handle),
(0, 4) => standard::call_datacopy(handle),
(0, 5) => standard::call_bigmodexp(handle),
(1, 1) => confidential::call_random_bytes(handle, self.backend),
(1, 2) => confidential::call_x25519_derive(handle),
(1, 3) => confidential::call_deoxysii_seal(handle),
(1, 4) => confidential::call_deoxysii_open(handle),
(1, 5) => confidential::call_keypair_generate(handle),
(1, 6) => confidential::call_sign(handle),
(1, 7) => confidential::call_verify(handle),
(1, 8) => confidential::call_curve25519_compute_public(handle),
Some(match (address[0], address[18], address[19]) {
// Standard precompiles.
(0, 0, 1) => standard::call_ecrecover(handle),
(0, 0, 2) => standard::call_sha256(handle),
(0, 0, 3) => standard::call_ripemd160(handle),
(0, 0, 4) => standard::call_datacopy(handle),
(0, 0, 5) => standard::call_bigmodexp(handle),
// Confidential precompiles.
(1, 0, 1) => confidential::call_random_bytes(handle, self.backend),
(1, 0, 2) => confidential::call_x25519_derive(handle),
(1, 0, 3) => confidential::call_deoxysii_seal(handle),
(1, 0, 4) => confidential::call_deoxysii_open(handle),
(1, 0, 5) => confidential::call_keypair_generate(handle),
(1, 0, 6) => confidential::call_sign(handle),
(1, 0, 7) => confidential::call_verify(handle),
(1, 0, 8) => confidential::call_curve25519_compute_public(handle),
// Auxiliary precompiles.
(1, 1, 1) => auxiliary::call_sha512_256(handle),
_ => return Cfg::additional_precompiles().and_then(|pc| pc.execute(handle)),
})
}

fn is_precompile(&self, address: H160) -> bool {
// All Ethereum precompiles are zero except for the last byte, which is no more than five.
// Otherwise, when confidentiality is enabled, Oasis precompiles start with one and have a last byte of no more than four.
let addr_bytes = address.as_bytes();
let (first, last) = (address[0], addr_bytes[19]);
(address[1..19].iter().all(|b| *b == 0)
let (first, second_last, last) = (address[0], addr_bytes[18], addr_bytes[19]);
(address[1..18].iter().all(|b| *b == 0)
&& matches!(
(first, last, Cfg::CONFIDENTIAL),
(0, 1..=5, _) | (1, 1..=8, true)
(first, second_last, last, Cfg::CONFIDENTIAL),
// Standard.
(0, 0, 1..=6, _) |
// Confidential.
(1, 0, 1..=8, true) |
// Auxiliary.
(1, 1, 1, _)
))
|| Cfg::additional_precompiles()
.map(|pc| pc.is_precompile(address))
Expand Down
1 change: 1 addition & 0 deletions runtime-sdk/modules/evm/src/precompile/standard.rs
@@ -1,3 +1,4 @@
//! Implements the standard precompiles as defined in the EVM specification.
use std::{
cmp::{max, min, Ordering},
convert::TryFrom,
Expand Down

0 comments on commit 029a936

Please sign in to comment.