1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(clippy::as_conversions)]
4
5use crate::prelude::{Address, H256, STORAGE_PRICE_PER_BYTE};
6#[cfg(feature = "contract")]
7use crate::prelude::{Vec, U256};
8pub use types::keccak;
9
10pub mod base64;
11pub mod caching;
12pub mod env;
13pub mod error;
14pub mod io;
15#[cfg(feature = "contract")]
16pub mod near_runtime;
17mod prelude;
18pub mod promise;
19pub mod types;
20
21#[cfg(feature = "contract")]
22use near_runtime::exports;
23
24#[cfg(feature = "contract")]
25const ECRECOVER_MESSAGE_SIZE: u64 = 32;
26#[cfg(feature = "contract")]
27const ECRECOVER_SIGNATURE_LENGTH: u64 = 64;
28#[cfg(feature = "contract")]
29const ECRECOVER_MALLEABILITY_FLAG: u64 = 0;
30
31#[cfg(feature = "contract")]
32pub fn panic_utf8(bytes: &[u8]) -> ! {
33 unsafe {
34 exports::panic_utf8(bytes.len() as u64, bytes.as_ptr() as u64);
35 }
36 unreachable!()
37}
38
39#[cfg(feature = "contract")]
40pub fn log_utf8(bytes: &[u8]) {
41 unsafe {
42 exports::log_utf8(bytes.len() as u64, bytes.as_ptr() as u64);
43 }
44}
45
46#[cfg(feature = "contract")]
48#[must_use]
49pub fn sha256(input: &[u8]) -> H256 {
50 unsafe {
51 const REGISTER_ID: u64 = 1;
52 exports::sha256(input.len() as u64, input.as_ptr() as u64, 1);
53 let bytes = H256::zero();
54 exports::read_register(REGISTER_ID, bytes.0.as_ptr() as u64);
55 bytes
56 }
57}
58
59#[cfg(not(feature = "contract"))]
60#[must_use]
61pub fn sha256(input: &[u8]) -> H256 {
62 use sha2::Digest;
63
64 let output = sha2::Sha256::digest(input);
65 H256(output.into())
66}
67
68#[cfg(feature = "contract")]
70#[must_use]
71pub fn ripemd160(input: &[u8]) -> [u8; 20] {
72 unsafe {
73 const REGISTER_ID: u64 = 1;
74 exports::ripemd160(input.len() as u64, input.as_ptr() as u64, REGISTER_ID);
75 let bytes = [0u8; 20];
76 exports::read_register(REGISTER_ID, bytes.as_ptr() as u64);
77 bytes
78 }
79}
80
81#[cfg(feature = "contract")]
82#[must_use]
83pub fn alt_bn128_g1_sum(left: [u8; 64], right: [u8; 64]) -> [u8; 64] {
84 let mut bytes = Vec::with_capacity(64 * 2 + 2); bytes.push(0); bytes.extend_from_slice(&left);
88 bytes.push(0);
89 bytes.extend_from_slice(&right);
90
91 let value_ptr = bytes.as_ptr() as u64;
92 let value_len = bytes.len() as u64;
93
94 unsafe {
95 const REGISTER_ID: u64 = 1;
96 exports::alt_bn128_g1_sum(value_len, value_ptr, REGISTER_ID);
97 let mut output = [0u8; 64];
98 exports::read_register(REGISTER_ID, output.as_ptr() as u64);
99 let x = U256::from_little_endian(&output[0..32]);
100 let y = U256::from_little_endian(&output[32..64]);
101 output[0..32].copy_from_slice(&x.to_big_endian());
102 output[32..64].copy_from_slice(&y.to_big_endian());
103 output
104 }
105}
106
107#[cfg(feature = "contract")]
108#[must_use]
109pub fn alt_bn128_g1_scalar_multiple(g1: [u8; 64], fr: [u8; 32]) -> [u8; 64] {
110 let mut bytes = [0u8; 96];
111 bytes[0..64].copy_from_slice(&g1);
112 bytes[64..96].copy_from_slice(&fr);
113
114 let value_ptr = bytes.as_ptr() as u64;
115 let value_len = bytes.len() as u64;
116
117 unsafe {
118 const REGISTER_ID: u64 = 1;
119 exports::alt_bn128_g1_multiexp(value_len, value_ptr, REGISTER_ID);
120 let mut output = [0u8; 64];
121 exports::read_register(REGISTER_ID, output.as_ptr() as u64);
122 let x = U256::from_little_endian(&output[0..32]);
123 let y = U256::from_little_endian(&output[32..64]);
124 output[0..32].copy_from_slice(&x.to_big_endian());
125 output[32..64].copy_from_slice(&y.to_big_endian());
126 output
127 }
128}
129
130#[cfg(feature = "contract")]
131pub fn alt_bn128_pairing<I>(pairs: I) -> bool
132where
133 I: ExactSizeIterator<Item = ([u8; 64], [u8; 128])>,
134{
135 let n = pairs.len();
136 let mut bytes = Vec::with_capacity(n * 6 * 32);
137 let mut buf = [0u8; 64 + 128];
138 for (g1, g2) in pairs {
139 buf[0..64].copy_from_slice(&g1);
140 buf[64..192].copy_from_slice(&g2);
141 bytes.extend_from_slice(&buf);
142 }
143
144 let value_ptr = bytes.as_ptr() as u64;
145 let value_len = bytes.len() as u64;
146
147 let result = unsafe { exports::alt_bn128_pairing_check(value_len, value_ptr) };
148
149 result == 1
150}
151
152#[cfg(feature = "contract")]
154pub fn ecrecover(hash: H256, signature: &[u8]) -> Result<Address, ECRecoverErr> {
155 unsafe {
156 const RECOVER_REGISTER_ID: u64 = 1;
157 const KECCACK_REGISTER_ID: u64 = 2;
158
159 let hash_ptr = hash.as_ptr() as u64;
160 let sig_ptr = signature.as_ptr() as u64;
161 let result = exports::ecrecover(
162 ECRECOVER_MESSAGE_SIZE,
163 hash_ptr,
164 ECRECOVER_SIGNATURE_LENGTH,
165 sig_ptr,
166 u64::from(signature[64]),
167 ECRECOVER_MALLEABILITY_FLAG,
168 RECOVER_REGISTER_ID,
169 );
170 if result == u64::from(true) {
171 exports::keccak256(u64::MAX, RECOVER_REGISTER_ID, KECCACK_REGISTER_ID);
175 let keccak_hash_bytes = [0u8; 32];
176 exports::read_register(KECCACK_REGISTER_ID, keccak_hash_bytes.as_ptr() as u64);
177 Ok(Address::try_from_slice(&keccak_hash_bytes[12..]).map_err(|_| ECRecoverErr)?)
178 } else {
179 Err(ECRecoverErr)
180 }
181 }
182}
183
184#[cfg(not(feature = "contract"))]
185pub fn ecrecover(hash: H256, signature: &[u8]) -> Result<Address, ECRecoverErr> {
186 use sha3::Digest;
187
188 let hash = libsecp256k1::Message::parse_slice(hash.as_bytes()).map_err(|_| ECRecoverErr)?;
189 let v = signature[64];
190 let signature = libsecp256k1::Signature::parse_standard_slice(&signature[0..64])
191 .map_err(|_| ECRecoverErr)?;
192 let bit = match v {
193 0..=26 => v,
194 _ => v - 27,
195 };
196 let recovery_id = libsecp256k1::RecoveryId::parse(bit).map_err(|_| ECRecoverErr)?;
197
198 libsecp256k1::recover(&hash, &signature, &recovery_id)
199 .map_err(|_| ECRecoverErr)
200 .and_then(|public_key| {
201 let r = sha3::Keccak256::digest(&public_key.serialize()[1..]);
203 Address::try_from_slice(&r[12..]).map_err(|_| ECRecoverErr)
204 })
205}
206
207#[cfg(feature = "contract")]
208pub fn log(data: &str) {
209 log_utf8(data.as_bytes());
210}
211
212#[cfg(not(feature = "contract"))]
213#[allow(clippy::missing_const_for_fn)]
214pub fn log(_data: &str) {
215 }
217
218#[macro_export]
219macro_rules! log {
220 ($($args:tt)*) => {
221 #[cfg(feature = "log")]
222 $crate::log(&aurora_engine_types::format!("{}", format_args!($($args)*)))
223 };
224}
225
226#[must_use]
227pub const fn storage_byte_cost() -> u128 {
228 STORAGE_PRICE_PER_BYTE
229}
230
231pub struct ECRecoverErr;
232
233impl ECRecoverErr {
234 #[must_use]
235 pub const fn as_str(&self) -> &'static str {
236 "ERR_ECRECOVER"
237 }
238}
239
240impl AsRef<[u8]> for ECRecoverErr {
241 fn as_ref(&self) -> &[u8] {
242 self.as_str().as_bytes()
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249 use aurora_engine_types::types::Address;
250 use aurora_engine_types::H256;
251
252 const SIGNATURE_LENGTH: usize = 65;
253
254 fn ecverify(hash: H256, signature: &[u8], signer: Address) -> bool {
255 matches!(ecrecover(hash, signature[0..SIGNATURE_LENGTH].try_into().unwrap()), Ok(s) if s == signer)
256 }
257
258 #[test]
259 fn test_ecverify() {
260 let hash = H256::from_slice(
261 &hex::decode("1111111111111111111111111111111111111111111111111111111111111111")
262 .unwrap(),
263 );
264 let signature =
265 &hex::decode("b9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b69812ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447441b")
266 .unwrap();
267 let signer = Address::try_from_slice(
268 &hex::decode("1563915e194D8CfBA1943570603F7606A3115508").unwrap(),
269 )
270 .unwrap();
271 assert!(ecverify(hash, signature, signer));
272 }
273}