use std::convert::TryInto;
use std::mem::{size_of, size_of_val};
use std::panic as std_panic;
use std::{convert::TryFrom, mem::MaybeUninit};
#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
use crate::mock::MockedBlockchain;
use crate::promise::Allowance;
use crate::types::{
AccountId, BlockHeight, Gas, NearToken, PromiseIndex, PromiseResult, PublicKey, StorageUsage,
};
use crate::{GasWeight, PromiseError};
use near_sys as sys;
const REGISTER_EXPECTED_ERR: &str =
"Register was expected to have data because we just wrote it into it.";
const ATOMIC_OP_REGISTER: u64 = std::u64::MAX - 2;
const EVICTED_REGISTER: u64 = std::u64::MAX - 1;
const STATE_KEY: &[u8] = b"STATE";
const MIN_ACCOUNT_ID_LEN: u64 = 2;
const MAX_ACCOUNT_ID_LEN: u64 = 64;
fn expect_register<T>(option: Option<T>) -> T {
option.unwrap_or_else(|| panic_str(REGISTER_EXPECTED_ERR))
}
macro_rules! try_method_into_register {
( $method:ident ) => {{
unsafe { sys::$method(ATOMIC_OP_REGISTER) };
read_register(ATOMIC_OP_REGISTER)
}};
}
macro_rules! method_into_register {
( $method:ident ) => {{
expect_register(try_method_into_register!($method))
}};
}
pub(crate) unsafe fn read_register_fixed_20(register_id: u64) -> [u8; 20] {
let mut hash = [MaybeUninit::<u8>::uninit(); 20];
sys::read_register(register_id, hash.as_mut_ptr() as _);
std::mem::transmute(hash)
}
pub(crate) unsafe fn read_register_fixed_32(register_id: u64) -> [u8; 32] {
let mut hash = [MaybeUninit::<u8>::uninit(); 32];
sys::read_register(register_id, hash.as_mut_ptr() as _);
std::mem::transmute(hash)
}
pub(crate) unsafe fn read_register_fixed_64(register_id: u64) -> [u8; 64] {
let mut hash = [MaybeUninit::<u8>::uninit(); 64];
sys::read_register(register_id, hash.as_mut_ptr() as _);
std::mem::transmute(hash)
}
#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
pub fn set_blockchain_interface(blockchain_interface: MockedBlockchain) {
crate::mock::with_mocked_blockchain(|b| {
*b = blockchain_interface;
})
}
fn panic_hook_impl(info: &std_panic::PanicInfo) {
panic_str(info.to_string().as_str());
}
pub fn setup_panic_hook() {
std_panic::set_hook(Box::new(panic_hook_impl));
}
pub fn read_register(register_id: u64) -> Option<Vec<u8>> {
let len: usize = register_len(register_id)?.try_into().unwrap_or_else(|_| abort());
let mut buffer = Vec::with_capacity(len);
unsafe {
sys::read_register(register_id, buffer.as_mut_ptr() as u64);
buffer.set_len(len);
}
Some(buffer)
}
pub fn register_len(register_id: u64) -> Option<u64> {
let len = unsafe { sys::register_len(register_id) };
if len == std::u64::MAX {
None
} else {
Some(len)
}
}
pub fn current_account_id() -> AccountId {
assert_valid_account_id(method_into_register!(current_account_id))
}
pub fn signer_account_id() -> AccountId {
assert_valid_account_id(method_into_register!(signer_account_id))
}
pub fn signer_account_pk() -> PublicKey {
PublicKey::try_from(method_into_register!(signer_account_pk)).unwrap_or_else(|_| abort())
}
pub fn predecessor_account_id() -> AccountId {
assert_valid_account_id(method_into_register!(predecessor_account_id))
}
fn assert_valid_account_id(bytes: Vec<u8>) -> AccountId {
String::from_utf8(bytes)
.ok()
.and_then(|s| AccountId::try_from(s).ok())
.unwrap_or_else(|| abort())
}
pub fn input() -> Option<Vec<u8>> {
try_method_into_register!(input)
}
#[deprecated(since = "4.0.0", note = "Use block_height instead")]
pub fn block_index() -> BlockHeight {
block_height()
}
pub fn block_height() -> BlockHeight {
unsafe { sys::block_height() }
}
pub fn block_timestamp() -> u64 {
unsafe { sys::block_timestamp() }
}
pub fn block_timestamp_ms() -> u64 {
block_timestamp() / 1_000_000
}
pub fn epoch_height() -> u64 {
unsafe { sys::epoch_height() }
}
pub fn storage_usage() -> StorageUsage {
unsafe { sys::storage_usage() }
}
pub fn account_balance() -> NearToken {
let data = [0u8; size_of::<NearToken>()];
unsafe { sys::account_balance(data.as_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
pub fn account_locked_balance() -> NearToken {
let data = [0u8; size_of::<NearToken>()];
unsafe { sys::account_locked_balance(data.as_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
pub fn attached_deposit() -> NearToken {
let data = [0u8; size_of::<NearToken>()];
unsafe { sys::attached_deposit(data.as_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
pub fn prepaid_gas() -> Gas {
Gas::from_gas(unsafe { sys::prepaid_gas() })
}
pub fn used_gas() -> Gas {
Gas::from_gas(unsafe { sys::used_gas() })
}
pub fn random_seed() -> Vec<u8> {
random_seed_array().to_vec()
}
pub fn random_seed_array() -> [u8; 32] {
unsafe {
sys::random_seed(ATOMIC_OP_REGISTER);
read_register_fixed_32(ATOMIC_OP_REGISTER)
}
}
pub fn sha256(value: &[u8]) -> Vec<u8> {
sha256_array(value).to_vec()
}
pub fn keccak256(value: &[u8]) -> Vec<u8> {
keccak256_array(value).to_vec()
}
pub fn keccak512(value: &[u8]) -> Vec<u8> {
keccak512_array(value).to_vec()
}
pub fn sha256_array(value: &[u8]) -> [u8; 32] {
unsafe {
sys::sha256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed_32(ATOMIC_OP_REGISTER)
}
}
pub fn keccak256_array(value: &[u8]) -> [u8; 32] {
unsafe {
sys::keccak256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed_32(ATOMIC_OP_REGISTER)
}
}
pub fn keccak512_array(value: &[u8]) -> [u8; 64] {
unsafe {
sys::keccak512(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed_64(ATOMIC_OP_REGISTER)
}
}
pub fn ripemd160_array(value: &[u8]) -> [u8; 20] {
unsafe {
sys::ripemd160(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed_20(ATOMIC_OP_REGISTER)
}
}
#[cfg(feature = "unstable")]
pub fn ecrecover(
hash: &[u8],
signature: &[u8],
v: u8,
malleability_flag: bool,
) -> Option<[u8; 64]> {
unsafe {
let return_code = sys::ecrecover(
hash.len() as _,
hash.as_ptr() as _,
signature.len() as _,
signature.as_ptr() as _,
v as u64,
malleability_flag as u64,
ATOMIC_OP_REGISTER,
);
if return_code == 0 {
None
} else {
Some(read_register_fixed_64(ATOMIC_OP_REGISTER))
}
}
}
pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], public_key: &[u8; 32]) -> bool {
unsafe {
sys::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 _,
) == 1
}
}
pub fn alt_bn128_g1_multiexp(value: &[u8]) -> Vec<u8> {
unsafe {
sys::alt_bn128_g1_multiexp(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
read_register(ATOMIC_OP_REGISTER).expect(REGISTER_EXPECTED_ERR)
}
pub fn alt_bn128_g1_sum(value: &[u8]) -> Vec<u8> {
unsafe {
sys::alt_bn128_g1_sum(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
read_register(ATOMIC_OP_REGISTER).expect(REGISTER_EXPECTED_ERR)
}
pub fn alt_bn128_pairing_check(value: &[u8]) -> bool {
unsafe { sys::alt_bn128_pairing_check(value.len() as _, value.as_ptr() as _) == 1 }
}
pub fn promise_create(
account_id: AccountId,
function_name: &str,
arguments: &[u8],
amount: NearToken,
gas: Gas,
) -> PromiseIndex {
let account_id = account_id.as_bytes();
unsafe {
PromiseIndex(sys::promise_create(
account_id.len() as _,
account_id.as_ptr() as _,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
))
}
}
pub fn promise_then(
promise_idx: PromiseIndex,
account_id: AccountId,
function_name: &str,
arguments: &[u8],
amount: NearToken,
gas: Gas,
) -> PromiseIndex {
let account_id = account_id.as_bytes();
unsafe {
PromiseIndex(sys::promise_then(
promise_idx.0,
account_id.len() as _,
account_id.as_ptr() as _,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
))
}
}
pub fn promise_and(promise_indices: &[PromiseIndex]) -> PromiseIndex {
let mut data = vec![0u8; size_of_val(promise_indices)];
for i in 0..promise_indices.len() {
data[i * size_of::<PromiseIndex>()..(i + 1) * size_of::<PromiseIndex>()]
.copy_from_slice(&promise_indices[i].0.to_le_bytes());
}
unsafe { PromiseIndex(sys::promise_and(data.as_ptr() as _, promise_indices.len() as _)) }
}
pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex {
let account_id: &str = account_id.as_ref();
unsafe {
PromiseIndex(sys::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _))
}
}
pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) -> PromiseIndex {
let account_id: &str = account_id.as_ref();
unsafe {
PromiseIndex(sys::promise_batch_then(
promise_index.0,
account_id.len() as _,
account_id.as_ptr() as _,
))
}
}
pub fn promise_batch_action_create_account(promise_index: PromiseIndex) {
unsafe { sys::promise_batch_action_create_account(promise_index.0) }
}
pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: &[u8]) {
unsafe {
sys::promise_batch_action_deploy_contract(
promise_index.0,
code.len() as _,
code.as_ptr() as _,
)
}
}
pub fn promise_batch_action_function_call(
promise_index: PromiseIndex,
function_name: &str,
arguments: &[u8],
amount: NearToken,
gas: Gas,
) {
unsafe {
sys::promise_batch_action_function_call(
promise_index.0,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
)
}
}
pub fn promise_batch_action_function_call_weight(
promise_index: PromiseIndex,
function_name: &str,
arguments: &[u8],
amount: NearToken,
gas: Gas,
weight: GasWeight,
) {
unsafe {
sys::promise_batch_action_function_call_weight(
promise_index.0,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
weight.0,
)
}
}
pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: NearToken) {
unsafe {
sys::promise_batch_action_transfer(
promise_index.0,
&amount.as_yoctonear() as *const u128 as _,
)
}
}
pub fn promise_batch_action_stake(
promise_index: PromiseIndex,
amount: NearToken,
public_key: &PublicKey,
) {
unsafe {
sys::promise_batch_action_stake(
promise_index.0,
&amount.as_yoctonear() as *const u128 as _,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
)
}
}
pub fn promise_batch_action_add_key_with_full_access(
promise_index: PromiseIndex,
public_key: &PublicKey,
nonce: u64,
) {
unsafe {
sys::promise_batch_action_add_key_with_full_access(
promise_index.0,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
nonce,
)
}
}
pub(crate) fn migrate_to_allowance(allowance: NearToken) -> Allowance {
Allowance::limited(allowance).unwrap_or(Allowance::Unlimited)
}
#[deprecated(since = "5.0.0", note = "Use add_access_key_allowance instead")]
pub fn promise_batch_action_add_key_with_function_call(
promise_index: PromiseIndex,
public_key: &PublicKey,
nonce: u64,
allowance: NearToken,
receiver_id: &AccountId,
function_names: &str,
) {
let allowance = migrate_to_allowance(allowance);
promise_batch_action_add_key_allowance_with_function_call(
promise_index,
public_key,
nonce,
allowance,
receiver_id,
function_names,
)
}
pub fn promise_batch_action_add_key_allowance_with_function_call(
promise_index: PromiseIndex,
public_key: &PublicKey,
nonce: u64,
allowance: Allowance,
receiver_id: &AccountId,
function_names: &str,
) {
let receiver_id: &str = receiver_id.as_ref();
let allowance = match allowance {
Allowance::Limited(x) => x.get(),
Allowance::Unlimited => 0,
};
unsafe {
sys::promise_batch_action_add_key_with_function_call(
promise_index.0,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
nonce,
&allowance as *const u128 as _,
receiver_id.len() as _,
receiver_id.as_ptr() as _,
function_names.len() as _,
function_names.as_ptr() as _,
)
}
}
pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: &PublicKey) {
unsafe {
sys::promise_batch_action_delete_key(
promise_index.0,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
)
}
}
pub fn promise_batch_action_delete_account(
promise_index: PromiseIndex,
beneficiary_id: &AccountId,
) {
let beneficiary_id: &str = beneficiary_id.as_ref();
unsafe {
sys::promise_batch_action_delete_account(
promise_index.0,
beneficiary_id.len() as _,
beneficiary_id.as_ptr() as _,
)
}
}
pub fn promise_results_count() -> u64 {
unsafe { sys::promise_results_count() }
}
pub fn promise_result(result_idx: u64) -> PromiseResult {
match promise_result_internal(result_idx) {
Ok(()) => {
let data = expect_register(read_register(ATOMIC_OP_REGISTER));
PromiseResult::Successful(data)
}
Err(PromiseError::Failed) => PromiseResult::Failed,
}
}
pub(crate) fn promise_result_internal(result_idx: u64) -> Result<(), PromiseError> {
match unsafe { sys::promise_result(result_idx, ATOMIC_OP_REGISTER) } {
1 => Ok(()),
2 => Err(PromiseError::Failed),
_ => abort(),
}
}
pub fn promise_return(promise_idx: PromiseIndex) {
unsafe { sys::promise_return(promise_idx.0) }
}
pub fn validator_stake(account_id: &AccountId) -> NearToken {
let account_id: &str = account_id.as_ref();
let data = [0u8; size_of::<NearToken>()];
unsafe {
sys::validator_stake(account_id.len() as _, account_id.as_ptr() as _, data.as_ptr() as u64)
};
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
pub fn validator_total_stake() -> NearToken {
let data = [0u8; size_of::<NearToken>()];
unsafe { sys::validator_total_stake(data.as_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
pub fn value_return(value: &[u8]) {
unsafe { sys::value_return(value.len() as _, value.as_ptr() as _) }
}
#[deprecated(since = "4.0.0", note = "Use env::panic_str to panic with a message.")]
pub fn panic(message: &[u8]) -> ! {
unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) }
}
pub fn panic_str(message: &str) -> ! {
unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) }
}
pub fn abort() -> ! {
#[cfg(target_arch = "wasm32")]
#[allow(unused_unsafe)]
unsafe {
core::arch::wasm32::unreachable()
}
#[cfg(not(target_arch = "wasm32"))]
unsafe {
sys::panic()
}
}
pub fn log_str(message: &str) {
#[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
eprintln!("{}", message);
unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
}
#[deprecated(since = "4.0.0", note = "Use env::log_str for logging messages.")]
pub fn log(message: &[u8]) {
#[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
eprintln!("{}", String::from_utf8_lossy(message));
unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
}
pub fn storage_write(key: &[u8], value: &[u8]) -> bool {
match unsafe {
sys::storage_write(
key.len() as _,
key.as_ptr() as _,
value.len() as _,
value.as_ptr() as _,
EVICTED_REGISTER,
)
} {
0 => false,
1 => true,
_ => abort(),
}
}
pub fn storage_read(key: &[u8]) -> Option<Vec<u8>> {
match unsafe { sys::storage_read(key.len() as _, key.as_ptr() as _, ATOMIC_OP_REGISTER) } {
0 => None,
1 => Some(expect_register(read_register(ATOMIC_OP_REGISTER))),
_ => abort(),
}
}
pub fn storage_remove(key: &[u8]) -> bool {
match unsafe { sys::storage_remove(key.len() as _, key.as_ptr() as _, EVICTED_REGISTER) } {
0 => false,
1 => true,
_ => abort(),
}
}
pub fn storage_get_evicted() -> Option<Vec<u8>> {
read_register(EVICTED_REGISTER)
}
pub fn storage_has_key(key: &[u8]) -> bool {
match unsafe { sys::storage_has_key(key.len() as _, key.as_ptr() as _) } {
0 => false,
1 => true,
_ => abort(),
}
}
pub fn state_read<T: borsh::BorshDeserialize>() -> Option<T> {
storage_read(STATE_KEY)
.map(|data| T::try_from_slice(&data).expect("Cannot deserialize the contract state."))
}
pub fn state_write<T: borsh::BorshSerialize>(state: &T) {
let data = borsh::to_vec(state).expect("Cannot serialize the contract state.");
storage_write(STATE_KEY, &data);
}
pub fn state_exists() -> bool {
storage_has_key(STATE_KEY)
}
pub fn storage_byte_cost() -> NearToken {
NearToken::from_yoctonear(10_000_000_000_000_000_000u128)
}
pub fn is_valid_account_id(account_id: &[u8]) -> bool {
if (account_id.len() as u64) < MIN_ACCOUNT_ID_LEN
|| (account_id.len() as u64) > MAX_ACCOUNT_ID_LEN
{
return false;
}
let mut last_char_is_separator = true;
for c in account_id {
let current_char_is_separator = match *c {
b'a'..=b'z' | b'0'..=b'9' => false,
b'-' | b'_' | b'.' => true,
_ => return false,
};
if current_char_is_separator && last_char_is_separator {
return false;
}
last_char_is_separator = current_char_is_separator;
}
!last_char_is_separator
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_valid_account_id_strings() {
for account_id in &[
"aa",
"a-a",
"a-aa",
"100",
"0o",
"com",
"near",
"bowen",
"b-o_w_e-n",
"b.owen",
"bro.wen",
"a.ha",
"a.b-a.ra",
"system",
"over.9000",
"google.com",
"illia.cheapaccounts.near",
"0o0ooo00oo00o",
"alex-skidanov",
"10-4.8-2",
"b-o_w_e-n",
"no_lols",
"0123456789012345678901234567890123456789012345678901234567890123",
"near.a",
"a.a",
] {
assert!(
is_valid_account_id(account_id.as_ref()),
"Valid account id {:?} marked invalid",
account_id
);
}
for account_id in &[
"",
"a",
"A",
"Abc",
"-near",
"near-",
"-near-",
"near.",
".near",
"near@",
"@near",
"неар",
"@@@@@",
"0__0",
"0_-_0",
"0_-_0",
"..",
"a..near",
"nEar",
"_bowen",
"hello world",
"abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz",
"01234567890123456789012345678901234567890123456789012345678901234",
"some-complex-address@gmail.com",
"sub.buy_d1gitz@atata@b0-rg.c_0_m",
] {
assert!(
!is_valid_account_id(account_id.as_ref()),
"Invalid account id {:?} marked valid",
account_id
);
}
}
#[test]
fn test_is_valid_account_id_binary() {
assert!(!is_valid_account_id(&[]));
assert!(!is_valid_account_id(&[0]));
assert!(!is_valid_account_id(&[0, 1]));
assert!(!is_valid_account_id(&[0, 1, 2]));
assert!(is_valid_account_id(b"near"));
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn hash_smoke_tests() {
assert_eq!(
&super::sha256_array(b"some value"),
hex::decode("ab3d07f3169ccbd0ed6c4b45de21519f9f938c72d24124998aab949ce83bb51b")
.unwrap()
.as_slice()
);
assert_eq!(
&super::keccak256_array(b"some value"),
hex::decode("f928dfb5fc72b3bbfb9a5ccb0ee9843b27b4ac1ebc25a6f6f783e23ebd47ef1f")
.unwrap()
.as_slice()
);
assert_eq!(
&super::keccak512_array(b"some value"),
hex::decode("3e38d140a85123374ee63ec208973aa39b87349d17ccac948a2493e18b18b5913220cd174b4f511aa97977009e16be485fc94f5e2743cb9bb0579d35ab410583")
.unwrap()
.as_slice()
);
assert_eq!(
&super::ripemd160_array(b"some value"),
hex::decode("09f025fed704e1ecac8f88b2bda3e56876da03ac").unwrap().as_slice()
);
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn random_seed_smoke_test() {
crate::testing_env!(crate::test_utils::VMContextBuilder::new()
.random_seed([8; 32])
.build());
assert_eq!(super::random_seed(), [8; 32]);
}
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "unstable")]
#[test]
fn test_ecrecover() {
use crate::test_utils::test_env;
use hex::FromHex;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use serde_json::from_slice;
use std::fmt::Display;
#[derive(Deserialize)]
struct EcrecoverTest {
#[serde(with = "hex::serde")]
m: [u8; 32],
v: u8,
#[serde(with = "hex::serde")]
sig: [u8; 64],
mc: bool,
#[serde(deserialize_with = "deserialize_option_hex")]
res: Option<[u8; 64]>,
}
fn deserialize_option_hex<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: FromHex,
<T as FromHex>::Error: Display,
{
Deserialize::deserialize(deserializer)
.map(|v: Option<&str>| v.map(FromHex::from_hex).transpose().map_err(Error::custom))
.and_then(|v| v)
}
test_env::setup_free();
for EcrecoverTest { m, v, sig, mc, res } in
from_slice::<'_, Vec<_>>(include_bytes!("../../tests/ecrecover-tests.json")).unwrap()
{
assert_eq!(super::ecrecover(&m, &sig, v, mc), res);
}
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn signer_public_key() {
let key: PublicKey =
"ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp".parse().unwrap();
crate::testing_env!(crate::test_utils::VMContextBuilder::new()
.signer_account_pk(key.clone())
.build());
assert_eq!(super::signer_account_pk(), key);
}
#[test]
fn ed25519_verify() {
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,
];
const BAD_SIGNATURE: [u8; 64] = [1; 64];
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,
];
const FORGED_PUBLIC_KEY: [u8; 32] = {
let mut key = PUBLIC_KEY;
key[31] = 0b1110_0001;
key
};
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,
];
assert!(super::ed25519_verify(&SIGNATURE, &MESSAGE, &PUBLIC_KEY));
assert!(!super::ed25519_verify(&BAD_SIGNATURE, &MESSAGE, &FORGED_PUBLIC_KEY));
assert!(!super::ed25519_verify(&SIGNATURE, &MESSAGE, &FORGED_PUBLIC_KEY));
assert!(!super::ed25519_verify(&FORGED_SIGNATURE, &MESSAGE, &PUBLIC_KEY));
}
#[test]
pub fn alt_bn128_g1_multiexp() {
let buffer = [
16, 238, 91, 161, 241, 22, 172, 158, 138, 252, 202, 212, 136, 37, 110, 231, 118, 220,
8, 45, 14, 153, 125, 217, 227, 87, 238, 238, 31, 138, 226, 8, 238, 185, 12, 155, 93,
126, 144, 248, 200, 177, 46, 245, 40, 162, 169, 80, 150, 211, 157, 13, 10, 36, 44, 232,
173, 32, 32, 115, 123, 2, 9, 47, 190, 148, 181, 91, 69, 6, 83, 40, 65, 222, 251, 70,
81, 73, 60, 142, 130, 217, 176, 20, 69, 75, 40, 167, 41, 180, 244, 5, 142, 215, 135,
35,
];
assert_eq!(
super::alt_bn128_g1_multiexp(&buffer),
vec![
150, 94, 159, 52, 239, 226, 181, 150, 77, 86, 90, 186, 102, 219, 243, 204, 36, 128,
164, 209, 106, 6, 62, 124, 235, 104, 223, 195, 30, 204, 42, 20, 13, 158, 14, 197,
133, 73, 43, 171, 28, 68, 82, 116, 244, 164, 36, 251, 244, 8, 234, 40, 118, 55,
216, 187, 242, 39, 213, 160, 192, 184, 28, 23
]
);
}
#[test]
pub fn alt_bn128_g1_sum() {
let buffer = [
0, 11, 49, 94, 29, 152, 111, 116, 138, 248, 2, 184, 8, 159, 80, 169, 45, 149, 48, 32,
49, 37, 6, 133, 105, 171, 194, 120, 44, 195, 17, 180, 35, 137, 154, 4, 192, 211, 244,
93, 200, 2, 44, 0, 64, 26, 108, 139, 147, 88, 235, 242, 23, 253, 52, 110, 236, 67, 99,
176, 2, 186, 198, 228, 25,
];
assert_eq!(
super::alt_bn128_g1_sum(&buffer),
vec![
11, 49, 94, 29, 152, 111, 116, 138, 248, 2, 184, 8, 159, 80, 169, 45, 149, 48, 32,
49, 37, 6, 133, 105, 171, 194, 120, 44, 195, 17, 180, 35, 137, 154, 4, 192, 211,
244, 93, 200, 2, 44, 0, 64, 26, 108, 139, 147, 88, 235, 242, 23, 253, 52, 110, 236,
67, 99, 176, 2, 186, 198, 228, 25
]
);
}
#[test]
pub fn alt_bn128_pairing_check() {
let valid_pair = [
117, 10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213,
88, 224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3,
113, 76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246,
65, 237, 168, 104, 16, 4, 1, 26, 3, 219, 6, 13, 193, 115, 77, 230, 27, 13, 242, 214,
195, 9, 213, 99, 135, 12, 160, 202, 114, 135, 175, 42, 116, 172, 79, 234, 26, 41, 212,
111, 192, 129, 124, 112, 57, 107, 38, 244, 230, 222, 240, 36, 65, 238, 133, 188, 19,
43, 148, 59, 205, 40, 161, 179, 173, 228, 88, 169, 231, 29, 17, 67, 163, 51, 165, 187,
101, 44, 250, 24, 68, 101, 92, 128, 203, 190, 51, 85, 9, 43, 58, 136, 68, 180, 92, 110,
185, 168, 107, 129, 45, 30, 187, 22, 100, 17, 75, 93, 216, 125, 23, 212, 11, 186, 199,
204, 1, 140, 133, 11, 82, 44, 65, 222, 20, 26, 48, 26, 132, 220, 25, 213, 93, 25, 79,
176, 4, 149, 151, 243, 11, 131, 253, 233, 121, 38, 222, 15, 118, 117, 200, 214, 175,
233, 130, 181, 193, 167, 255, 153, 169, 240, 207, 235, 28, 31, 83, 74, 69, 179, 6, 150,
72, 67, 74, 166, 130, 83, 82, 115, 123, 111, 208, 221, 64, 43, 237, 213, 186, 235, 7,
56, 251, 179, 95, 233, 159, 23, 109, 173, 85, 103, 8, 165, 235, 226, 218, 79, 72, 120,
172, 251, 20, 83, 121, 201, 140, 98, 170, 246, 121, 218, 19, 115, 42, 135, 60, 239, 30,
32, 49, 170, 171, 204, 196, 197, 160, 158, 168, 47, 23, 110, 139, 123, 222, 222, 245,
98, 125, 208, 70, 39, 110, 186, 146, 254, 66, 185, 118, 3, 78, 32, 47, 179, 197, 93,
79, 240, 204, 78, 236, 133, 213, 173, 117, 94, 63, 154, 68, 89, 236, 138, 0, 247, 242,
212, 245, 33, 249, 0, 35, 246, 233, 0, 124, 86, 198, 162, 201, 54, 19, 26, 196, 75,
254, 71, 70, 238, 51, 2, 23, 185, 152, 139, 134, 65, 107, 129, 114, 244, 47, 251, 240,
80, 193, 23,
];
assert!(super::alt_bn128_pairing_check(&valid_pair));
let invalid_pair = [
117, 10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213,
88, 224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3,
113, 76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246,
65, 237, 168, 104, 16, 4, 1, 26, 3, 219, 6, 13, 193, 115, 77, 230, 27, 13, 242, 214,
195, 9, 213, 99, 135, 12, 160, 202, 114, 135, 175, 42, 116, 172, 79, 234, 26, 41, 212,
111, 192, 129, 124, 112, 57, 107, 38, 244, 230, 222, 240, 36, 65, 238, 133, 188, 19,
43, 148, 59, 205, 40, 161, 179, 173, 228, 88, 169, 231, 29, 17, 67, 163, 51, 165, 187,
101, 44, 250, 24, 68, 101, 92, 128, 203, 190, 51, 85, 9, 43, 58, 136, 68, 180, 92, 110,
185, 168, 107, 129, 45, 30, 187, 22, 100, 17, 75, 93, 216, 125, 23, 212, 11, 186, 199,
204, 1, 140, 133, 11, 82, 44, 65, 222, 20, 26, 48, 26, 132, 220, 25, 213, 93, 25, 117,
10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213, 88,
224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3, 113,
76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246, 65,
237, 168, 104, 16, 4, 109, 173, 85, 103, 8, 165, 235, 226, 218, 79, 72, 120, 172, 251,
20, 83, 121, 201, 140, 98, 170, 246, 121, 218, 19, 115, 42, 135, 60, 239, 30, 32, 49,
170, 171, 204, 196, 197, 160, 158, 168, 47, 23, 110, 139, 123, 222, 222, 245, 98, 125,
208, 70, 39, 110, 186, 146, 254, 66, 185, 118, 3, 78, 32, 47, 179, 197, 93, 79, 240,
204, 78, 236, 133, 213, 173, 117, 94, 63, 154, 68, 89, 236, 138, 0, 247, 242, 212, 245,
33, 249, 0, 35, 246, 233, 0, 124, 86, 198, 162, 201, 54, 19, 26, 196, 75, 254, 71, 70,
238, 51, 2, 23, 185, 152, 139, 134, 65, 107, 129, 114, 244, 47, 251, 240, 80, 193, 23,
];
assert!(!super::alt_bn128_pairing_check(&invalid_pair));
}
}