From 7dff269a519488060848f19feff388b58e3d6e29 Mon Sep 17 00:00:00 2001 From: Alex Kladov Date: Mon, 31 Oct 2022 11:42:09 +0000 Subject: [PATCH] refactor: cleanup ed25519_verify (#7955) * Align doc comment with other host functions (not that we are super-consistent here) * Align code style with other host functions * Reduce some duplication from tests * Add tricky test-cases where a value of the wrong length is read from the register. https://github.com/near/nearcore/issues/7567 --- runtime/near-vm-logic/src/logic.rs | 100 ++-- .../near-vm-logic/src/tests/ed25519_verify.rs | 554 ++++++++++-------- 2 files changed, 361 insertions(+), 293 deletions(-) diff --git a/runtime/near-vm-logic/src/logic.rs b/runtime/near-vm-logic/src/logic.rs index 53bce2b9b26..f6438e40a41 100644 --- a/runtime/near-vm-logic/src/logic.rs +++ b/runtime/near-vm-logic/src/logic.rs @@ -1122,71 +1122,75 @@ impl<'a> VMLogic<'a> { } /// Verify an ED25519 signature given a message and a public key. - /// # Returns - /// - 1 meaning the boolean expression true to encode that the signature was properly verified - /// - 0 meaning the boolean expression false to encode that the signature failed to be verified /// - /// # Cost + /// Returns a bool indicating success (1) or failure (0) as a `u64`. + /// + /// # Errors /// - /// Each input can either be in memory or in a register. Set the length of the input to `u64::MAX` - /// to declare that the input is a register number and not a pointer. - /// Each input has a gas cost input_cost(num_bytes) that depends on whether it is from memory - /// or from a register. It is either read_memory_base + num_bytes * read_memory_byte in the - /// former case or read_register_base + num_bytes * read_register_byte in the latter. This function - /// is labeled as `input_cost` below. + /// * If the public key's size is not equal to 32, or signature size is not + /// equal to 64, returns [HostError::Ed25519VerifyInvalidInput]. + /// * If any of the signature, message or public key arguments are out of + /// memory bounds, returns [`HostError::MemoryAccessViolation`] /// - /// `input_cost(num_bytes_signature) + input_cost(num_bytes_message) + input_cost(num_bytes_public_key) + - /// ed25519_verify_base + ed25519_verify_byte * num_bytes_message` + /// # Cost /// - /// # Error + /// Each input can either be in memory or in a register. Set the length of + /// the input to `u64::MAX` to declare that the input is a register number + /// and not a pointer. Each input has a gas cost input_cost(num_bytes) that + /// depends on whether it is from memory or from a register. It is either + /// read_memory_base + num_bytes * read_memory_byte in the former case or + /// read_register_base + num_bytes * read_register_byte in the latter. This + /// function is labeled as `input_cost` below. /// - /// If the public key's size is not equal to 32 returns [HostError::Ed25519VerifyInvalidInput]. - /// If the signature size is not equal to 64 returns [HostError::Ed25519VerifyInvalidInput]. - + /// `input_cost(num_bytes_signature) + input_cost(num_bytes_message) + + /// input_cost(num_bytes_public_key) + ed25519_verify_base + + /// ed25519_verify_byte * num_bytes_message` #[cfg(feature = "protocol_feature_ed25519_verify")] pub fn ed25519_verify( &mut self, - sig_len: u64, - sig_ptr: u64, - msg_len: u64, - msg_ptr: u64, - pub_key_len: u64, - pub_key_ptr: u64, + signature_len: u64, + signature_ptr: u64, + message_len: u64, + message_ptr: u64, + public_key_len: u64, + public_key_ptr: u64, ) -> Result { - use ed25519_dalek::{PublicKey, Signature, Verifier, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH}; + use ed25519_dalek::Verifier; self.gas_counter.pay_base(ed25519_verify_base)?; - let signature_array = self.get_vec_from_memory_or_register(sig_ptr, sig_len)?; - if signature_array.len() != SIGNATURE_LENGTH { - return Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput { - msg: "invalid signature length".to_string(), - })); - } - - let signature = match Signature::from_bytes(&signature_array) { - Ok(signature) => signature, - Err(_) => return Ok(0), + let signature: ed25519_dalek::Signature = { + let vec = self.get_vec_from_memory_or_register(signature_ptr, signature_len)?; + if vec.len() != ed25519_dalek::SIGNATURE_LENGTH { + return Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput { + msg: "invalid signature length".to_string(), + })); + } + match ed25519_dalek::Signature::from_bytes(&vec) { + Ok(signature) => signature, + Err(_) => return Ok(false as u64), + } }; - let msg = self.get_vec_from_memory_or_register(msg_ptr, msg_len)?; - let num_bytes = msg.len(); - self.gas_counter.pay_per(ed25519_verify_byte, num_bytes as _)?; + let message = self.get_vec_from_memory_or_register(message_ptr, message_len)?; + self.gas_counter.pay_per(ed25519_verify_byte, message.len() as u64)?; - let pub_key_array = self.get_vec_from_memory_or_register(pub_key_ptr, pub_key_len)?; - if pub_key_array.len() != PUBLIC_KEY_LENGTH { - return Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput { - msg: "invalid public key length".to_string(), - })); - } - let pub_key = match PublicKey::from_bytes(&pub_key_array) { - Ok(pub_key) => pub_key, - Err(_) => return Ok(0), + let public_key: ed25519_dalek::PublicKey = { + let vec = self.get_vec_from_memory_or_register(public_key_ptr, public_key_len)?; + if vec.len() != ed25519_dalek::PUBLIC_KEY_LENGTH { + return Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput { + msg: "invalid public key length".to_string(), + })); + } + match ed25519_dalek::PublicKey::from_bytes(&vec) { + Ok(public_key) => public_key, + Err(_) => return Ok(false as u64), + } }; - match pub_key.verify(&msg, &signature) { - Err(_) => Ok(0), - Ok(()) => Ok(1), + match public_key.verify(&message, &signature) { + Err(_) => Ok(false as u64), + Ok(()) => Ok(true as u64), } } diff --git a/runtime/near-vm-logic/src/tests/ed25519_verify.rs b/runtime/near-vm-logic/src/tests/ed25519_verify.rs index edc04d02fd3..cb563ab08f1 100644 --- a/runtime/near-vm-logic/src/tests/ed25519_verify.rs +++ b/runtime/near-vm-logic/src/tests/ed25519_verify.rs @@ -1,288 +1,352 @@ use crate::tests::fixtures::get_context; use crate::tests::helpers::*; use crate::tests::vm_logic_builder::VMLogicBuilder; -use crate::VMLogic; use crate::{map, ExtCosts}; use near_vm_errors::HostError; use near_vm_errors::VMLogicError; - use std::collections::HashMap; -fn create_signature() -> [u8; 64] { - [ - 145, 193, 203, 18, 114, 227, 14, 117, 33, 213, 121, 66, 130, 14, 25, 4, 36, 120, 46, 142, - 226, 215, 7, 66, 122, 112, 97, 30, 249, 135, 61, 165, 221, 249, 252, 23, 105, 40, 56, 70, - 31, 152, 236, 141, 154, 122, 207, 20, 75, 118, 79, 90, 168, 6, 221, 122, 213, 29, 126, 196, - 216, 104, 191, 6, - ] -} +const SIGNATURE: [u8; 64] = [ + 145, 193, 203, 18, 114, 227, 14, 117, 33, 213, 121, 66, 130, 14, 25, 4, 36, 120, 46, 142, 226, + 215, 7, 66, 122, 112, 97, 30, 249, 135, 61, 165, 221, 249, 252, 23, 105, 40, 56, 70, 31, 152, + 236, 141, 154, 122, 207, 20, 75, 118, 79, 90, 168, 6, 221, 122, 213, 29, 126, 196, 216, 104, + 191, 6, +]; -fn create_public_key() -> [u8; 32] { - [ - 32, 122, 6, 120, 146, 130, 30, 37, 215, 112, 241, 251, 160, 196, 124, 17, 255, 75, 129, 62, - 84, 22, 46, 206, 158, 184, 57, 224, 118, 35, 26, 182, - ] -} +const BAD_SIGNATURE: [u8; 64] = [1; 64]; + +// create a forged signature with the `s` scalar not properly reduced +// https://docs.rs/ed25519/latest/src/ed25519/lib.rs.html#302 +const FORGED_SIGNATURE: [u8; 64] = { + let mut sig = SIGNATURE; + sig[63] = 0b1110_0001; + sig +}; + +const PUBLIC_KEY: [u8; 32] = [ + 32, 122, 6, 120, 146, 130, 30, 37, 215, 112, 241, 251, 160, 196, 124, 17, 255, 75, 129, 62, 84, + 22, 46, 206, 158, 184, 57, 224, 118, 35, 26, 182, +]; + +// create a forged public key to force a PointDecompressionError +// https://docs.rs/ed25519-dalek/latest/src/ed25519_dalek/public.rs.html#142 +const FORGED_PUBLIC_KEY: [u8; 32] = { + let mut key = PUBLIC_KEY; + key[31] = 0b1110_0001; + key +}; + +// 32 bytes message +const MESSAGE: [u8; 32] = [ + 107, 97, 106, 100, 108, 102, 107, 106, 97, 108, 107, 102, 106, 97, 107, 108, 102, 106, 100, + 107, 108, 97, 100, 106, 102, 107, 108, 106, 97, 100, 115, 107, +]; #[track_caller] fn check_ed25519_verify( - logic: &mut VMLogic, - signature_len: usize, + signature_len: u64, signature: &[u8], - message_len: usize, + message_len: u64, message: &[u8], - public_key_len: usize, + public_key_len: u64, public_key: &[u8], - want: Result, + want: Result, want_costs: HashMap, ) { - let result = logic.ed25519_verify( - signature_len as _, - signature.as_ptr() as _, - message_len as _, - message.as_ptr() as _, - public_key_len as _, - public_key.as_ptr() as _, - ); - - assert_eq!(want, result); - assert_costs(want_costs); -} - -#[test] -fn test_ed25519_verify_behavior_and_errors() { let mut logic_builder = VMLogicBuilder::default(); let mut logic = logic_builder.build(get_context(vec![], false)); - let signature = create_signature(); - let bad_signature: [u8; 64] = [1; 64]; - - let mut forged_signature = signature.clone(); - // create a forged signature with the `s` scalar not properly reduced - // https://docs.rs/ed25519/latest/src/ed25519/lib.rs.html#302 - forged_signature[63] = 0b1110_0001; - - let public_key = create_public_key(); - - let mut forged_public_key = public_key.clone(); - // create a forged public key to force a PointDecompressionError - // https://docs.rs/ed25519-dalek/latest/src/ed25519_dalek/public.rs.html#142 - forged_public_key[31] = 0b1110_0001; + let signature_ptr = if signature_len == u64::MAX { + logic.wrapped_internal_write_register(1, &signature).unwrap(); + 1 + } else { + signature.as_ptr() as u64 + }; - // 32 bytes message - let message: [u8; 32] = [ - 107, 97, 106, 100, 108, 102, 107, 106, 97, 108, 107, 102, 106, 97, 107, 108, 102, 106, 100, - 107, 108, 97, 100, 106, 102, 107, 108, 106, 97, 100, 115, 107, - ]; + let message_ptr = if message_len == u64::MAX { + logic.wrapped_internal_write_register(2, &message).unwrap(); + 2 + } else { + message.as_ptr() as u64 + }; - let scenarios = [ - ( - signature.len(), - signature.clone(), - message.len(), - message.as_slice(), - public_key.len(), - public_key.clone(), - Ok(1), - map! { - ExtCosts::read_memory_byte: 128, - ExtCosts::read_memory_base: 3, - ExtCosts::ed25519_verify_base: 1, - ExtCosts::ed25519_verify_byte: 32, - }, - ), - ( - signature.len(), - signature.clone(), - message.len(), - message.as_slice(), - public_key.len(), - forged_public_key.clone(), - Ok(0), - map! { - ExtCosts::read_memory_byte: 128, - ExtCosts::read_memory_base: 3, - ExtCosts::ed25519_verify_base: 1, - ExtCosts::ed25519_verify_byte: 32, - }, - ), - ( - signature.len(), - signature.clone(), - message.len(), - message.as_slice(), - public_key.len() - 1, - public_key.clone(), - Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput { - msg: "invalid public key length".to_string(), - })), - map! { - ExtCosts::read_memory_byte: 127, - ExtCosts::read_memory_base: 3, - ExtCosts::ed25519_verify_base: 1, - ExtCosts::ed25519_verify_byte: 32, - }, - ), - ( - bad_signature.len(), - bad_signature.clone(), - message.len(), - message.as_slice(), - public_key.len(), - public_key.clone(), - Ok(0), - map! { - ExtCosts::read_memory_byte: 128, - ExtCosts::read_memory_base: 3, - ExtCosts::ed25519_verify_base: 1, - ExtCosts::ed25519_verify_byte: 32, - }, - ), - ( - signature.len() - 1, - signature.clone(), - message.len(), - message.as_slice(), - public_key.len(), - public_key.clone(), - Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput { - msg: "invalid signature length".to_string(), - })), - map! { - ExtCosts::read_memory_base: 1, - ExtCosts::read_memory_byte: 63, - ExtCosts::ed25519_verify_base: 1, - }, - ), - ( - forged_signature.len(), - forged_signature.clone(), - message.len(), - message.as_slice(), - public_key.len(), - public_key.clone(), - Ok(0), - map! { - ExtCosts::read_memory_base: 1, - ExtCosts::read_memory_byte: 64, - ExtCosts::ed25519_verify_base: 1, - }, - ), - ( - forged_signature.len(), - forged_signature.clone(), - 0, - message.as_slice(), - public_key.len(), - public_key.clone(), - Ok(0), - map! { - ExtCosts::read_memory_base: 1, - ExtCosts::read_memory_byte: 64, - ExtCosts::ed25519_verify_base: 1, - }, - ), - ]; + let public_key_ptr = if public_key_len == u64::MAX { + logic.wrapped_internal_write_register(3, &public_key).unwrap(); + 3 + } else { + public_key.as_ptr() as u64 + }; - for ( + let result = logic.ed25519_verify( signature_len, - signature, + signature_ptr, message_len, - message, + message_ptr, public_key_len, - public_key, - expected_result, - want_costs, - ) in scenarios - { - check_ed25519_verify( - &mut logic, - signature_len as _, - signature.as_ref(), - message_len as _, - message.as_ref(), - public_key_len as _, - public_key.as_ref(), - expected_result, - want_costs, - ); - } + public_key_ptr, + ); + + let want = want.map_err(VMLogicError::HostError); + assert_eq!(want, result); + assert_costs(want_costs); } #[test] -fn test_ed25519_verify_check_registers() { - let mut logic_builder = VMLogicBuilder::default(); - let mut logic = logic_builder.build(get_context(vec![], false)); - - let signature = create_signature(); - let public_key = create_public_key(); - - let bad_signature: [u8; 64] = [1; 64]; - - // 32 bytes message - let message: [u8; 32] = [ - 107, 97, 106, 100, 108, 102, 107, 106, 97, 108, 107, 102, 106, 97, 107, 108, 102, 106, 100, - 107, 108, 97, 100, 106, 102, 107, 108, 106, 97, 100, 115, 107, - ]; - - let mut forged_signature = signature.clone(); - // create a forged signature with the `s` scalar not properly reduced - // https://docs.rs/ed25519/latest/src/ed25519/lib.rs.html#302 - forged_signature[63] = 0b1110_0001; - - // tests for data beingn read from registers - logic.wrapped_internal_write_register(1, &signature).unwrap(); - let result = logic.ed25519_verify( - u64::MAX, - 1 as _, - message.len() as _, - message.as_ptr() as _, - public_key.len() as _, - public_key.as_ptr() as _, +fn test_ed25519_verify_behavior_and_errors() { + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(1), + map! { + ExtCosts::read_memory_byte: 128, + ExtCosts::read_memory_base: 3, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, + ); + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &FORGED_PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::read_memory_byte: 128, + ExtCosts::read_memory_base: 3, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, + ); + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64 - 1, + &PUBLIC_KEY, + Err(HostError::Ed25519VerifyInvalidInput { msg: "invalid public key length".to_string() }), + map! { + ExtCosts::read_memory_byte: 127, + ExtCosts::read_memory_base: 3, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, + ); + check_ed25519_verify( + BAD_SIGNATURE.len() as u64, + &BAD_SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::read_memory_byte: 128, + ExtCosts::read_memory_base: 3, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, ); - assert_eq!(Ok(1u64), result); + check_ed25519_verify( + SIGNATURE.len() as u64 - 1, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Err(HostError::Ed25519VerifyInvalidInput { msg: "invalid signature length".to_string() }), + map! { + ExtCosts::read_memory_base: 1, + ExtCosts::read_memory_byte: 63, + ExtCosts::ed25519_verify_base: 1, + }, + ); + check_ed25519_verify( + FORGED_SIGNATURE.len() as u64, + &FORGED_SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::read_memory_base: 1, + ExtCosts::read_memory_byte: 64, + ExtCosts::ed25519_verify_base: 1, + }, + ); + check_ed25519_verify( + FORGED_SIGNATURE.len() as u64, + &FORGED_SIGNATURE, + 0, + &[], + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::read_memory_base: 1, + ExtCosts::read_memory_byte: 64, + ExtCosts::ed25519_verify_base: 1, + }, + ); + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + 0, + &[], + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::read_memory_base: 3, + ExtCosts::read_memory_byte: 96, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 0, + }, + ); +} - logic.wrapped_internal_write_register(1, &bad_signature).unwrap(); - let result = logic.ed25519_verify( +// tests for data being read from registers +#[test] +fn test_ed25519_verify_check_registers() { + check_ed25519_verify( u64::MAX, - 1 as _, - message.len() as _, - message.as_ptr() as _, - public_key.len() as _, - public_key.as_ptr() as _, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(1), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 64, + + ExtCosts::read_register_base: 1, + ExtCosts::read_register_byte: 64, + ExtCosts::read_memory_base: 2, + ExtCosts::read_memory_byte: 64, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, ); - assert_eq!(Ok(0), result); + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + u64::MAX, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(1), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 32, - logic.wrapped_internal_write_register(1, &forged_signature).unwrap(); - let result = logic.ed25519_verify( + ExtCosts::read_register_base: 1, + ExtCosts::read_register_byte: 32, + ExtCosts::read_memory_base: 2, + ExtCosts::read_memory_byte: 96, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, + ); + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, u64::MAX, - 1 as _, - message.len() as _, - message.as_ptr() as _, - public_key.len() as _, - public_key.as_ptr() as _, + &PUBLIC_KEY, + Ok(1), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 32, + + ExtCosts::read_register_byte: 32, + ExtCosts::read_register_base: 1, + ExtCosts::read_memory_base: 2, + ExtCosts::read_memory_byte: 96, + ExtCosts::ed25519_verify_base: 1, + ExtCosts::ed25519_verify_byte: 32, + }, ); - assert_eq!(Ok(0), result); + check_ed25519_verify( + u64::MAX, + &BAD_SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 64, - logic.wrapped_internal_write_register(1, &message).unwrap(); - let result = logic.ed25519_verify( - signature.len() as _, - signature.as_ptr() as _, + ExtCosts::read_register_base: 1, + ExtCosts::read_register_byte: 64, + ExtCosts::read_memory_base: 2, + ExtCosts::read_memory_byte: 64, + ExtCosts::ed25519_verify_byte: 32, + ExtCosts::ed25519_verify_base: 1, + }, + ); + check_ed25519_verify( u64::MAX, - 1, - public_key.len() as _, - public_key.as_ptr() as _, + &FORGED_SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Ok(0), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 64, + + ExtCosts::read_register_base: 1, + ExtCosts::read_register_byte: 64, + ExtCosts::ed25519_verify_base: 1, + }, ); - assert_eq!(Ok(1), result); + check_ed25519_verify( + u64::MAX, + &[0], + MESSAGE.len() as u64, + &MESSAGE, + PUBLIC_KEY.len() as u64, + &PUBLIC_KEY, + Err(HostError::Ed25519VerifyInvalidInput { msg: "invalid signature length".to_string() }), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 1, - logic.wrapped_internal_write_register(1, &public_key).unwrap(); - let result = logic.ed25519_verify( - signature.len() as _, - signature.as_ptr() as _, - message.len() as _, - message.as_ptr() as _, + ExtCosts::read_register_base: 1, + ExtCosts::read_register_byte: 1, + ExtCosts::ed25519_verify_base: 1, + }, + ); + check_ed25519_verify( + SIGNATURE.len() as u64, + &SIGNATURE, + MESSAGE.len() as u64, + &MESSAGE, u64::MAX, - 1, + &[0], + Err(HostError::Ed25519VerifyInvalidInput { msg: "invalid public key length".to_string() }), + map! { + ExtCosts::write_register_base: 1, + ExtCosts::write_register_byte: 1, + + ExtCosts::read_register_base: 1, + ExtCosts::read_register_byte: 1, + ExtCosts::read_memory_base: 2, + ExtCosts::read_memory_byte: 96, + ExtCosts::ed25519_verify_byte: 32, + ExtCosts::ed25519_verify_base: 1, + }, ); - assert_eq!(Ok(1), result); }