diff --git a/Cargo.lock b/Cargo.lock index 7be75cda91..8a347e4ee4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6509,6 +6509,7 @@ dependencies = [ "petgraph 0.5.1", "primitive-types 0.12.2", "revm-precompile", + "revm-primitives", "rlp", "serde 1.0.202", "serde_bytes", diff --git a/Cargo.toml b/Cargo.toml index aced115c7e..06033c07f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -295,6 +295,7 @@ bitcoincore-rpc-json = "0.18.0" toml = "0.8.12" csv = "1.2.1" revm-precompile = "7.0.0" +revm-primitives = "4.0.0" # Note: the BEGIN and END comments below are required for external tooling. Do not remove. # BEGIN MOVE DEPENDENCIES diff --git a/frameworks/moveos-stdlib/Cargo.toml b/frameworks/moveos-stdlib/Cargo.toml index 3e07fdf42b..9fb722501a 100644 --- a/frameworks/moveos-stdlib/Cargo.toml +++ b/frameworks/moveos-stdlib/Cargo.toml @@ -35,6 +35,7 @@ primitive-types = { workspace = true } bech32 = { workspace = true } bs58 = { workspace = true, features = ["check"] } revm-precompile = { workspace = true } +revm-primitives = { workspace = true } move-binary-format = { workspace = true } move-bytecode-utils = { workspace = true } diff --git a/frameworks/moveos-stdlib/doc/evm.md b/frameworks/moveos-stdlib/doc/evm.md index 0d212693b4..f681d098c7 100644 --- a/frameworks/moveos-stdlib/doc/evm.md +++ b/frameworks/moveos-stdlib/doc/evm.md @@ -6,12 +6,20 @@ - [Constants](#@Constants_0) +- [Function `ec_recover`](#0x2_evm_ec_recover) - [Function `sha2_256`](#0x2_evm_sha2_256) +- [Function `ripemd_160`](#0x2_evm_ripemd_160) +- [Function `identity`](#0x2_evm_identity) +- [Function `modexp`](#0x2_evm_modexp) - [Function `ec_add`](#0x2_evm_ec_add) +- [Function `ec_mul`](#0x2_evm_ec_mul) - [Function `ec_pairing`](#0x2_evm_ec_pairing) +- [Function `blake2f`](#0x2_evm_blake2f) +- [Function `point_evaluation`](#0x2_evm_point_evaluation)
use 0x1::hash;
+use 0x2::hash;
@@ -21,6 +29,15 @@
## Constants
+
+
+
+
+const ErrorBlake2fFailed: u64 = 9;
+
+
+
+
@@ -30,6 +47,15 @@
+
+
+
+
+const ErrorEcMulFailed: u64 = 7;
+
+
+
+
@@ -39,11 +65,57 @@
-
+
-const ErrorInvalidCoordinate: u64 = 11;
+const ErrorEcRecoverFailed: u64 = 1;
+
+
+
+
+
+
+
+
+const ErrorInvalidInputSize: u64 = 11;
+
+
+
+
+
+
+
+
+const ErrorModexpFailed: u64 = 5;
+
+
+
+
+
+
+
+
+const ErrorPointEvaluationFailed: u64 = 10;
+
+
+
+
+
+
+## Function `ec_recover`
+
+@param hash: Keccack-256 hash of the transaction.
+@param v: Recovery identifier, expected to be either 27 or 28.
+@param r: x-value, expected to be in the range ]0; secp256k1n[.
+@param s: Expected to be in the range ]0; secp256k1n[.
+
+@return public_address: The recovered 20-byte address right aligned to 32 bytes.
+
+Elliptic curve digital signature algorithm (ECDSA) public key recovery function.
+
+
+public fun ec_recover(hash: vector<u8>, v: vector<u8>, r: vector<u8>, s: vector<u8>): vector<u8>
@@ -52,7 +124,9 @@
## Function `sha2_256`
-@param data: Arbitrary binary data to hash
+@param data: Data to hash with SHA2-256.
+
+@return hash: The result hash.
Hash function.
@@ -62,6 +136,59 @@ Hash function.
+
+
+## Function `ripemd_160`
+
+@param data: Data to hash with RIPEMD-160.
+
+@return hash: The result 20-byte hash right aligned to 32 bytes.
+
+Hash function.
+
+
+public fun ripemd_160(data: vector<u8>): vector<u8>
+
+
+
+
+
+
+## Function `identity`
+
+@param data: Data to return.
+
+@return data: Data from input.
+
+Returns the input.
+
+
+public fun identity(data: vector<u8>): vector<u8>
+
+
+
+
+
+
+## Function `modexp`
+
+@param b_size: Byte size of B.
+@param e_size: Byte size of E.
+@param m_size: Byte size of M.
+@param b: Base as unsigned integer.
+@param e: Exponent as unsigned integer, if zero, then B ** E will be one.
+@param m: Modulo as unsigned integer, if zero, then returns zero.
+
+@return value: Result of the computation, with the same number of bytes as M.
+
+Arbitrary-precision exponentiation under modulo.
+
+
+public fun modexp(b_size: vector<u8>, e_size: vector<u8>, m_size: vector<u8>, b: vector<u8>, e: vector<u8>, m: vector<u8>): vector<u8>
+
+
+
+
## Function `ec_add`
@@ -71,9 +198,12 @@ Hash function.
@param x2: X coordinate of the second point on the elliptic curve 'alt_bn128'.
@param y2: Y coordinate of the second point on the elliptic curve 'alt_bn128'.
+@return x: X coordinate of the result point on the elliptic curve 'alt_bn128'.
+@return y: Y coordinate of the result point on the elliptic curve 'alt_bn128'.
+
Notes: The point at infinity is encoded with both field x and y at 0.
-Point addition (ADD) on the elliptic curve 'alt_bn128'
+Point addition (ADD) on the elliptic curve 'alt_bn128'.
public fun ec_add(x1: vector<u8>, y1: vector<u8>, x2: vector<u8>, y2: vector<u8>): (vector<u8>, vector<u8>)
@@ -81,6 +211,27 @@ Point addition (ADD) on the elliptic curve 'alt_bn128'
+
+
+## Function `ec_mul`
+
+@param x1: X coordinate of the first point on the elliptic curve 'alt_bn128'.
+@param y1: Y coordinate of the first point on the elliptic curve 'alt_bn128'.
+@param s: Scalar to use for the multiplication.
+
+@return x: X coordinate of the result point on the elliptic curve 'alt_bn128'.
+@return y: Y coordinate of the result point on the elliptic curve 'alt_bn128'.
+
+Notes: The point at infinity is encoded with both field x and y at 0.
+
+Scalar multiplication (MUL) on the elliptic curve 'alt_bn128'.
+
+
+public fun ec_mul(x1: vector<u8>, y1: vector<u8>, s: vector<u8>): (vector<u8>, vector<u8>)
+
+
+
+
## Function `ec_pairing`
@@ -88,6 +239,8 @@ Point addition (ADD) on the elliptic curve 'alt_bn128'
@param data: Coordinates of the points.
The input must always be a multiple of 6 32-byte values. 0 inputs is valid and returns 1.
+@return success: 1 if the pairing was a success, 0 otherwise.
+
Notes: The point at infinity is encoded with both field x and y at 0.
Bilinear function on groups on the elliptic curve 'alt_bn128'.
@@ -95,3 +248,44 @@ Bilinear function on groups on the elliptic curve 'alt_bn128'.
public fun ec_pairing(data: vector<u8>): vector<u8>
+
+
+
+
+
+## Function `blake2f`
+
+@param rounds: Number of rounds (big-endian unsigned integer).
+@param h: State vector (8 8-byte little-endian unsigned integer).
+@param m: Message block vector (16 8-byte little-endian unsigned integer).
+@param t: Offset counters (2 8-byte little-endian integer).
+@param f: Final block indicator flag (0 or 1).
+
+@return h: State vector (8 8-byte little-endian unsigned integer).
+
+Compression function F used in the BLAKE2 cryptographic hashing algorithm.
+
+
+public fun blake2f(rounds: vector<u8>, h: vector<u8>, m: vector<u8>, t: vector<u8>, f: vector<u8>): vector<u8>
+
+
+
+
+
+
+## Function `point_evaluation`
+
+@param versioned_hash: Reference to a blob in the execution layer.
+@param x: x-coordinate at which the blob is being evaluated.
+@param y: y-coordinate at which the blob is being evaluated.
+@param commitment: Commitment to the blob being evaluated.
+@param proof: Proof associated with the commitment.
+
+@return FIELD_ELEMENTS_PER_BLOB: The number of field elements in the blob.
+@return : BLS_MODULUS: The modulus used in the BLS signature scheme.
+
+Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof. Also verify that the provided commitment matches the provided versioned_hash.
+
+
+public fun point_evaluation(versioned_hash: vector<u8>, x: vector<u8>, y: vector<u8>, commitment: vector<u8>, proof: vector<u8>): (vector<u8>, vector<u8>)
+
diff --git a/frameworks/moveos-stdlib/sources/evm.move b/frameworks/moveos-stdlib/sources/evm.move
index 7048960abb..23ab05066f 100644
--- a/frameworks/moveos-stdlib/sources/evm.move
+++ b/frameworks/moveos-stdlib/sources/evm.move
@@ -3,40 +3,149 @@
// Evm Precompiled Contracts https://www.evm.codes/precompiled?fork=cancun
module moveos_std::evm {
+ use std::vector;
+ use moveos_std::hash;
+ const ErrorEcRecoverFailed: u64 = 1;
+ const ErrorModexpFailed: u64 = 5;
const ErrorEcAddFailed: u64 = 6;
+ const ErrorEcMulFailed: u64 = 7;
const ErrorEcPairingFailed: u64 = 8;
+ const ErrorBlake2fFailed: u64 = 9;
+ const ErrorPointEvaluationFailed: u64 = 10;
+ const ErrorInvalidInputSize: u64 = 11;
+
+ /// @param hash: Keccack-256 hash of the transaction.
+ /// @param v: Recovery identifier, expected to be either 27 or 28.
+ /// @param r: x-value, expected to be in the range ]0; secp256k1n[.
+ /// @param s: Expected to be in the range ]0; secp256k1n[.
+ ///
+ /// @return public_address: The recovered 20-byte address right aligned to 32 bytes.
+ ///
+ /// Elliptic curve digital signature algorithm (ECDSA) public key recovery function.
+ public native fun ec_recover(hash: vector, v: vector, r: vector, s: vector): vector;
- // The coordinate must be 32 bytes.
- const ErrorInvalidCoordinate: u64 = 11;
-
- /// @param data: Arbitrary binary data to hash
+ /// @param data: Data to hash with SHA2-256.
+ ///
+ /// @return hash: The result hash.
///
/// Hash function.
public fun sha2_256(data: vector): vector {
std::hash::sha2_256(data)
}
+ /// @param data: Data to hash with RIPEMD-160.
+ ///
+ /// @return hash: The result 20-byte hash right aligned to 32 bytes.
+ ///
+ /// Hash function.
+ public fun ripemd_160(data: vector): vector {
+ hash::ripemd160(&data)
+ }
+
+ /// @param data: Data to return.
+ ///
+ /// @return data: Data from input.
+ ///
+ /// Returns the input.
+ public fun identity(data: vector): vector {
+ let data_clone = data;
+ data_clone
+ }
+
+ /// @param b_size: Byte size of B.
+ /// @param e_size: Byte size of E.
+ /// @param m_size: Byte size of M.
+ /// @param b: Base as unsigned integer.
+ /// @param e: Exponent as unsigned integer, if zero, then B ** E will be one.
+ /// @param m: Modulo as unsigned integer, if zero, then returns zero.
+ ///
+ /// @return value: Result of the computation, with the same number of bytes as M.
+ ///
+ /// Arbitrary-precision exponentiation under modulo.
+ public native fun modexp(b_size: vector, e_size: vector, m_size: vector, b: vector, e: vector, m: vector): vector;
+
/// @param x1: X coordinate of the first point on the elliptic curve 'alt_bn128'.
/// @param y1: Y coordinate of the first point on the elliptic curve 'alt_bn128'.
/// @param x2: X coordinate of the second point on the elliptic curve 'alt_bn128'.
/// @param y2: Y coordinate of the second point on the elliptic curve 'alt_bn128'.
+ ///
+ /// @return x: X coordinate of the result point on the elliptic curve 'alt_bn128'.
+ /// @return y: Y coordinate of the result point on the elliptic curve 'alt_bn128'.
///
/// Notes: The point at infinity is encoded with both field x and y at 0.
///
- /// Point addition (ADD) on the elliptic curve 'alt_bn128'
+ /// Point addition (ADD) on the elliptic curve 'alt_bn128'.
public native fun ec_add(x1: vector, y1: vector, x2: vector, y2: vector): (vector, vector);
+ /// @param x1: X coordinate of the first point on the elliptic curve 'alt_bn128'.
+ /// @param y1: Y coordinate of the first point on the elliptic curve 'alt_bn128'.
+ /// @param s: Scalar to use for the multiplication.
+ ///
+ /// @return x: X coordinate of the result point on the elliptic curve 'alt_bn128'.
+ /// @return y: Y coordinate of the result point on the elliptic curve 'alt_bn128'.
+ ///
+ /// Notes: The point at infinity is encoded with both field x and y at 0.
+ ///
+ /// Scalar multiplication (MUL) on the elliptic curve 'alt_bn128'.
+ public native fun ec_mul(x1: vector, y1: vector, s: vector): (vector, vector);
+
/// @param data: Coordinates of the points.
/// The input must always be a multiple of 6 32-byte values. 0 inputs is valid and returns 1.
+ ///
+ /// @return success: 1 if the pairing was a success, 0 otherwise.
///
/// Notes: The point at infinity is encoded with both field x and y at 0.
///
/// Bilinear function on groups on the elliptic curve 'alt_bn128'.
public native fun ec_pairing(data: vector): vector;
- #[test_only]
- use std::vector;
+ /// @param rounds: Number of rounds (big-endian unsigned integer).
+ /// @param h: State vector (8 8-byte little-endian unsigned integer).
+ /// @param m: Message block vector (16 8-byte little-endian unsigned integer).
+ /// @param t: Offset counters (2 8-byte little-endian integer).
+ /// @param f: Final block indicator flag (0 or 1).
+ ///
+ /// @return h: State vector (8 8-byte little-endian unsigned integer).
+ ///
+ /// Compression function F used in the BLAKE2 cryptographic hashing algorithm.
+ public native fun blake2f(rounds: vector, h: vector, m: vector, t: vector, f: vector): vector;
+
+ /// @param versioned_hash: Reference to a blob in the execution layer.
+ /// @param x: x-coordinate at which the blob is being evaluated.
+ /// @param y: y-coordinate at which the blob is being evaluated.
+ /// @param commitment: Commitment to the blob being evaluated.
+ /// @param proof: Proof associated with the commitment.
+ ///
+ /// @return FIELD_ELEMENTS_PER_BLOB: The number of field elements in the blob.
+ /// @return : BLS_MODULUS: The modulus used in the BLS signature scheme.
+ ///
+ /// Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof. Also verify that the provided commitment matches the provided versioned_hash.
+ public native fun point_evaluation(versioned_hash: vector, x: vector, y: vector, commitment: vector, proof: vector): (vector, vector);
+
+ #[test]
+ fun test_ec_recover() {
+ let hash = x"456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3";
+ let v = x"000000000000000000000000000000000000000000000000000000000000001c";
+ let r = x"9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608";
+ let s = x"4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada";
+
+ let public_address = ec_recover(hash, v, r, s);
+ assert!(public_address == x"0000000000000000000000007156526fbd7a3c72969b54f64e42c10fbb768c8a", ErrorEcRecoverFailed);
+ }
+
+ #[test]
+ fun test_modexp() {
+ let b_size = x"0000000000000000000000000000000000000000000000000000000000000001";
+ let e_size = x"0000000000000000000000000000000000000000000000000000000000000001";
+ let m_size = x"0000000000000000000000000000000000000000000000000000000000000001";
+ let b = x"08";
+ let e = x"09";
+ let m = x"0a";
+
+ let value = modexp(b_size, e_size, m_size, b, e, m);
+ assert!(value == x"08", ErrorModexpFailed);
+ }
#[test]
fun test_ec_add() {
@@ -50,6 +159,17 @@ module moveos_std::evm {
assert!(y3 == x"15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", ErrorEcAddFailed);
}
+ #[test]
+ fun test_ec_mul() {
+ let x1 = x"0000000000000000000000000000000000000000000000000000000000000001";
+ let y1 = x"0000000000000000000000000000000000000000000000000000000000000002";
+ let s = x"0000000000000000000000000000000000000000000000000000000000000002";
+
+ let (x, y) = ec_mul(x1, y1, s);
+ assert!(x == x"030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3", ErrorEcMulFailed);
+ assert!(y == x"15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", ErrorEcMulFailed);
+ }
+
#[test]
fun test_ec_pairing() {
let x1 = x"2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da";
@@ -82,7 +202,7 @@ module moveos_std::evm {
}
#[test]
- #[expected_failure(abort_code = ErrorInvalidCoordinate, location = Self)]
+ #[expected_failure(abort_code = ErrorInvalidInputSize, location = Self)]
fun test_ec_add_input_not_match() {
let x1 = x"01";
let y1 = x"02";
@@ -101,4 +221,29 @@ module moveos_std::evm {
ec_pairing(x1);
}
+
+ #[test]
+ fun test_blake2f() {
+ let rounds = x"0000000c";
+ let h = x"48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b";
+ let m = x"6162630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
+ let t = x"03000000000000000000000000000000";
+ let f = x"01";
+
+ let h = blake2f(rounds, h, m, t, f);
+ assert!(h == x"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", ErrorBlake2fFailed);
+ }
+
+ #[test]
+ fun test_point_evaluation() {
+ let versioned_hash = x"01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b";
+ let x = x"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000";
+ let y = x"1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9";
+ let commitment = x"8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7";
+ let proof = x"a62ad71d14c5719385c0686f1871430475bf3a00f0aa3f7b8dd99a9abc2160744faf0070725e00b60ad9a026a15b1a8c";
+
+ let (field_elements_per_blob, bls_modulus) = point_evaluation(versioned_hash, x, y, commitment, proof);
+ assert!(field_elements_per_blob == x"0000000000000000000000000000000000000000000000000000000000001000", ErrorPointEvaluationFailed);
+ assert!(bls_modulus == x"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", ErrorPointEvaluationFailed);
+ }
}
\ No newline at end of file
diff --git a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/evm.rs b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/evm.rs
index 2b838d7c42..f4e2dd4d37 100644
--- a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/evm.rs
+++ b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/evm.rs
@@ -8,20 +8,108 @@ use move_vm_runtime::native_functions::{NativeContext, NativeFunction};
use move_vm_types::{
loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value,
};
-use revm_precompile::bn128;
+use revm_precompile::{blake2, bn128, kzg_point_evaluation, modexp, secp256k1};
+use revm_primitives::Env;
use smallvec::smallvec;
use std::collections::VecDeque;
+pub const E_EC_RECOVER_FAILED: u64 = 1;
+pub const E_MODEXP_FAILED: u64 = 5;
pub const E_EC_ADD_FAILED: u64 = 6;
+pub const E_EC_MUL_FAILED: u64 = 7;
pub const E_EC_PAIRING_FAILED: u64 = 8;
-pub const E_INVALID_COORDINATE: u64 = 11;
+pub const E_BLAKE2F_FAILED: u64 = 9;
+pub const E_POINT_EVALUATION_FAILED: u64 = 10;
+pub const E_INVALID_INPUT_SIZE: u64 = 11;
/***************************************************************************************************
- * native fun ec_add
- * Implementation of the Move native function `ec_add(x1: vector, y1: vector, x2: vector, y2: vector): (vector, vector)`
- * gas cost: ec_add_cost_base | base cost for function call and fixed opers
- * + ec_add_data_cost_per_byte * 128 | cost depends on length of message
- * + ec_add_data_cost_per_block * num_blocks | cost depends on number of blocks in message
+ * native function `ec_recover(hash: vector, v: vector, r: vector, s: vector): vector`
+ **************************************************************************************************/
+pub fn native_ec_recover(
+ gas_params: &FromBytesGasParameters,
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 4);
+
+ let s = pop_arg!(args, Vec);
+ let r = pop_arg!(args, Vec);
+ let v = pop_arg!(args, Vec);
+ let hash = pop_arg!(args, Vec);
+
+ if s.len() != 32 || r.len() != 32 || v.len() != 32 || hash.len() != 32 {
+ return Ok(NativeResult::err(0.into(), E_INVALID_INPUT_SIZE));
+ }
+ let cost = gas_params.base + (gas_params.per_byte * NumBytes::new(128_u64));
+
+ let mut data: Vec = Vec::new();
+ data.extend(hash);
+ data.extend(v);
+ data.extend(r);
+ data.extend(s);
+
+ match secp256k1::ec_recover_run(&data.into(), 5000) {
+ Ok((_, out)) => Ok(NativeResult::ok(
+ cost,
+ smallvec![Value::vector_u8(out.to_vec())],
+ )),
+
+ Err(_) => Ok(NativeResult::err(cost, E_EC_RECOVER_FAILED)),
+ }
+}
+
+/***************************************************************************************************
+ * native function `modexp(b_size: vector, e_size: vector, m_size: vector, b: vector, e: vector, m: vector): vector`
+ **************************************************************************************************/
+pub fn native_modexp(
+ gas_params: &FromBytesGasParameters,
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 6);
+
+ let m = pop_arg!(args, Vec);
+ let e = pop_arg!(args, Vec);
+ let b = pop_arg!(args, Vec);
+ let m_size = pop_arg!(args, Vec);
+ let e_size = pop_arg!(args, Vec);
+ let b_size = pop_arg!(args, Vec);
+
+ let cost = gas_params.base
+ + (gas_params.per_byte
+ * NumBytes::new(
+ m.len() as u64
+ + e.len() as u64
+ + b.len() as u64
+ + m_size.len() as u64
+ + e_size.len() as u64
+ + b_size.len() as u64,
+ ));
+
+ let mut data: Vec = Vec::new();
+ data.extend(b_size);
+ data.extend(e_size);
+ data.extend(m_size);
+ data.extend(b);
+ data.extend(e);
+ data.extend(m);
+
+ match modexp::byzantium_run(&data.into(), 100_000_000_000) {
+ Ok((_, output)) => Ok(NativeResult::ok(
+ cost,
+ smallvec![Value::vector_u8(output.to_vec())],
+ )),
+
+ Err(_) => Ok(NativeResult::err(cost, E_MODEXP_FAILED)),
+ }
+}
+
+/***************************************************************************************************
+ * native function `ec_add(x1: vector, y1: vector, x2: vector, y2: vector): (vector, vector)`
**************************************************************************************************/
pub fn native_ec_add(
gas_params: &FromBytesGasParameters,
@@ -38,7 +126,7 @@ pub fn native_ec_add(
let x1 = pop_arg!(args, Vec);
if y2.len() != 32 || x2.len() != 32 || y1.len() != 32 || x1.len() != 32 {
- return Ok(NativeResult::err(0.into(), E_INVALID_COORDINATE));
+ return Ok(NativeResult::err(0.into(), E_INVALID_INPUT_SIZE));
}
let cost = gas_params.base + (gas_params.per_byte * NumBytes::new(128_u64));
@@ -62,11 +150,46 @@ pub fn native_ec_add(
}
/***************************************************************************************************
- * native fun ec_pairing
- * Implementation of the Move native function `ec_pairing(data: vector): vector`
- * gas cost: ec_pairing_cost_base | base cost for function call and fixed opers
- * + ec_pairing_data_cost_per_byte * msg.len() | cost depends on length of message
- * + ec_pairing_data_cost_per_block * num_blocks | cost depends on number of blocks in message
+ * native function `ec_mul(x1: vector, y1: vector, s: vector): (vector, vector)`
+ **************************************************************************************************/
+pub fn native_ec_mul(
+ gas_params: &FromBytesGasParameters,
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 3);
+
+ let s = pop_arg!(args, Vec);
+ let y1 = pop_arg!(args, Vec);
+ let x1 = pop_arg!(args, Vec);
+
+ if s.len() != 32 || y1.len() != 32 || x1.len() != 32 {
+ return Ok(NativeResult::err(0.into(), E_INVALID_INPUT_SIZE));
+ }
+
+ let cost = gas_params.base + (gas_params.per_byte * NumBytes::new(96_u64));
+
+ let mut data: Vec = Vec::new();
+ data.extend(x1);
+ data.extend(y1);
+ data.extend(s);
+
+ match bn128::run_mul(&data, 0, 10) {
+ Ok((_, mul)) => {
+ let (mul_x, mul_y) = mul.split_at(32);
+ let mul_x = Value::vector_u8(mul_x.to_vec());
+ let mul_y = Value::vector_u8(mul_y.to_vec());
+ Ok(NativeResult::ok(cost, smallvec![mul_x, mul_y]))
+ }
+
+ Err(_) => Ok(NativeResult::err(cost, E_EC_MUL_FAILED)),
+ }
+}
+
+/***************************************************************************************************
+ * native function `ec_pairing(data: vector): vector`
**************************************************************************************************/
pub fn native_ec_pairing(
gas_params: &FromBytesGasParameters,
@@ -90,6 +213,95 @@ pub fn native_ec_pairing(
}
}
+/***************************************************************************************************
+ * native function `blake2f(rounds: vector, h: vector, m: vector, t: vector, f: vector): vector`
+ **************************************************************************************************/
+pub fn native_blake2f(
+ gas_params: &FromBytesGasParameters,
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 5);
+
+ let f = pop_arg!(args, Vec);
+ let t = pop_arg!(args, Vec);
+ let m = pop_arg!(args, Vec);
+ let h = pop_arg!(args, Vec);
+ let rounds = pop_arg!(args, Vec);
+
+ if rounds.len() != 4 || h.len() != 64 || m.len() != 128 || t.len() != 16 || f.len() != 1 {
+ return Ok(NativeResult::err(0.into(), E_INVALID_INPUT_SIZE));
+ }
+
+ let cost = gas_params.base + (gas_params.per_byte * NumBytes::new(213_u64));
+
+ let mut data: Vec = Vec::new();
+ data.extend(rounds);
+ data.extend(h);
+ data.extend(m);
+ data.extend(t);
+ data.extend(f);
+
+ match blake2::run(&data.into(), 100_000_000_000) {
+ Ok((_, out)) => Ok(NativeResult::ok(
+ cost,
+ smallvec![Value::vector_u8(out.to_vec())],
+ )),
+ Err(_) => Ok(NativeResult::err(cost, E_EC_PAIRING_FAILED)),
+ }
+}
+
+/***************************************************************************************************
+ * native function `point_evaluation(versioned_hash: vector, x: vector, y: vector, commitment: vector, proof: vector): (vector, vector)`
+ **************************************************************************************************/
+pub fn native_point_evaluation(
+ gas_params: &FromBytesGasParameters,
+ _context: &mut NativeContext,
+ ty_args: Vec,
+ mut args: VecDeque,
+) -> PartialVMResult {
+ debug_assert!(ty_args.is_empty());
+ debug_assert!(args.len() == 5);
+
+ let proof = pop_arg!(args, Vec);
+ let commitment = pop_arg!(args, Vec);
+ let y = pop_arg!(args, Vec);
+ let x = pop_arg!(args, Vec);
+ let versioned_hash = pop_arg!(args, Vec);
+
+ if versioned_hash.len() != 32
+ || x.len() != 32
+ || y.len() != 32
+ || commitment.len() != 48
+ || proof.len() != 48
+ {
+ return Ok(NativeResult::err(0.into(), E_INVALID_INPUT_SIZE));
+ }
+
+ let cost = gas_params.base + (gas_params.per_byte * NumBytes::new(192_u64));
+
+ let mut data: Vec = Vec::new();
+ data.extend(versioned_hash);
+ data.extend(x);
+ data.extend(y);
+ data.extend(commitment);
+ data.extend(proof);
+ let env = Env::default();
+
+ match kzg_point_evaluation::run(&data.into(), 100_000_000_000, &env) {
+ Ok((_, output)) => {
+ let (output_f, output_b) = output.split_at(32);
+ let output_f = Value::vector_u8(output_f.to_vec());
+ let output_b = Value::vector_u8(output_b.to_vec());
+ Ok(NativeResult::ok(cost, smallvec![output_f, output_b]))
+ }
+
+ Err(_) => Ok(NativeResult::err(cost, E_POINT_EVALUATION_FAILED)),
+ }
+}
+
#[derive(Debug, Clone)]
pub struct FromBytesGasParameters {
pub base: InternalGas,
@@ -111,26 +323,47 @@ impl FromBytesGasParameters {
#[derive(Debug, Clone)]
pub struct GasParameters {
+ pub modexp: FromBytesGasParameters,
+ pub ec_recover: FromBytesGasParameters,
pub ec_add: FromBytesGasParameters,
+ pub ec_mul: FromBytesGasParameters,
pub ec_pairing: FromBytesGasParameters,
+ pub blake2f: FromBytesGasParameters,
+ pub point_evaluation: FromBytesGasParameters,
}
impl GasParameters {
pub fn zeros() -> Self {
Self {
+ modexp: FromBytesGasParameters::zeros(),
+ ec_recover: FromBytesGasParameters::zeros(),
ec_add: FromBytesGasParameters::zeros(),
+ ec_mul: FromBytesGasParameters::zeros(),
ec_pairing: FromBytesGasParameters::zeros(),
+ blake2f: FromBytesGasParameters::zeros(),
+ point_evaluation: FromBytesGasParameters::zeros(),
}
}
}
pub fn make_all(gas_params: GasParameters) -> impl Iterator- {
let natives = [
+ ("modexp", make_native(gas_params.modexp, native_modexp)),
+ (
+ "ec_recover",
+ make_native(gas_params.ec_recover, native_ec_recover),
+ ),
("ec_add", make_native(gas_params.ec_add, native_ec_add)),
+ ("ec_mul", make_native(gas_params.ec_mul, native_ec_mul)),
(
"ec_pairing",
make_native(gas_params.ec_pairing, native_ec_pairing),
),
+ ("blake2f", make_native(gas_params.blake2f, native_blake2f)),
+ (
+ "point_evaluation",
+ make_native(gas_params.point_evaluation, native_point_evaluation),
+ ),
];
make_module_natives(natives)
diff --git a/frameworks/rooch-framework/src/natives/gas_parameter/evm.rs b/frameworks/rooch-framework/src/natives/gas_parameter/evm.rs
index a68482193b..253fcdc6af 100644
--- a/frameworks/rooch-framework/src/natives/gas_parameter/evm.rs
+++ b/frameworks/rooch-framework/src/natives/gas_parameter/evm.rs
@@ -5,8 +5,18 @@ use crate::natives::gas_parameter::native::MUL;
use moveos_stdlib::natives::moveos_stdlib::evm::GasParameters;
crate::natives::gas_parameter::native::define_gas_parameters_for_natives!(GasParameters, "evm", [
+ [.modexp.base, "modexp.base", 1000 * MUL],
+ [.modexp.per_byte, "modexp.per_byte", 30 * MUL],
+ [.ec_recover.base, "ec_recover.base", 1000 * MUL],
+ [.ec_recover.per_byte, "ec_recover.per_byte", 30 * MUL],
[.ec_add.base, "ec_add.base", 1000 * MUL],
[.ec_add.per_byte, "ec_add.per_byte", 30 * MUL],
+ [.ec_mul.base, "ec_mul.base", 1000 * MUL],
+ [.ec_mul.per_byte, "ec_mul.per_byte", 30 * MUL],
[.ec_pairing.base, "ec_pairing.base", 1000 * MUL],
[.ec_pairing.per_byte, "ec_pairing.per_byte", 30 * MUL],
+ [.blake2f.base, "blake2f.base", 1000 * MUL],
+ [.blake2f.per_byte, "blake2f.per_byte", 30 * MUL],
+ [.point_evaluation.base, "point_evaluation.base", 1000 * MUL],
+ [.point_evaluation.per_byte, "point_evaluation.per_byte", 30 * MUL],
]);