From 8fea0cc0dcb94dfbc5b1ced5993e70d01baa42e5 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 6 May 2021 09:17:29 -0400 Subject: [PATCH 01/45] Add BigNumber and syscalls --- Cargo.lock | 61 +- programs/bpf_loader/Cargo.toml | 3 + programs/bpf_loader/src/syscalls.rs | 5684 ++++++++++++++++++--------- sdk/bpf/c/inc/solana_sdk.h | 217 + sdk/program/Cargo.toml | 3 + sdk/program/src/bignum.rs | 704 ++++ sdk/program/src/lib.rs | 1 + sdk/src/process_instruction.rs | 57 + 8 files changed, 4958 insertions(+), 1772 deletions(-) create mode 100644 sdk/program/src/bignum.rs diff --git a/Cargo.lock b/Cargo.lock index 6ab0dd84df03de..1323d4592fac9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -873,6 +873,16 @@ dependencies = [ "subtle 2.2.2", ] +[[package]] +name = "crypto-mac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array 0.14.3", + "subtle 2.2.2", +] + [[package]] name = "csv" version = "1.1.3" @@ -1176,7 +1186,7 @@ version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1676e1daadfd216bda88d3a6fedd1bf53b829a085f5cc4d81c6f3054f50ef983" dependencies = [ - "num-bigint", + "num-bigint 0.3.1", "num-traits", "proc-macro2 1.0.24", "quote 1.0.6", @@ -1669,6 +1679,16 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" +[[package]] +name = "hkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +dependencies = [ + "digest 0.9.0", + "hmac 0.11.0", +] + [[package]] name = "hmac" version = "0.7.1" @@ -1709,6 +1729,16 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.0", + "digest 0.9.0", +] + [[package]] name = "hmac-drbg" version = "0.2.0" @@ -2527,6 +2557,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" +dependencies = [ + "autocfg 1.0.0", + "num-integer", + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.2" @@ -2624,15 +2665,15 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.29" +version = "0.10.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd" +checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" dependencies = [ "bitflags", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", "openssl-sys", ] @@ -2644,9 +2685,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.57" +version = "0.9.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7410fef80af8ac071d4f63755c0ab89ac3df0fd1ea91f1d1f37cf5cec4395990" +checksum = "fa52160d45fa2e7608d504b7c3a3355afed615e6d8b627a74458634ba21b69bd" dependencies = [ "autocfg 1.0.0", "cc", @@ -4080,10 +4121,13 @@ name = "solana-bpf-loader-program" version = "1.7.0" dependencies = [ "bincode", + "blake3", "byteorder", + "hkdf", "log 0.4.11", "num-derive", "num-traits", + "openssl", "rand 0.7.3", "rand_core 0.6.2", "rustversion", @@ -4956,11 +5000,14 @@ dependencies = [ "bv", "curve25519-dalek 2.1.0", "hex", + "hkdf", "itertools", "lazy_static", "log 0.4.11", + "num-bigint 0.4.0", "num-derive", "num-traits", + "openssl", "rand 0.7.3", "rustc_version", "rustversion", diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index cd1e8ec382216a..9bf99839155a2b 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -21,6 +21,9 @@ solana-runtime = { path = "../../runtime", version = "=1.7.0" } solana-sdk = { path = "../../sdk", version = "=1.7.0" } solana_rbpf = "=0.2.8" thiserror = "1.0" +hkdf = "0.11.0" +blake3 = "0.3.7" +openssl = "0.10.32" [dev-dependencies] rand = "0.7.3" diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index cbfafbc9e1ce0b..b8a4e2da7b29e9 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1,5 +1,8 @@ use crate::{alloc, BpfError}; use alloc::Alloc; +use blake3::traits::digest::Digest; +use hkdf::Hkdf; +use openssl::bn::*; use solana_rbpf::{ aligned_memory::AlignedMemory, ebpf::MM_HEAP_START, @@ -73,6 +76,30 @@ pub enum SyscallError { InstructionTooLarge(usize, usize), #[error("Too many accounts passed to inner instruction")] TooManyAccounts, + #[error("BigNumber: Modular exponentiation error")] + BigNumberModExpError, + #[error("BigNumber: add error")] + BigNumberAddError, + #[error("BigNumber: sub error")] + BigNumberSubError, + #[error("BigNumber: mul error")] + BigNumberMulError, + #[error("BigNumber: div error")] + BigNumberDivError, + #[error("BigNumber: exp error")] + BigNumberExpError, + #[error("BigNumber: sqr error")] + BigNumberSqrError, + #[error("BigNumber: mod_sqr error")] + BigNumberModSqrError, + #[error("BigNumber: mod_mul error")] + BigNumberModMulError, + #[error("BigNumber: mod_inv error")] + BigNumberModInvError, + #[error("BigNumber: hash generator error")] + BigNumberHgError, + #[error("BigNumber: hash_to_primeerror")] + BigNumberHtpError, } impl From for EbpfError { fn from(error: SyscallError) -> Self { @@ -146,6 +173,36 @@ pub fn register_syscalls( .register_syscall_by_name(b"sol_invoke_signed_rust", SyscallInvokeSignedRust::call)?; syscall_registry.register_syscall_by_name(b"sol_alloc_free_", SyscallAllocFree::call)?; + // Bignum syscall names + syscall_registry.register_syscall_by_name(b"sol_bignum_new", SyscallBigNumNew::call)?; + syscall_registry + .register_syscall_by_name(b"sol_bignum_from_u32", SyscallBigNumFromU32::call)?; + syscall_registry + .register_syscall_by_name(b"sol_bignum_from_bytes", SyscallBigNumFromBytes::call)?; + syscall_registry + .register_syscall_by_name(b"sol_bignum_to_bytes", SyscallBigNumToBytes::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_mod_exp", SyscallBigNumModExp::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_drop", SyscallBigNumDrop::call)?; + syscall_registry.register_syscall_by_name(b"sol_log_bignum", SyscallLogBigNum::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_add", SyscallBigNumAdd::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_sub", SyscallBigNumSub::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_mul", SyscallBigNumMul::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_div", SyscallBigNumDiv::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_exp", SyscallBigNumExp::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_sqr", SyscallBigNumSqr::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_mod_sqr", SyscallBigNumModSqr::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_mod_mul", SyscallBigNumModMul::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_mod_inv", SyscallBigNumModInv::call)?; + // Compound functions + syscall_registry + .register_syscall_by_name(b"sol_bignum_hashed_generator", SyscallBigNumHg::call)?; + + syscall_registry.register_syscall_by_name(b"sol_blake3_digest", SyscallBlake3Digest::call)?; + syscall_registry.register_syscall_by_name( + b"sol_bignum_hash_to_prime", + SyscallBigNumberHashToPrime::call, + )?; + Ok(syscall_registry) } @@ -252,6 +309,165 @@ pub fn bind_syscall_context_objects<'a>( None, )?; + // Bignum bindings + vm.bind_syscall_context_object( + Box::new(SyscallBigNumNew { + cost: bpf_compute_budget.bignum_new_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumFromU32 { + cost: bpf_compute_budget.bignum_from_u32_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumFromBytes { + cost: bpf_compute_budget.bignum_from_bytes_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumToBytes { + cost: bpf_compute_budget.bignum_to_bytes_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallBigNumModExp { + cost: bpf_compute_budget.bignum_mod_exp_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumDrop { + cost: bpf_compute_budget.bignum_drop_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallLogBigNum { + cost: bpf_compute_budget.log_bignum_cost, + compute_meter: invoke_context.get_compute_meter(), + logger: invoke_context.get_logger(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumAdd { + cost: bpf_compute_budget.bignum_add_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumSub { + cost: bpf_compute_budget.bignum_sub_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumMul { + cost: bpf_compute_budget.bignum_mul_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumDiv { + cost: bpf_compute_budget.bignum_div_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumExp { + cost: bpf_compute_budget.bignum_exp_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumSqr { + cost: bpf_compute_budget.bignum_sqr_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumModSqr { + cost: bpf_compute_budget.bignum_mod_sqr_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumModMul { + cost: bpf_compute_budget.bignum_mod_mul_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumModInv { + cost: bpf_compute_budget.bignum_mod_inv_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallBigNumHg { + cost: bpf_compute_budget.bignum_hashed_generator_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallBlake3Digest { + cost: bpf_compute_budget.blake3_digest_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumberHashToPrime { + cost: bpf_compute_budget.bignum_hash_to_prime_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; + let is_sysvar_via_syscall_active = invoke_context.is_feature_active(&sysvar_via_syscall::id()); let invoke_context = Rc::new(RefCell::new(invoke_context)); @@ -934,49 +1150,27 @@ impl<'a> SyscallObject for SyscallSha256<'a> { } } -fn get_sysvar( - id: &Pubkey, - var_addr: u64, - loader_id: &Pubkey, - memory_mapping: &MemoryMapping, - invoke_context: Rc>, -) -> Result> { - let mut invoke_context = invoke_context - .try_borrow_mut() - .map_err(|_| SyscallError::InvokeContextBorrowFailed)?; - - invoke_context.get_compute_meter().consume( - invoke_context.get_bpf_compute_budget().sysvar_base_cost + size_of::() as u64, - )?; - let var = translate_type_mut::( - memory_mapping, - var_addr, - loader_id, - invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()), - )?; - - let sysvar_data = invoke_context.get_sysvar_data(id).ok_or_else(|| { - ic_msg!(invoke_context, "Unable to get Sysvar {}", id); - SyscallError::InstructionError(InstructionError::UnsupportedSysvar) - })?; - - *var = bincode::deserialize(&sysvar_data).map_err(|e| { - ic_msg!(invoke_context, "Unable to get Sysvar {}: {:?}", id, e); - SyscallError::InstructionError(InstructionError::UnsupportedSysvar) - })?; - - Ok(SUCCESS) +/// BIGNUM data cost +const BIGNUM_WORDCOST: f64 = 6.0; +/// BIGNUM cost divisor +const BIGNUM_WORDCOST_DIVISOR: f64 = 32.0; +/// Bignum data cost calculator +macro_rules! calc_bignum_cost { + ($input:expr) => { + (BIGNUM_WORDCOST * ($input / BIGNUM_WORDCOST_DIVISOR).ceil()) as u64 + }; } -/// Get a Clock sysvar -struct SyscallGetClockSysvar<'a> { - invoke_context: Rc>, +/// BIGNUM sol_bignum_new +pub struct SyscallBigNumNew<'a> { + cost: u64, + compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallGetClockSysvar<'a> { +impl<'a> SyscallObject for SyscallBigNumNew<'a> { fn call( &mut self, - var_addr: u64, + bn_addr: u64, _arg2: u64, _arg3: u64, _arg4: u64, @@ -984,851 +1178,1864 @@ impl<'a> SyscallObject for SyscallGetClockSysvar<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - *result = get_sysvar::( - &sysvar::clock::id(), - var_addr, - self.loader_id, - memory_mapping, - self.invoke_context.clone(), + let big_number = question_mark!( + translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), + result ); + let bbox = Box::new(BigNum::new().unwrap()); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + *big_number = bignum_ptr; + question_mark!(self.compute_meter.consume(self.cost), result); + *result = Ok(0) } } -/// Get a EpochSchedule sysvar -struct SyscallGetEpochScheduleSysvar<'a> { - invoke_context: Rc>, + +pub struct SyscallBigNumFromU32<'a> { + cost: u64, + compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallGetEpochScheduleSysvar<'a> { +impl<'a> SyscallObject for SyscallBigNumFromU32<'a> { fn call( &mut self, - var_addr: u64, - _arg2: u64, + bn_addr: u64, + u32_val: u64, _arg3: u64, _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - *result = get_sysvar::( - &sysvar::epoch_schedule::id(), - var_addr, - self.loader_id, - memory_mapping, - self.invoke_context.clone(), + let big_number = question_mark!( + translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), + result ); + let bbox = Box::new(BigNum::from_u32(u32_val as u32).unwrap()); + let bytes = bbox.num_bytes() as f64; + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + *big_number = bignum_ptr; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + *result = Ok(0) } } -/// Get a Fees sysvar -struct SyscallGetFeesSysvar<'a> { - invoke_context: Rc>, +pub struct SyscallBigNumFromBytes<'a> { + cost: u64, + compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallGetFeesSysvar<'a> { +impl<'a> SyscallObject for SyscallBigNumFromBytes<'a> { fn call( &mut self, - var_addr: u64, - _arg2: u64, - _arg3: u64, + bn_addr: u64, + bytes_addr: u64, + bytes_len: u64, _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - *result = get_sysvar::( - &sysvar::fees::id(), - var_addr, - self.loader_id, - memory_mapping, - self.invoke_context.clone(), + let big_number = question_mark!( + translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), + result + ); + let byte_slice = question_mark!( + translate_slice::(memory_mapping, bytes_addr, bytes_len, self.loader_id, true), + result + ); + let bytes: f64 = byte_slice.len() as f64; + let bbox = Box::new(BigNum::from_slice(byte_slice).unwrap()); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + *big_number = bignum_ptr; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result ); + *result = Ok(0) } } -/// Get a Rent sysvar -struct SyscallGetRentSysvar<'a> { - invoke_context: Rc>, +pub struct SyscallBigNumToBytes<'a> { + cost: u64, + compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallGetRentSysvar<'a> { +impl<'a> SyscallObject for SyscallBigNumToBytes<'a> { fn call( &mut self, - var_addr: u64, - _arg2: u64, - _arg3: u64, + bn_self: u64, + bytes_addr: u64, + bytes_len_addr: u64, _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - *result = get_sysvar::( - &sysvar::rent::id(), - var_addr, - self.loader_id, - memory_mapping, - self.invoke_context.clone(), + let self_bignum_address = question_mark!( + translate_type::(memory_mapping, bn_self, self.loader_id, true), + result + ); + let bytes_len = question_mark!( + translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), + result + ); + let bytes_buffer = question_mark!( + translate_slice_mut::(memory_mapping, bytes_addr, *bytes_len, self.loader_id, true), + result + ); + let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; + let bn_bytes = bn_self.as_ref().to_vec(); + let bytes = bn_bytes.len() as f64; + let mut index = 0; + for byte in bn_bytes.iter() { + bytes_buffer[index] = *byte; + index += 1; + } + *bytes_len = index as u64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result ); + *result = Ok(0) } } -// Cross-program invocation syscalls - -struct AccountReferences<'a> { - lamports: &'a mut u64, - owner: &'a mut Pubkey, - data: &'a mut [u8], - vm_data_addr: u64, - ref_to_len_in_vm: &'a mut u64, - serialized_len_ptr: &'a mut u64, +/// BIGNUM sol_bignum_mod_exp +pub struct SyscallBigNumModExp<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, } -type TranslatedAccount<'a> = ( - Rc>, - Option>, -); -type TranslatedAccounts<'a> = ( - Vec>>, - Vec>>, -); - -/// Implemented by language specific data structure translators -trait SyscallInvokeSigned<'a> { - fn get_context_mut(&self) -> Result, EbpfError>; - fn get_context(&self) -> Result, EbpfError>; - fn translate_instruction( - &self, - addr: u64, - memory_mapping: &MemoryMapping, - enforce_aligned_host_addrs: bool, - ) -> Result>; - fn translate_accounts( - &self, - account_keys: &[Pubkey], - caller_write_privileges: &[bool], - program_account_index: usize, - account_infos_addr: u64, - account_infos_len: u64, +impl<'a> SyscallObject for SyscallBigNumModExp<'a> { + fn call( + &mut self, + mod_exp_addr: u64, + self_bn_addr: u64, + exponent_bn_addr: u64, + modulus_bn_addr: u64, + _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result, EbpfError>; - fn translate_signers( - &self, - program_id: &Pubkey, - signers_seeds_addr: u64, - signers_seeds_len: u64, + result: &mut Result>, + ) { + let mod_bignum_address = question_mark!( + translate_type_mut::(memory_mapping, mod_exp_addr, self.loader_id, true), + result + ); + let self_bignum_address = question_mark!( + translate_type::(memory_mapping, self_bn_addr, self.loader_id, true), + result + ); + let exponent_bignum_address = question_mark!( + translate_type::(memory_mapping, exponent_bn_addr, self.loader_id, true), + result + ); + let modulus_bignum_address = question_mark!( + translate_type::(memory_mapping, modulus_bn_addr, self.loader_id, true), + result + ); + + let mut mod_exp_bn = Box::new(BigNum::new().unwrap()); + let bn_self = unsafe { &*(*self_bignum_address as *const BigNum) }; + let bn_exponent = unsafe { &*(*exponent_bignum_address as *const BigNum) }.as_ref(); + let bn_modulus = (unsafe { &*(*modulus_bignum_address as *const BigNum) }).as_ref(); + let bytes = (bn_self.num_bytes() + bn_exponent.num_bytes() + bn_modulus.num_bytes()) as f64; + let ctx = &mut BigNumContext::new().unwrap(); + match mod_exp_bn.mod_exp(bn_self, bn_exponent, bn_modulus, ctx) { + Ok(()) => { + let rwptr = Box::into_raw(mod_exp_bn); + let mod_exp_ptr = rwptr as u64; + *mod_bignum_address = mod_exp_ptr; + *result = Ok(0) + } + Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), + } + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + } +} +/// Add BigNums +pub struct SyscallBigNumAdd<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumAdd<'a> { + fn call( + &mut self, + self_addr: u64, + rhs_addr: u64, + sum_addr: u64, + _arg4: u64, + _arg5: u64, memory_mapping: &MemoryMapping, - enforce_aligned_host_addrs: bool, - ) -> Result, EbpfError>; + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let rhs_ptr = question_mark!( + translate_type::(memory_mapping, rhs_addr, self.loader_id, true), + result + ); + let sum_address = question_mark!( + translate_type_mut::(memory_mapping, sum_addr, self.loader_id, true), + result + ); + + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + let mut sum_bn = Box::new(BigNum::new().unwrap()); + // let mut sum_ref = *sum_bn; + match BigNumRef::checked_add(&mut *sum_bn, self_bn, rhs_bn) { + Ok(_) => { + let rwptr = Box::into_raw(sum_bn); + let sum_ptr = rwptr as u64; + *sum_address = sum_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberAddError.into()), + }; + } } -/// Cross-program invocation called from Rust -pub struct SyscallInvokeSignedRust<'a> { - invoke_context: Rc>, +/// Subtract BigNums +pub struct SyscallBigNumSub<'a> { + cost: u64, + compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { - fn get_context_mut(&self) -> Result, EbpfError> { - self.invoke_context - .try_borrow_mut() - .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) - } - fn get_context(&self) -> Result, EbpfError> { - self.invoke_context - .try_borrow() - .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) +impl<'a> SyscallObject for SyscallBigNumSub<'a> { + fn call( + &mut self, + self_addr: u64, + rhs_addr: u64, + diff_addr: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let rhs_ptr = question_mark!( + translate_type::(memory_mapping, rhs_addr, self.loader_id, true), + result + ); + let diff_address = question_mark!( + translate_type_mut::(memory_mapping, diff_addr, self.loader_id, true), + result + ); + + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + let mut diff_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::checked_sub(&mut *diff_bn, self_bn, rhs_bn) { + Ok(_) => { + let rwptr = Box::into_raw(diff_bn); + let diff_ptr = rwptr as u64; + *diff_address = diff_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberSubError.into()), + }; } - fn translate_instruction( - &self, - addr: u64, +} +/// Subtract BigNums +pub struct SyscallBigNumMul<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumMul<'a> { + fn call( + &mut self, + self_addr: u64, + rhs_addr: u64, + prod_addr: u64, + _arg4: u64, + _arg5: u64, memory_mapping: &MemoryMapping, - enforce_aligned_host_addrs: bool, - ) -> Result> { - let ix = translate_type::( - memory_mapping, - addr, - self.loader_id, - enforce_aligned_host_addrs, - )?; + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let rhs_ptr = question_mark!( + translate_type::(memory_mapping, rhs_addr, self.loader_id, true), + result + ); + let prod_address = question_mark!( + translate_type_mut::(memory_mapping, prod_addr, self.loader_id, true), + result + ); - check_instruction_size( - ix.accounts.len(), - ix.data.len(), - &self.invoke_context.borrow(), - )?; + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - let accounts = translate_slice::( - memory_mapping, - ix.accounts.as_ptr() as u64, - ix.accounts.len() as u64, - self.loader_id, - enforce_aligned_host_addrs, - )? - .to_vec(); - let data = translate_slice::( - memory_mapping, - ix.data.as_ptr() as u64, - ix.data.len() as u64, - self.loader_id, - enforce_aligned_host_addrs, - )? - .to_vec(); - Ok(Instruction { - program_id: ix.program_id, - accounts, - data, - }) + let mut prod_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::checked_mul( + &mut *prod_bn, + self_bn, + rhs_bn, + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + let rwptr = Box::into_raw(prod_bn); + let prod_ptr = rwptr as u64; + *prod_address = prod_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberMulError.into()), + }; } - - fn translate_accounts( - &self, - account_keys: &[Pubkey], - caller_write_privileges: &[bool], - program_account_index: usize, - account_infos_addr: u64, - account_infos_len: u64, +} +pub struct SyscallBigNumDiv<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumDiv<'a> { + fn call( + &mut self, + self_addr: u64, + rhs_addr: u64, + quotient_addr: u64, + _arg4: u64, + _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result, EbpfError> { - let invoke_context = self.invoke_context.borrow(); - let enforce_aligned_host_addrs = - invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()); + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let rhs_ptr = question_mark!( + translate_type::(memory_mapping, rhs_addr, self.loader_id, true), + result + ); + let quotient_address = question_mark!( + translate_type_mut::(memory_mapping, quotient_addr, self.loader_id, true), + result + ); - let account_infos = translate_slice::( - memory_mapping, - account_infos_addr, - account_infos_len, - self.loader_id, - enforce_aligned_host_addrs, - )?; - check_account_infos(account_infos.len(), &invoke_context)?; - let account_info_keys = account_infos - .iter() - .map(|account_info| { - translate_type::( - memory_mapping, - account_info.key as *const _ as u64, - self.loader_id, - enforce_aligned_host_addrs, - ) - }) - .collect::, EbpfError>>()?; + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - let translate = |account_info: &AccountInfo, - invoke_context: &Ref<&mut dyn InvokeContext>| { - // Translate the account from user space + let mut quot_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::checked_div( + &mut *quot_bn, + self_bn, + rhs_bn, + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + let rwptr = Box::into_raw(quot_bn); + let prod_ptr = rwptr as u64; + *quotient_address = prod_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberDivError.into()), + }; + } +} +pub struct SyscallBigNumExp<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumExp<'a> { + fn call( + &mut self, + self_addr: u64, + exponent_addr: u64, + result_exp_addr: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let exp_ptr = question_mark!( + translate_type::(memory_mapping, exponent_addr, self.loader_id, true), + result + ); + let result_exp_address = question_mark!( + translate_type_mut::(memory_mapping, result_exp_addr, self.loader_id, true), + result + ); - let lamports = { - // Double translate lamports out of RefCell - let ptr = translate_type::( - memory_mapping, - account_info.lamports.as_ptr() as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?; - translate_type_mut::( - memory_mapping, - *ptr, - self.loader_id, - enforce_aligned_host_addrs, - )? - }; - let owner = translate_type_mut::( - memory_mapping, - account_info.owner as *const _ as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?; - - let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = { - // Double translate data out of RefCell - let data = *translate_type::<&[u8]>( - memory_mapping, - account_info.data.as_ptr() as *const _ as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?; - - if invoke_context.is_feature_active(&cpi_data_cost::id()) { - invoke_context.get_compute_meter().consume( - data.len() as u64 - / invoke_context.get_bpf_compute_budget().cpi_bytes_per_unit, - )?; - } - - let translated = translate( - memory_mapping, - AccessType::Store, - unsafe { (account_info.data.as_ptr() as *const u64).offset(1) as u64 }, - 8, - )? as *mut u64; - let ref_to_len_in_vm = unsafe { &mut *translated }; - let ref_of_len_in_input_buffer = unsafe { data.as_ptr().offset(-8) }; - let serialized_len_ptr = translate_type_mut::( - memory_mapping, - ref_of_len_in_input_buffer as *const _ as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?; - let vm_data_addr = data.as_ptr() as u64; - ( - translate_slice_mut::( - memory_mapping, - vm_data_addr, - data.len() as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?, - vm_data_addr, - ref_to_len_in_vm, - serialized_len_ptr, - ) - }; + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let exp_bn = unsafe { &*(*exp_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + exp_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - Ok(( - Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: *lamports, - data: data.to_vec(), - executable: account_info.executable, - owner: *owner, - rent_epoch: account_info.rent_epoch, - }))), - Some(AccountReferences { - lamports, - owner, - data, - vm_data_addr, - ref_to_len_in_vm, - serialized_len_ptr, - }), - )) + let mut result_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::exp( + &mut *result_bn, + self_bn, + exp_bn, + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + let rwptr = Box::into_raw(result_bn); + let exp_ptr = rwptr as u64; + *result_exp_address = exp_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberExpError.into()), }; - - get_translated_accounts( - account_keys, - caller_write_privileges, - program_account_index, - &account_info_keys, - account_infos, - &invoke_context, - translate, - ) } - - fn translate_signers( - &self, - program_id: &Pubkey, - signers_seeds_addr: u64, - signers_seeds_len: u64, +} +pub struct SyscallBigNumSqr<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumSqr<'a> { + fn call( + &mut self, + self_addr: u64, + result_sqr_addr: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, memory_mapping: &MemoryMapping, - enforce_aligned_host_addrs: bool, - ) -> Result, EbpfError> { - let mut signers = Vec::new(); - if signers_seeds_len > 0 { - let signers_seeds = translate_slice::<&[&[u8]]>( - memory_mapping, - signers_seeds_addr, - signers_seeds_len, - self.loader_id, - enforce_aligned_host_addrs, - )?; - if signers_seeds.len() > MAX_SIGNERS { - return Err(SyscallError::TooManySigners.into()); - } - for signer_seeds in signers_seeds.iter() { - let untranslated_seeds = translate_slice::<&[u8]>( - memory_mapping, - signer_seeds.as_ptr() as *const _ as u64, - signer_seeds.len() as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?; - if untranslated_seeds.len() > MAX_SEEDS { - return Err(SyscallError::InstructionError( - InstructionError::MaxSeedLengthExceeded, - ) - .into()); - } - let seeds = untranslated_seeds - .iter() - .map(|untranslated_seed| { - translate_slice::( - memory_mapping, - untranslated_seed.as_ptr() as *const _ as u64, - untranslated_seed.len() as u64, - self.loader_id, - enforce_aligned_host_addrs, - ) - }) - .collect::, EbpfError>>()?; - let signer = Pubkey::create_program_address(&seeds, program_id) - .map_err(SyscallError::BadSeeds)?; - signers.push(signer); + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let result_sqr_address = question_mark!( + translate_type_mut::(memory_mapping, result_sqr_addr, self.loader_id, true), + result + ); + + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let bytes = self_bn.num_bytes() as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + + let mut result_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::sqr(&mut *result_bn, self_bn, &mut BigNumContext::new().unwrap()) { + Ok(_) => { + let rwptr = Box::into_raw(result_bn); + let exp_ptr = rwptr as u64; + *result_sqr_address = exp_ptr; + *result = Ok(0) } - Ok(signers) - } else { - Ok(vec![]) - } + _ => *result = Err(SyscallError::BigNumberSqrError.into()), + }; } } -impl<'a> SyscallObject for SyscallInvokeSignedRust<'a> { +pub struct SyscallBigNumModSqr<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumModSqr<'a> { fn call( &mut self, - instruction_addr: u64, - account_infos_addr: u64, - account_infos_len: u64, - signers_seeds_addr: u64, - signers_seeds_len: u64, + self_addr: u64, + mod_addr: u64, + result_mod_sqr_addr: u64, + _arg4: u64, + _arg5: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - *result = call( - self, - instruction_addr, - account_infos_addr, - account_infos_len, - signers_seeds_addr, - signers_seeds_len, - memory_mapping, + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let mod_ptr = question_mark!( + translate_type::(memory_mapping, mod_addr, self.loader_id, true), + result + ); + let result_mod_sqr_address = question_mark!( + translate_type_mut::(memory_mapping, result_mod_sqr_addr, self.loader_id, true), + result ); - } -} -/// Rust representation of C's SolInstruction -#[derive(Debug)] -struct SolInstruction { - program_id_addr: u64, - accounts_addr: u64, - accounts_len: usize, - data_addr: u64, - data_len: usize, -} + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let mod_bn = unsafe { &*(*mod_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + mod_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); -/// Rust representation of C's SolAccountMeta -#[derive(Debug)] -struct SolAccountMeta { - pubkey_addr: u64, - is_writable: bool, - is_signer: bool, + let mut result_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::mod_sqr( + &mut *result_bn, + self_bn, + mod_bn, + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + let rwptr = Box::into_raw(result_bn); + let mod_sqr_ptr = rwptr as u64; + *result_mod_sqr_address = mod_sqr_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberModSqrError.into()), + }; + } } -/// Rust representation of C's SolAccountInfo -#[derive(Debug)] -struct SolAccountInfo { - key_addr: u64, - lamports_addr: u64, - data_len: u64, - data_addr: u64, - owner_addr: u64, - rent_epoch: u64, - is_signer: bool, - is_writable: bool, - executable: bool, +pub struct SyscallBigNumModMul<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, } +impl<'a> SyscallObject for SyscallBigNumModMul<'a> { + fn call( + &mut self, + self_addr: u64, + mul_addr: u64, + mod_addr: u64, + result_mod_mul_addr: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let mul_ptr = question_mark!( + translate_type::(memory_mapping, mul_addr, self.loader_id, true), + result + ); + let mod_ptr = question_mark!( + translate_type::(memory_mapping, mod_addr, self.loader_id, true), + result + ); + let result_mod_mul_address = question_mark!( + translate_type_mut::(memory_mapping, result_mod_mul_addr, self.loader_id, true), + result + ); -/// Rust representation of C's SolSignerSeed -#[derive(Debug)] -struct SolSignerSeedC { - addr: u64, - len: u64, -} + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let mul_bn = unsafe { &*(*mul_ptr as *mut BigNum) }; + let mod_bn = unsafe { &*(*mod_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + mul_bn.num_bytes() + mod_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); -/// Rust representation of C's SolSignerSeeds -#[derive(Debug)] -struct SolSignerSeedsC { - addr: u64, - len: u64, + let mut result_bn = Box::new(BigNum::new().unwrap()); + match BigNumRef::mod_mul( + &mut *result_bn, + self_bn, + mul_bn, + mod_bn, + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + let rwptr = Box::into_raw(result_bn); + let mod_sqr_ptr = rwptr as u64; + *result_mod_mul_address = mod_sqr_ptr; + *result = Ok(0) + } + _ => *result = Err(SyscallError::BigNumberModSqrError.into()), + }; + } } -/// Cross-program invocation called from C -pub struct SyscallInvokeSignedC<'a> { - invoke_context: Rc>, - loader_id: &'a Pubkey, +pub struct SyscallBigNumModInv<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, } -impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { - fn get_context_mut(&self) -> Result, EbpfError> { - self.invoke_context - .try_borrow_mut() - .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) - } - fn get_context(&self) -> Result, EbpfError> { - self.invoke_context - .try_borrow() - .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) - } - - fn translate_instruction( - &self, - addr: u64, +impl<'a> SyscallObject for SyscallBigNumModInv<'a> { + fn call( + &mut self, + self_addr: u64, + mod_addr: u64, + result_mod_sqr_addr: u64, + _arg4: u64, + _arg5: u64, memory_mapping: &MemoryMapping, - enforce_aligned_host_addrs: bool, - ) -> Result> { - let ix_c = translate_type::( - memory_mapping, - addr, - self.loader_id, - enforce_aligned_host_addrs, - )?; + result: &mut Result>, + ) { + let self_ptr = question_mark!( + translate_type::(memory_mapping, self_addr, self.loader_id, true), + result + ); + let mod_ptr = question_mark!( + translate_type::(memory_mapping, mod_addr, self.loader_id, true), + result + ); + let result_mod_sqr_address = question_mark!( + translate_type_mut::(memory_mapping, result_mod_sqr_addr, self.loader_id, true), + result + ); - check_instruction_size( - ix_c.accounts_len, - ix_c.data_len, - &self.invoke_context.borrow(), - )?; - let program_id = translate_type::( - memory_mapping, - ix_c.program_id_addr, - self.loader_id, - enforce_aligned_host_addrs, - )?; - let meta_cs = translate_slice::( - memory_mapping, - ix_c.accounts_addr, - ix_c.accounts_len as u64, - self.loader_id, - enforce_aligned_host_addrs, - )?; - let data = translate_slice::( - memory_mapping, - ix_c.data_addr, - ix_c.data_len as u64, - self.loader_id, - enforce_aligned_host_addrs, - )? - .to_vec(); - let accounts = meta_cs - .iter() - .map(|meta_c| { - let pubkey = translate_type::( - memory_mapping, - meta_c.pubkey_addr, - self.loader_id, - enforce_aligned_host_addrs, - )?; - Ok(AccountMeta { - pubkey: *pubkey, - is_signer: meta_c.is_signer, - is_writable: meta_c.is_writable, - }) - }) - .collect::, EbpfError>>()?; + let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; + let mod_bn = unsafe { &*(*mod_ptr as *mut BigNum) }; + let bytes = (self_bn.num_bytes() + mod_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - Ok(Instruction { - program_id: *program_id, - accounts, - data, - }) + // let mut result_bn = Box::new(BigNum::new().unwrap()); + let mut result_bn = BigNum::new().unwrap(); + match result_bn.mod_inverse(&*self_bn, &*mod_bn, &mut BigNumContext::new().unwrap()) { + // match BigNumRef::mod_inverse(&mut result_bn, self_bn, mod_bn, &mut BigNumContext::new().unwrap()) { + Ok(_) => { + let rwptr = Box::into_raw(Box::new(result_bn)); + let mod_sqr_ptr = rwptr as u64; + *result_mod_sqr_address = mod_sqr_ptr; + *result = Ok(0) + } + Err(_e) => { + // println!("{}", e); + *result = Err(SyscallError::BigNumberModInvError.into()) + }, + }; } +} - fn translate_accounts( - &self, - account_keys: &[Pubkey], - caller_write_privileges: &[bool], - program_account_index: usize, - account_infos_addr: u64, - account_infos_len: u64, +pub struct SyscallBigNumHg<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumHg<'a> { + fn call( + &mut self, + u_addr: u64, + a_addr: u64, + n_addr: u64, + nonce_addr: u64, + hg_result_addr: u64, memory_mapping: &MemoryMapping, - ) -> Result, EbpfError> { - let invoke_context = self.invoke_context.borrow(); - let enforce_aligned_host_addrs = - invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()); + result: &mut Result>, + ) { + // Get the 3 BigNums (u, a, n) + let bn_u_ptr = question_mark!( + translate_type::(memory_mapping, u_addr, self.loader_id, true), + result + ); + let bn_a_ptr = question_mark!( + translate_type::(memory_mapping, a_addr, self.loader_id, true), + result + ); + let bn_n_ptr = question_mark!( + translate_type::(memory_mapping, n_addr, self.loader_id, true), + result + ); + let hg_result_address = question_mark!( + translate_type_mut::(memory_mapping, hg_result_addr, self.loader_id, true), + result + ); + let nonce_len = unsafe { *(hg_result_address as *mut u64) }; + let nonce_ptr = question_mark!( + translate_slice::(memory_mapping, nonce_addr, nonce_len, self.loader_id, true), + result + ); - let account_infos = translate_slice::( - memory_mapping, - account_infos_addr, - account_infos_len, - self.loader_id, - enforce_aligned_host_addrs, - )?; - check_account_infos(account_infos.len(), &invoke_context)?; - let account_info_keys = account_infos - .iter() - .map(|account_info| { - translate_type::( - memory_mapping, - account_info.key_addr, - self.loader_id, - enforce_aligned_host_addrs, - ) - }) - .collect::, EbpfError>>()?; + let u_bn = unsafe { &*(*bn_u_ptr as *mut BigNum) }; + let a_bn = unsafe { &*(*bn_a_ptr as *mut BigNum) }; + let n_bn = unsafe { &*(*bn_n_ptr as *mut BigNum) }; + let bytes = (u_bn.num_bytes() + a_bn.num_bytes() + n_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - let translate = |account_info: &SolAccountInfo, - invoke_context: &Ref<&mut dyn InvokeContext>| { - // Translate the account from user space + // println!("u:{}",u_bn); + // println!("a:{}",a_bn); + // println!("n:{}",n_bn); + + // hash_generator + let mut transcript = u_bn.as_ref().to_vec(); + transcript.append(&mut a_bn.as_ref().to_vec()); + // transcript.extend_from_slice(nonce_ptr.as_ref()); + transcript.extend_from_slice(nonce_ptr); + // println!("t:{:?}",transcript); + let length = n_bn.num_bytes(); + // println!("len:{}",length); + let h = Hkdf::::new( + Some(b"SST_SALT_HASH_TO_GENERATOR_"), + transcript.as_slice().as_ref(), + ); + let mut okm = vec![0u8; length as usize]; + h.expand(b"", &mut okm).unwrap(); + // println!("okm:{:?}", okm); - let lamports = translate_type_mut::( - memory_mapping, - account_info.lamports_addr, - self.loader_id, - enforce_aligned_host_addrs, - )?; - let owner = translate_type_mut::( - memory_mapping, - account_info.owner_addr, - self.loader_id, - enforce_aligned_host_addrs, - )?; - let vm_data_addr = account_info.data_addr; + let okm_bn = BigNum::from_slice(okm.as_slice()).unwrap(); - if invoke_context.is_feature_active(&cpi_data_cost::id()) { - invoke_context.get_compute_meter().consume( - account_info.data_len - / invoke_context.get_bpf_compute_budget().cpi_bytes_per_unit, - )?; - } + let mut res_bn = Box::new(BigNum::new().unwrap()); + res_bn + .mod_sqr(okm_bn.as_ref(), n_bn, &mut BigNumContext::new().unwrap()) + .unwrap(); + let rwptr = Box::into_raw(res_bn); + *hg_result_address = rwptr as u64; + *result = Ok(0) + } +} +/// BIGNUM sol_bignum_drop +pub struct SyscallBigNumDrop<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumDrop<'a> { + fn call( + &mut self, + bn_addr: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let big_number = question_mark!( + translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), + result + ); + drop(unsafe { Box::from_raw(*big_number as *mut BigNum) }); + *big_number = 0u64; + question_mark!(self.compute_meter.consume(self.cost), result); + *result = Ok(0) + } +} - let data = translate_slice_mut::( - memory_mapping, - vm_data_addr, - account_info.data_len, - self.loader_id, - enforce_aligned_host_addrs, - )?; +/// Log BigNum values +pub struct SyscallLogBigNum<'a> { + cost: u64, + compute_meter: Rc>, + logger: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallLogBigNum<'a> { + fn call( + &mut self, + bn_addr: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let bignum_ptr = question_mark!( + translate_type::(memory_mapping, bn_addr, self.loader_id, true), + result + ); + let bignum = unsafe { &*(*bignum_ptr as *mut BigNum) }; + let bytes = bignum.num_bytes() as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - let first_info_addr = &account_infos[0] as *const _ as u64; - let addr = &account_info.data_len as *const u64 as u64; - let vm_addr = account_infos_addr + (addr - first_info_addr); - let _ = translate( - memory_mapping, - AccessType::Store, - vm_addr, - size_of::() as u64, - )?; - let ref_to_len_in_vm = unsafe { &mut *(addr as *mut u64) }; + stable_log::program_log(&self.logger, &bignum.to_string()); + *result = Ok(0); + } +} - let ref_of_len_in_input_buffer = - unsafe { (account_info.data_addr as *mut u8).offset(-8) }; - let serialized_len_ptr = translate_type_mut::( +pub struct SyscallBlake3Digest<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBlake3Digest<'a> { + fn call( + &mut self, + bytes_addr: u64, + bytes_len_addr: u64, + digest_addr: u64, + digest_len_addr: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let bytes_len = question_mark!( + translate_type::(memory_mapping, bytes_len_addr, self.loader_id, true), + result + ); + let bytes = question_mark!( + translate_slice::(memory_mapping, bytes_addr, *bytes_len, self.loader_id, true), + result + ); + let digest_len = question_mark!( + translate_type_mut::(memory_mapping, digest_len_addr, self.loader_id, true), + result + ); + let digest_bytes = question_mark!( + translate_slice_mut::( memory_mapping, - ref_of_len_in_input_buffer as *const _ as u64, + digest_addr, + *digest_len, self.loader_id, - enforce_aligned_host_addrs, - )?; + true + ), + result + ); - Ok(( - Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: *lamports, - data: data.to_vec(), - executable: account_info.executable, - owner: *owner, - rent_epoch: account_info.rent_epoch, - }))), - Some(AccountReferences { - lamports, - owner, - data, - vm_data_addr, - ref_to_len_in_vm, - serialized_len_ptr, - }), - )) - }; - - get_translated_accounts( - account_keys, - caller_write_privileges, - program_account_index, - &account_info_keys, - account_infos, - &invoke_context, - translate, - ) - } - - fn translate_signers( - &self, - program_id: &Pubkey, - signers_seeds_addr: u64, - signers_seeds_len: u64, - memory_mapping: &MemoryMapping, - enforce_aligned_host_addrs: bool, - ) -> Result, EbpfError> { - if signers_seeds_len > 0 { - let signers_seeds = translate_slice::( - memory_mapping, - signers_seeds_addr, - signers_seeds_len, - self.loader_id, - enforce_aligned_host_addrs, - )?; - if signers_seeds.len() > MAX_SIGNERS { - return Err(SyscallError::TooManySigners.into()); - } - Ok(signers_seeds - .iter() - .map(|signer_seeds| { - let seeds = translate_slice::( - memory_mapping, - signer_seeds.addr, - signer_seeds.len, - self.loader_id, - enforce_aligned_host_addrs, - )?; - if seeds.len() > MAX_SEEDS { - return Err(SyscallError::InstructionError( - InstructionError::MaxSeedLengthExceeded, - ) - .into()); - } - let seeds_bytes = seeds - .iter() - .map(|seed| { - translate_slice::( - memory_mapping, - seed.addr, - seed.len, - self.loader_id, - enforce_aligned_host_addrs, - ) - }) - .collect::, EbpfError>>()?; - Pubkey::create_program_address(&seeds_bytes, program_id) - .map_err(|err| SyscallError::BadSeeds(err).into()) - }) - .collect::, EbpfError>>()?) - } else { - Ok(vec![]) + // println!("bytes-----syscall:{:?}", bytes); + let digest = blake3::Hasher::digest(bytes); + // println!("digest-----syscall:{:?}", digest.as_slice().to_vec()); + let mut index = 0; + for byte in digest.iter() { + digest_bytes[index] = *byte; + index += 1; } + *digest_len = index as u64; + let bytes = (*bytes_len + *digest_len) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + *result = Ok(0) } } -impl<'a> SyscallObject for SyscallInvokeSignedC<'a> { + +/// Finds a valid prime from hash of u, a, z, nonce +pub struct SyscallBigNumberHashToPrime<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumberHashToPrime<'a> { fn call( &mut self, - instruction_addr: u64, - account_infos_addr: u64, - account_infos_len: u64, - signers_seeds_addr: u64, - signers_seeds_len: u64, + u_addr: u64, + a_addr: u64, + z_addr: u64, + nonce_addr: u64, + htp_result_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - *result = call( - self, - instruction_addr, - account_infos_addr, - account_infos_len, - signers_seeds_addr, - signers_seeds_len, - memory_mapping, + // Get the 3 BigNums pointers (u, a, z) + let bn_u_ptr = question_mark!( + translate_type::(memory_mapping, u_addr, self.loader_id, true), + result + ); + let bn_a_ptr = question_mark!( + translate_type::(memory_mapping, a_addr, self.loader_id, true), + result + ); + let bn_z_ptr = question_mark!( + translate_type::(memory_mapping, z_addr, self.loader_id, true), + result + ); + // Get the result location, on inbound it contains the nonce length + let htp_result_address = question_mark!( + translate_type_mut::(memory_mapping, htp_result_addr, self.loader_id, true), + result + ); + // Get the nonce + let nonce_len = unsafe { *(htp_result_address as *mut u64) }; + let nonce_ptr = question_mark!( + translate_slice::(memory_mapping, nonce_addr, nonce_len, self.loader_id, true), + result ); - } -} -fn get_translated_accounts<'a, T, F>( - account_keys: &[Pubkey], - caller_write_privileges: &[bool], - program_account_index: usize, - account_info_keys: &[&Pubkey], - account_infos: &[T], - invoke_context: &Ref<&mut dyn InvokeContext>, - do_translate: F, -) -> Result, EbpfError> -where - F: Fn(&T, &Ref<&mut dyn InvokeContext>) -> Result, EbpfError>, -{ - let mut accounts = Vec::with_capacity(account_keys.len()); - let mut refs = Vec::with_capacity(account_keys.len()); - for (i, ref account_key) in account_keys.iter().enumerate() { - let account = invoke_context.get_account(&account_key).ok_or_else(|| { - ic_msg!( - invoke_context, - "Instruction references an unknown account {}", - account_key - ); - SyscallError::InstructionError(InstructionError::MissingAccount) - })?; + let u_bn = unsafe { &*(*bn_u_ptr as *mut BigNum) }; + let a_bn = unsafe { &*(*bn_a_ptr as *mut BigNum) }; + let z_bn = unsafe { &*(*bn_z_ptr as *mut BigNum) }; + let bytes = (u_bn.num_bytes() + a_bn.num_bytes() + z_bn.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); - if i == program_account_index - || account.borrow().executable() - || (invoke_context.is_feature_active(&cpi_share_ro_and_exec_accounts::id()) - && !caller_write_privileges[i]) - { - // Use the known account - accounts.push(account); - refs.push(None); - } else if let Some(account_info) = - account_info_keys - .iter() - .zip(account_infos) - .find_map(|(key, account_info)| { - if key == account_key { - Some(account_info) - } else { - None - } - }) - { - let (account, account_ref) = do_translate(account_info, invoke_context)?; - accounts.push(account); - refs.push(account_ref); - } else { - ic_msg!( - invoke_context, - "Instruction references an unknown account {}", - account_key - ); - return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into()); + let mut input = u_bn.as_ref().to_vec(); + input.extend_from_slice(&a_bn.as_ref().to_vec()); + input.extend_from_slice(&z_bn.as_ref().to_vec()); + input.extend_from_slice(nonce_ptr); + // println!("t:{:?}",input); + + let mut i = 1u32; + let offset = input.len(); + input.extend_from_slice(&i.to_be_bytes()[..]); + let end = input.len(); + let ctx = &mut BigNumContext::new().unwrap(); + let mut num; + loop { + let mut hash = blake3::Hasher::digest(input.as_slice()); + // Force it to be odd + hash[31] |= 1; + // Only need 256 bits just borrow the bottom 32 bytes + // There should be plenty of primes below 2^256 + // and we want this to be reasonably fast + //num = BigNumber::from_bytes(&hash[32..]); + num = BigNum::from_slice(&hash).unwrap(); + if num.is_prime(15, ctx).unwrap() { + // msg!("num_bytes:{:?}",num.to_bytes().to_vec()); + // msg!("i:{}",i); + break; + } + i += 1; + let i_bytes = i.to_be_bytes(); + input[offset..end].clone_from_slice(&i_bytes[..]); } + println!("HashToPrimeLoop:{}", i); + let res_bn = Box::new(num); + let rwptr = Box::into_raw(res_bn); + *htp_result_address = rwptr as u64; + *result = Ok(0) } - - Ok((accounts, refs)) } -fn check_instruction_size( - num_accounts: usize, - data_len: usize, - invoke_context: &Ref<&mut dyn InvokeContext>, -) -> Result<(), EbpfError> { - let size = num_accounts - .saturating_mul(size_of::()) - .saturating_add(data_len); - let max_size = invoke_context - .get_bpf_compute_budget() - .max_cpi_instruction_size; - if size > max_size { - return Err(SyscallError::InstructionTooLarge(size, max_size).into()); - } - Ok(()) -} +fn get_sysvar( + id: &Pubkey, + var_addr: u64, + loader_id: &Pubkey, + memory_mapping: &MemoryMapping, + invoke_context: Rc>, +) -> Result> { + let mut invoke_context = invoke_context + .try_borrow_mut() + .map_err(|_| SyscallError::InvokeContextBorrowFailed)?; -fn check_account_infos( - len: usize, - invoke_context: &Ref<&mut dyn InvokeContext>, -) -> Result<(), EbpfError> { - if len * size_of::() - > invoke_context - .get_bpf_compute_budget() - .max_cpi_instruction_size - { - // Cap the number of account_infos a caller can pass to approximate - // maximum that accounts that could be passed in an instruction - return Err(SyscallError::TooManyAccounts.into()); - }; - Ok(()) -} + invoke_context.get_compute_meter().consume( + invoke_context.get_bpf_compute_budget().sysvar_base_cost + size_of::() as u64, + )?; + let var = translate_type_mut::( + memory_mapping, + var_addr, + loader_id, + invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()), + )?; -fn check_authorized_program( - program_id: &Pubkey, - instruction_data: &[u8], - invoke_context: &Ref<&mut dyn InvokeContext>, -) -> Result<(), EbpfError> { - if native_loader::check_id(program_id) - || bpf_loader::check_id(program_id) - || bpf_loader_deprecated::check_id(program_id) - || (bpf_loader_upgradeable::check_id(program_id) - && !(bpf_loader_upgradeable::is_upgrade_instruction(instruction_data) - || (bpf_loader_upgradeable::is_set_authority_instruction(instruction_data) - && invoke_context - .is_feature_active(&set_upgrade_authority_via_cpi_enabled::id())))) - { - return Err(SyscallError::ProgramNotSupported(*program_id).into()); - } - Ok(()) + let sysvar_data = invoke_context.get_sysvar_data(id).ok_or_else(|| { + ic_msg!(invoke_context, "Unable to get Sysvar {}", id); + SyscallError::InstructionError(InstructionError::UnsupportedSysvar) + })?; + + *var = bincode::deserialize(&sysvar_data).map_err(|e| { + ic_msg!(invoke_context, "Unable to get Sysvar {}: {:?}", id, e); + SyscallError::InstructionError(InstructionError::UnsupportedSysvar) + })?; + + Ok(SUCCESS) } -#[allow(clippy::type_complexity)] -fn get_upgradeable_executable( - callee_program_id: &Pubkey, - program_account: &Rc>, - invoke_context: &Ref<&mut dyn InvokeContext>, -) -> Result>)>, EbpfError> { - if program_account.borrow().owner() == &bpf_loader_upgradeable::id() { - match program_account.borrow().state() { +/// Get a Clock sysvar +struct SyscallGetClockSysvar<'a> { + invoke_context: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallGetClockSysvar<'a> { + fn call( + &mut self, + var_addr: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = get_sysvar::( + &sysvar::clock::id(), + var_addr, + self.loader_id, + memory_mapping, + self.invoke_context.clone(), + ); + } +} +/// Get a EpochSchedule sysvar +struct SyscallGetEpochScheduleSysvar<'a> { + invoke_context: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallGetEpochScheduleSysvar<'a> { + fn call( + &mut self, + var_addr: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = get_sysvar::( + &sysvar::epoch_schedule::id(), + var_addr, + self.loader_id, + memory_mapping, + self.invoke_context.clone(), + ); + } +} +/// Get a Fees sysvar +struct SyscallGetFeesSysvar<'a> { + invoke_context: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallGetFeesSysvar<'a> { + fn call( + &mut self, + var_addr: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = get_sysvar::( + &sysvar::fees::id(), + var_addr, + self.loader_id, + memory_mapping, + self.invoke_context.clone(), + ); + } +} +/// Get a Rent sysvar +struct SyscallGetRentSysvar<'a> { + invoke_context: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallGetRentSysvar<'a> { + fn call( + &mut self, + var_addr: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = get_sysvar::( + &sysvar::rent::id(), + var_addr, + self.loader_id, + memory_mapping, + self.invoke_context.clone(), + ); + } +} + +// Cross-program invocation syscalls + +struct AccountReferences<'a> { + lamports: &'a mut u64, + owner: &'a mut Pubkey, + data: &'a mut [u8], + vm_data_addr: u64, + ref_to_len_in_vm: &'a mut u64, + serialized_len_ptr: &'a mut u64, +} +type TranslatedAccount<'a> = ( + Rc>, + Option>, +); +type TranslatedAccounts<'a> = ( + Vec>>, + Vec>>, +); + +/// Implemented by language specific data structure translators +trait SyscallInvokeSigned<'a> { + fn get_context_mut(&self) -> Result, EbpfError>; + fn get_context(&self) -> Result, EbpfError>; + fn translate_instruction( + &self, + addr: u64, + memory_mapping: &MemoryMapping, + enforce_aligned_host_addrs: bool, + ) -> Result>; + fn translate_accounts( + &self, + account_keys: &[Pubkey], + caller_write_privileges: &[bool], + program_account_index: usize, + account_infos_addr: u64, + account_infos_len: u64, + memory_mapping: &MemoryMapping, + ) -> Result, EbpfError>; + fn translate_signers( + &self, + program_id: &Pubkey, + signers_seeds_addr: u64, + signers_seeds_len: u64, + memory_mapping: &MemoryMapping, + enforce_aligned_host_addrs: bool, + ) -> Result, EbpfError>; +} + +/// Cross-program invocation called from Rust +pub struct SyscallInvokeSignedRust<'a> { + invoke_context: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { + fn get_context_mut(&self) -> Result, EbpfError> { + self.invoke_context + .try_borrow_mut() + .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) + } + fn get_context(&self) -> Result, EbpfError> { + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) + } + fn translate_instruction( + &self, + addr: u64, + memory_mapping: &MemoryMapping, + enforce_aligned_host_addrs: bool, + ) -> Result> { + let ix = translate_type::( + memory_mapping, + addr, + self.loader_id, + enforce_aligned_host_addrs, + )?; + + check_instruction_size( + ix.accounts.len(), + ix.data.len(), + &self.invoke_context.borrow(), + )?; + + let accounts = translate_slice::( + memory_mapping, + ix.accounts.as_ptr() as u64, + ix.accounts.len() as u64, + self.loader_id, + enforce_aligned_host_addrs, + )? + .to_vec(); + let data = translate_slice::( + memory_mapping, + ix.data.as_ptr() as u64, + ix.data.len() as u64, + self.loader_id, + enforce_aligned_host_addrs, + )? + .to_vec(); + Ok(Instruction { + program_id: ix.program_id, + accounts, + data, + }) + } + + fn translate_accounts( + &self, + account_keys: &[Pubkey], + caller_write_privileges: &[bool], + program_account_index: usize, + account_infos_addr: u64, + account_infos_len: u64, + memory_mapping: &MemoryMapping, + ) -> Result, EbpfError> { + let invoke_context = self.invoke_context.borrow(); + let enforce_aligned_host_addrs = + invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()); + + let account_infos = translate_slice::( + memory_mapping, + account_infos_addr, + account_infos_len, + self.loader_id, + enforce_aligned_host_addrs, + )?; + check_account_infos(account_infos.len(), &invoke_context)?; + let account_info_keys = account_infos + .iter() + .map(|account_info| { + translate_type::( + memory_mapping, + account_info.key as *const _ as u64, + self.loader_id, + enforce_aligned_host_addrs, + ) + }) + .collect::, EbpfError>>()?; + + let translate = |account_info: &AccountInfo, + invoke_context: &Ref<&mut dyn InvokeContext>| { + // Translate the account from user space + + let lamports = { + // Double translate lamports out of RefCell + let ptr = translate_type::( + memory_mapping, + account_info.lamports.as_ptr() as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + translate_type_mut::( + memory_mapping, + *ptr, + self.loader_id, + enforce_aligned_host_addrs, + )? + }; + let owner = translate_type_mut::( + memory_mapping, + account_info.owner as *const _ as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + + let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = { + // Double translate data out of RefCell + let data = *translate_type::<&[u8]>( + memory_mapping, + account_info.data.as_ptr() as *const _ as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + + if invoke_context.is_feature_active(&cpi_data_cost::id()) { + invoke_context.get_compute_meter().consume( + data.len() as u64 + / invoke_context.get_bpf_compute_budget().cpi_bytes_per_unit, + )?; + } + + let translated = translate( + memory_mapping, + AccessType::Store, + unsafe { (account_info.data.as_ptr() as *const u64).offset(1) as u64 }, + 8, + )? as *mut u64; + let ref_to_len_in_vm = unsafe { &mut *translated }; + let ref_of_len_in_input_buffer = unsafe { data.as_ptr().offset(-8) }; + let serialized_len_ptr = translate_type_mut::( + memory_mapping, + ref_of_len_in_input_buffer as *const _ as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + let vm_data_addr = data.as_ptr() as u64; + ( + translate_slice_mut::( + memory_mapping, + vm_data_addr, + data.len() as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?, + vm_data_addr, + ref_to_len_in_vm, + serialized_len_ptr, + ) + }; + + Ok(( + Rc::new(RefCell::new(AccountSharedData::from(Account { + lamports: *lamports, + data: data.to_vec(), + executable: account_info.executable, + owner: *owner, + rent_epoch: account_info.rent_epoch, + }))), + Some(AccountReferences { + lamports, + owner, + data, + vm_data_addr, + ref_to_len_in_vm, + serialized_len_ptr, + }), + )) + }; + + get_translated_accounts( + account_keys, + caller_write_privileges, + program_account_index, + &account_info_keys, + account_infos, + &invoke_context, + translate, + ) + } + + fn translate_signers( + &self, + program_id: &Pubkey, + signers_seeds_addr: u64, + signers_seeds_len: u64, + memory_mapping: &MemoryMapping, + enforce_aligned_host_addrs: bool, + ) -> Result, EbpfError> { + let mut signers = Vec::new(); + if signers_seeds_len > 0 { + let signers_seeds = translate_slice::<&[&[u8]]>( + memory_mapping, + signers_seeds_addr, + signers_seeds_len, + self.loader_id, + enforce_aligned_host_addrs, + )?; + if signers_seeds.len() > MAX_SIGNERS { + return Err(SyscallError::TooManySigners.into()); + } + for signer_seeds in signers_seeds.iter() { + let untranslated_seeds = translate_slice::<&[u8]>( + memory_mapping, + signer_seeds.as_ptr() as *const _ as u64, + signer_seeds.len() as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + if untranslated_seeds.len() > MAX_SEEDS { + return Err(SyscallError::InstructionError( + InstructionError::MaxSeedLengthExceeded, + ) + .into()); + } + let seeds = untranslated_seeds + .iter() + .map(|untranslated_seed| { + translate_slice::( + memory_mapping, + untranslated_seed.as_ptr() as *const _ as u64, + untranslated_seed.len() as u64, + self.loader_id, + enforce_aligned_host_addrs, + ) + }) + .collect::, EbpfError>>()?; + let signer = Pubkey::create_program_address(&seeds, program_id) + .map_err(SyscallError::BadSeeds)?; + signers.push(signer); + } + Ok(signers) + } else { + Ok(vec![]) + } + } +} +impl<'a> SyscallObject for SyscallInvokeSignedRust<'a> { + fn call( + &mut self, + instruction_addr: u64, + account_infos_addr: u64, + account_infos_len: u64, + signers_seeds_addr: u64, + signers_seeds_len: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = call( + self, + instruction_addr, + account_infos_addr, + account_infos_len, + signers_seeds_addr, + signers_seeds_len, + memory_mapping, + ); + } +} + +/// Rust representation of C's SolInstruction +#[derive(Debug)] +struct SolInstruction { + program_id_addr: u64, + accounts_addr: u64, + accounts_len: usize, + data_addr: u64, + data_len: usize, +} + +/// Rust representation of C's SolAccountMeta +#[derive(Debug)] +struct SolAccountMeta { + pubkey_addr: u64, + is_writable: bool, + is_signer: bool, +} + +/// Rust representation of C's SolAccountInfo +#[derive(Debug)] +struct SolAccountInfo { + key_addr: u64, + lamports_addr: u64, + data_len: u64, + data_addr: u64, + owner_addr: u64, + rent_epoch: u64, + is_signer: bool, + is_writable: bool, + executable: bool, +} + +/// Rust representation of C's SolSignerSeed +#[derive(Debug)] +struct SolSignerSeedC { + addr: u64, + len: u64, +} + +/// Rust representation of C's SolSignerSeeds +#[derive(Debug)] +struct SolSignerSeedsC { + addr: u64, + len: u64, +} + +/// Cross-program invocation called from C +pub struct SyscallInvokeSignedC<'a> { + invoke_context: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { + fn get_context_mut(&self) -> Result, EbpfError> { + self.invoke_context + .try_borrow_mut() + .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) + } + fn get_context(&self) -> Result, EbpfError> { + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed.into()) + } + + fn translate_instruction( + &self, + addr: u64, + memory_mapping: &MemoryMapping, + enforce_aligned_host_addrs: bool, + ) -> Result> { + let ix_c = translate_type::( + memory_mapping, + addr, + self.loader_id, + enforce_aligned_host_addrs, + )?; + + check_instruction_size( + ix_c.accounts_len, + ix_c.data_len, + &self.invoke_context.borrow(), + )?; + let program_id = translate_type::( + memory_mapping, + ix_c.program_id_addr, + self.loader_id, + enforce_aligned_host_addrs, + )?; + let meta_cs = translate_slice::( + memory_mapping, + ix_c.accounts_addr, + ix_c.accounts_len as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + let data = translate_slice::( + memory_mapping, + ix_c.data_addr, + ix_c.data_len as u64, + self.loader_id, + enforce_aligned_host_addrs, + )? + .to_vec(); + let accounts = meta_cs + .iter() + .map(|meta_c| { + let pubkey = translate_type::( + memory_mapping, + meta_c.pubkey_addr, + self.loader_id, + enforce_aligned_host_addrs, + )?; + Ok(AccountMeta { + pubkey: *pubkey, + is_signer: meta_c.is_signer, + is_writable: meta_c.is_writable, + }) + }) + .collect::, EbpfError>>()?; + + Ok(Instruction { + program_id: *program_id, + accounts, + data, + }) + } + + fn translate_accounts( + &self, + account_keys: &[Pubkey], + caller_write_privileges: &[bool], + program_account_index: usize, + account_infos_addr: u64, + account_infos_len: u64, + memory_mapping: &MemoryMapping, + ) -> Result, EbpfError> { + let invoke_context = self.invoke_context.borrow(); + let enforce_aligned_host_addrs = + invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()); + + let account_infos = translate_slice::( + memory_mapping, + account_infos_addr, + account_infos_len, + self.loader_id, + enforce_aligned_host_addrs, + )?; + check_account_infos(account_infos.len(), &invoke_context)?; + let account_info_keys = account_infos + .iter() + .map(|account_info| { + translate_type::( + memory_mapping, + account_info.key_addr, + self.loader_id, + enforce_aligned_host_addrs, + ) + }) + .collect::, EbpfError>>()?; + + let translate = |account_info: &SolAccountInfo, + invoke_context: &Ref<&mut dyn InvokeContext>| { + // Translate the account from user space + + let lamports = translate_type_mut::( + memory_mapping, + account_info.lamports_addr, + self.loader_id, + enforce_aligned_host_addrs, + )?; + let owner = translate_type_mut::( + memory_mapping, + account_info.owner_addr, + self.loader_id, + enforce_aligned_host_addrs, + )?; + let vm_data_addr = account_info.data_addr; + + if invoke_context.is_feature_active(&cpi_data_cost::id()) { + invoke_context.get_compute_meter().consume( + account_info.data_len + / invoke_context.get_bpf_compute_budget().cpi_bytes_per_unit, + )?; + } + + let data = translate_slice_mut::( + memory_mapping, + vm_data_addr, + account_info.data_len, + self.loader_id, + enforce_aligned_host_addrs, + )?; + + let first_info_addr = &account_infos[0] as *const _ as u64; + let addr = &account_info.data_len as *const u64 as u64; + let vm_addr = account_infos_addr + (addr - first_info_addr); + let _ = translate( + memory_mapping, + AccessType::Store, + vm_addr, + size_of::() as u64, + )?; + let ref_to_len_in_vm = unsafe { &mut *(addr as *mut u64) }; + + let ref_of_len_in_input_buffer = + unsafe { (account_info.data_addr as *mut u8).offset(-8) }; + let serialized_len_ptr = translate_type_mut::( + memory_mapping, + ref_of_len_in_input_buffer as *const _ as u64, + self.loader_id, + enforce_aligned_host_addrs, + )?; + + Ok(( + Rc::new(RefCell::new(AccountSharedData::from(Account { + lamports: *lamports, + data: data.to_vec(), + executable: account_info.executable, + owner: *owner, + rent_epoch: account_info.rent_epoch, + }))), + Some(AccountReferences { + lamports, + owner, + data, + vm_data_addr, + ref_to_len_in_vm, + serialized_len_ptr, + }), + )) + }; + + get_translated_accounts( + account_keys, + caller_write_privileges, + program_account_index, + &account_info_keys, + account_infos, + &invoke_context, + translate, + ) + } + + fn translate_signers( + &self, + program_id: &Pubkey, + signers_seeds_addr: u64, + signers_seeds_len: u64, + memory_mapping: &MemoryMapping, + enforce_aligned_host_addrs: bool, + ) -> Result, EbpfError> { + if signers_seeds_len > 0 { + let signers_seeds = translate_slice::( + memory_mapping, + signers_seeds_addr, + signers_seeds_len, + self.loader_id, + enforce_aligned_host_addrs, + )?; + if signers_seeds.len() > MAX_SIGNERS { + return Err(SyscallError::TooManySigners.into()); + } + Ok(signers_seeds + .iter() + .map(|signer_seeds| { + let seeds = translate_slice::( + memory_mapping, + signer_seeds.addr, + signer_seeds.len, + self.loader_id, + enforce_aligned_host_addrs, + )?; + if seeds.len() > MAX_SEEDS { + return Err(SyscallError::InstructionError( + InstructionError::MaxSeedLengthExceeded, + ) + .into()); + } + let seeds_bytes = seeds + .iter() + .map(|seed| { + translate_slice::( + memory_mapping, + seed.addr, + seed.len, + self.loader_id, + enforce_aligned_host_addrs, + ) + }) + .collect::, EbpfError>>()?; + Pubkey::create_program_address(&seeds_bytes, program_id) + .map_err(|err| SyscallError::BadSeeds(err).into()) + }) + .collect::, EbpfError>>()?) + } else { + Ok(vec![]) + } + } +} +impl<'a> SyscallObject for SyscallInvokeSignedC<'a> { + fn call( + &mut self, + instruction_addr: u64, + account_infos_addr: u64, + account_infos_len: u64, + signers_seeds_addr: u64, + signers_seeds_len: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = call( + self, + instruction_addr, + account_infos_addr, + account_infos_len, + signers_seeds_addr, + signers_seeds_len, + memory_mapping, + ); + } +} + +fn get_translated_accounts<'a, T, F>( + account_keys: &[Pubkey], + caller_write_privileges: &[bool], + program_account_index: usize, + account_info_keys: &[&Pubkey], + account_infos: &[T], + invoke_context: &Ref<&mut dyn InvokeContext>, + do_translate: F, +) -> Result, EbpfError> +where + F: Fn(&T, &Ref<&mut dyn InvokeContext>) -> Result, EbpfError>, +{ + let mut accounts = Vec::with_capacity(account_keys.len()); + let mut refs = Vec::with_capacity(account_keys.len()); + for (i, ref account_key) in account_keys.iter().enumerate() { + let account = invoke_context.get_account(&account_key).ok_or_else(|| { + ic_msg!( + invoke_context, + "Instruction references an unknown account {}", + account_key + ); + SyscallError::InstructionError(InstructionError::MissingAccount) + })?; + + if i == program_account_index + || account.borrow().executable() + || (invoke_context.is_feature_active(&cpi_share_ro_and_exec_accounts::id()) + && !caller_write_privileges[i]) + { + // Use the known account + accounts.push(account); + refs.push(None); + } else if let Some(account_info) = + account_info_keys + .iter() + .zip(account_infos) + .find_map(|(key, account_info)| { + if key == account_key { + Some(account_info) + } else { + None + } + }) + { + let (account, account_ref) = do_translate(account_info, invoke_context)?; + accounts.push(account); + refs.push(account_ref); + } else { + ic_msg!( + invoke_context, + "Instruction references an unknown account {}", + account_key + ); + return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into()); + } + } + + Ok((accounts, refs)) +} + +fn check_instruction_size( + num_accounts: usize, + data_len: usize, + invoke_context: &Ref<&mut dyn InvokeContext>, +) -> Result<(), EbpfError> { + let size = num_accounts + .saturating_mul(size_of::()) + .saturating_add(data_len); + let max_size = invoke_context + .get_bpf_compute_budget() + .max_cpi_instruction_size; + if size > max_size { + return Err(SyscallError::InstructionTooLarge(size, max_size).into()); + } + Ok(()) +} + +fn check_account_infos( + len: usize, + invoke_context: &Ref<&mut dyn InvokeContext>, +) -> Result<(), EbpfError> { + if len * size_of::() + > invoke_context + .get_bpf_compute_budget() + .max_cpi_instruction_size + { + // Cap the number of account_infos a caller can pass to approximate + // maximum that accounts that could be passed in an instruction + return Err(SyscallError::TooManyAccounts.into()); + }; + Ok(()) +} + +fn check_authorized_program( + program_id: &Pubkey, + instruction_data: &[u8], + invoke_context: &Ref<&mut dyn InvokeContext>, +) -> Result<(), EbpfError> { + if native_loader::check_id(program_id) + || bpf_loader::check_id(program_id) + || bpf_loader_deprecated::check_id(program_id) + || (bpf_loader_upgradeable::check_id(program_id) + && !(bpf_loader_upgradeable::is_upgrade_instruction(instruction_data) + || (bpf_loader_upgradeable::is_set_authority_instruction(instruction_data) + && invoke_context + .is_feature_active(&set_upgrade_authority_via_cpi_enabled::id())))) + { + return Err(SyscallError::ProgramNotSupported(*program_id).into()); + } + Ok(()) +} + +#[allow(clippy::type_complexity)] +fn get_upgradeable_executable( + callee_program_id: &Pubkey, + program_account: &Rc>, + invoke_context: &Ref<&mut dyn InvokeContext>, +) -> Result>)>, EbpfError> { + if program_account.borrow().owner() == &bpf_loader_upgradeable::id() { + match program_account.borrow().state() { Ok(UpgradeableLoaderState::Program { programdata_address, }) => { @@ -1843,942 +3050,2102 @@ fn get_upgradeable_executable( Err(SyscallError::InstructionError(InstructionError::MissingAccount).into()) } } - _ => { - ic_msg!( - invoke_context, - "Invalid upgradeable program account {}", - callee_program_id, - ); - Err(SyscallError::InstructionError(InstructionError::InvalidAccountData).into()) + _ => { + ic_msg!( + invoke_context, + "Invalid upgradeable program account {}", + callee_program_id, + ); + Err(SyscallError::InstructionError(InstructionError::InvalidAccountData).into()) + } + } + } else { + Ok(None) + } +} + +/// Call process instruction, common to both Rust and C +fn call<'a>( + syscall: &mut dyn SyscallInvokeSigned<'a>, + instruction_addr: u64, + account_infos_addr: u64, + account_infos_len: u64, + signers_seeds_addr: u64, + signers_seeds_len: u64, + memory_mapping: &MemoryMapping, +) -> Result> { + let ( + message, + executables, + accounts, + account_refs, + caller_write_privileges, + demote_sysvar_write_locks, + ) = { + let invoke_context = syscall.get_context()?; + + invoke_context + .get_compute_meter() + .consume(invoke_context.get_bpf_compute_budget().invoke_units)?; + + let enforce_aligned_host_addrs = + invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()); + + let caller_program_id = invoke_context + .get_caller() + .map_err(SyscallError::InstructionError)?; + + // Translate and verify caller's data + + let instruction = syscall.translate_instruction( + instruction_addr, + &memory_mapping, + enforce_aligned_host_addrs, + )?; + let signers = syscall.translate_signers( + caller_program_id, + signers_seeds_addr, + signers_seeds_len, + memory_mapping, + enforce_aligned_host_addrs, + )?; + let keyed_account_refs = invoke_context + .get_keyed_accounts() + .map_err(SyscallError::InstructionError)? + .iter() + .collect::>(); + let (message, callee_program_id, callee_program_id_index) = + MessageProcessor::create_message( + &instruction, + &keyed_account_refs, + &signers, + &invoke_context, + ) + .map_err(SyscallError::InstructionError)?; + let caller_write_privileges = message + .account_keys + .iter() + .map(|key| { + if let Some(keyed_account) = keyed_account_refs + .iter() + .find(|keyed_account| key == keyed_account.unsigned_key()) + { + keyed_account.is_writable() + } else { + false + } + }) + .collect::>(); + check_authorized_program(&callee_program_id, &instruction.data, &invoke_context)?; + let (accounts, account_refs) = syscall.translate_accounts( + &message.account_keys, + &caller_write_privileges, + callee_program_id_index, + account_infos_addr, + account_infos_len, + memory_mapping, + )?; + + // Construct executables + + let program_account = accounts + .get(callee_program_id_index) + .ok_or_else(|| { + ic_msg!(invoke_context, "Unknown program {}", callee_program_id,); + SyscallError::InstructionError(InstructionError::MissingAccount) + })? + .clone(); + let programdata_executable = + get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?; + let mut executables = vec![(callee_program_id, program_account)]; + if let Some(executable) = programdata_executable { + executables.push(executable); + } + + // Record the instruction + + invoke_context.record_instruction(&instruction); + + ( + message, + executables, + accounts, + account_refs, + caller_write_privileges, + invoke_context.is_feature_active(&demote_sysvar_write_locks::id()), + ) + }; + + // Process instruction + + #[allow(clippy::deref_addrof)] + match MessageProcessor::process_cross_program_instruction( + &message, + &executables, + &accounts, + &caller_write_privileges, + *(&mut *(syscall.get_context_mut()?)), + ) { + Ok(()) => (), + Err(err) => { + return Err(SyscallError::InstructionError(err).into()); + } + } + + // Copy results back to caller + { + let invoke_context = syscall.get_context()?; + for (i, (account, account_ref)) in accounts.iter().zip(account_refs).enumerate() { + let account = account.borrow(); + if let Some(mut account_ref) = account_ref { + if message.is_writable(i, demote_sysvar_write_locks) && !account.executable() { + *account_ref.lamports = account.lamports(); + *account_ref.owner = *account.owner(); + if account_ref.data.len() != account.data().len() { + if !account_ref.data.is_empty() { + // Only support for `CreateAccount` at this time. + // Need a way to limit total realloc size across multiple CPI calls + ic_msg!( + invoke_context, + "Inner instructions do not support realloc, only SystemProgram::CreateAccount", + ); + return Err(SyscallError::InstructionError( + InstructionError::InvalidRealloc, + ) + .into()); + } + if account.data().len() + > account_ref.data.len() + MAX_PERMITTED_DATA_INCREASE + { + ic_msg!( + invoke_context, + "SystemProgram::CreateAccount data size limited to {} in inner instructions", + MAX_PERMITTED_DATA_INCREASE + ); + return Err(SyscallError::InstructionError( + InstructionError::InvalidRealloc, + ) + .into()); + } + if invoke_context.is_feature_active(&update_data_on_realloc::id()) { + account_ref.data = translate_slice_mut::( + memory_mapping, + account_ref.vm_data_addr, + account.data().len() as u64, + &bpf_loader_deprecated::id(), // Don't care since it is byte aligned + true, + )?; + } else { + let _ = translate( + memory_mapping, + AccessType::Store, + account_ref.vm_data_addr, + account.data().len() as u64, + )?; + } + *account_ref.ref_to_len_in_vm = account.data().len() as u64; + *account_ref.serialized_len_ptr = account.data().len() as u64; + } + account_ref + .data + .copy_from_slice(&account.data()[0..account_ref.data.len()]); + } + } + } + } + + Ok(SUCCESS) +} + +#[cfg(test)] +mod tests { + use super::*; + use solana_rbpf::{ + ebpf::HOST_ALIGN, memory_region::MemoryRegion, user_error::UserError, vm::Config, + }; + use solana_sdk::{ + bpf_loader, + fee_calculator::FeeCalculator, + hash::hashv, + process_instruction::{MockComputeMeter, MockInvokeContext, MockLogger}, + }; + use std::str::FromStr; + + const DEFAULT_CONFIG: Config = Config { + max_call_depth: 20, + stack_frame_size: 4_096, + enable_instruction_meter: true, + enable_instruction_tracing: false, + }; + + macro_rules! assert_access_violation { + ($result:expr, $va:expr, $len:expr) => { + match $result { + Err(EbpfError::AccessViolation(_, _, va, len, _)) if $va == va && len == len => (), + _ => panic!(), + } + }; + } + + #[test] + fn test_translate() { + const START: u64 = 100; + const LENGTH: u64 = 1000; + let data = vec![0u8; LENGTH as usize]; + let addr = data.as_ptr() as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion::new_from_slice(&data, START, 0, false)], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let cases = vec![ + (true, START, 0, addr), + (true, START, 1, addr), + (true, START, LENGTH, addr), + (true, START + 1, LENGTH - 1, addr + 1), + (false, START + 1, LENGTH, 0), + (true, START + LENGTH - 1, 1, addr + LENGTH - 1), + (true, START + LENGTH, 0, addr + LENGTH), + (false, START + LENGTH, 1, 0), + (false, START, LENGTH + 1, 0), + (false, 0, 0, 0), + (false, 0, 1, 0), + (false, START - 1, 0, 0), + (false, START - 1, 1, 0), + (true, START + LENGTH / 2, LENGTH / 2, addr + LENGTH / 2), + ]; + for (ok, start, length, value) in cases { + if ok { + assert_eq!( + translate(&memory_mapping, AccessType::Load, start, length).unwrap(), + value + ) + } else { + assert!(translate(&memory_mapping, AccessType::Load, start, length).is_err()) + } + } + } + + #[test] + fn test_translate_type() { + // Pubkey + let pubkey = solana_sdk::pubkey::new_rand(); + let addr = &pubkey as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + let translated_pubkey = + translate_type::(&memory_mapping, 100, &bpf_loader::id(), true).unwrap(); + assert_eq!(pubkey, *translated_pubkey); + + // Instruction + let instruction = Instruction::new_with_bincode( + solana_sdk::pubkey::new_rand(), + &"foobar", + vec![AccountMeta::new(solana_sdk::pubkey::new_rand(), false)], + ); + let addr = &instruction as *const _ as u64; + let mut memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + let translated_instruction = + translate_type::(&memory_mapping, 96, &bpf_loader::id(), true).unwrap(); + assert_eq!(instruction, *translated_instruction); + memory_mapping.resize_region::(0, 1).unwrap(); + assert!( + translate_type::(&memory_mapping, 100, &bpf_loader::id(), true).is_err() + ); + } + + #[test] + fn test_translate_slice() { + // zero len + let good_data = vec![1u8, 2, 3, 4, 5]; + let data: Vec = vec![]; + assert_eq!(0x1 as *const u8, data.as_ptr()); + let addr = good_data.as_ptr() as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: good_data.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + let translated_data = translate_slice::( + &memory_mapping, + data.as_ptr() as u64, + 0, + &bpf_loader::id(), + true, + ) + .unwrap(); + assert_eq!(data, translated_data); + assert_eq!(0, translated_data.len()); + + // u8 + let mut data = vec![1u8, 2, 3, 4, 5]; + let addr = data.as_ptr() as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: data.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + let translated_data = translate_slice::( + &memory_mapping, + 100, + data.len() as u64, + &bpf_loader::id(), + true, + ) + .unwrap(); + assert_eq!(data, translated_data); + data[0] = 10; + assert_eq!(data, translated_data); + assert!(translate_slice::( + &memory_mapping, + data.as_ptr() as u64, + u64::MAX, + &bpf_loader::id(), + true, + ) + .is_err()); + + assert!(translate_slice::( + &memory_mapping, + 100 - 1, + data.len() as u64, + &bpf_loader::id(), + true, + ) + .is_err()); + + // u64 + let mut data = vec![1u64, 2, 3, 4, 5]; + let addr = data.as_ptr() as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 96, + len: (data.len() * size_of::()) as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + let translated_data = translate_slice::( + &memory_mapping, + 96, + data.len() as u64, + &bpf_loader::id(), + true, + ) + .unwrap(); + assert_eq!(data, translated_data); + data[0] = 10; + assert_eq!(data, translated_data); + assert!( + translate_slice::(&memory_mapping, 96, u64::MAX, &bpf_loader::id(), true,) + .is_err() + ); + + // Pubkeys + let mut data = vec![solana_sdk::pubkey::new_rand(); 5]; + let addr = data.as_ptr() as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: (data.len() * std::mem::size_of::()) as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + let translated_data = translate_slice::( + &memory_mapping, + 100, + data.len() as u64, + &bpf_loader::id(), + true, + ) + .unwrap(); + assert_eq!(data, translated_data); + data[0] = solana_sdk::pubkey::new_rand(); // Both should point to same place + assert_eq!(data, translated_data); + } + + #[test] + fn test_translate_string_and_do() { + let string = "Gaggablaghblagh!"; + let addr = string.as_ptr() as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: string.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + assert_eq!( + 42, + translate_string_and_do( + &memory_mapping, + 100, + string.len() as u64, + &bpf_loader::id(), + true, + &mut |string: &str| { + assert_eq!(string, "Gaggablaghblagh!"); + Ok(42) + } + ) + .unwrap() + ); + } + + #[test] + #[should_panic(expected = "UserError(SyscallError(Abort))")] + fn test_syscall_abort() { + let memory_mapping = + MemoryMapping::new::(vec![MemoryRegion::default()], &DEFAULT_CONFIG) + .unwrap(); + let mut result: Result> = Ok(0); + SyscallAbort::call( + &mut SyscallAbort {}, + 0, + 0, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); + } + + #[test] + #[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")] + fn test_syscall_sol_panic() { + let string = "Gaggablaghblagh!"; + let addr = string.as_ptr() as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: string.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: string.len() as u64 - 1, + })); + let mut syscall_panic = SyscallPanic { + compute_meter, + loader_id: &bpf_loader::id(), + enforce_aligned_host_addrs: true, + }; + let mut result: Result> = Ok(0); + syscall_panic.call( + 100, + string.len() as u64, + 42, + 84, + 0, + &memory_mapping, + &mut result, + ); + assert_eq!( + Err(EbpfError::UserError(BpfError::SyscallError( + SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) + ))), + result + ); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: string.len() as u64, + })); + let mut syscall_panic = SyscallPanic { + compute_meter, + loader_id: &bpf_loader::id(), + enforce_aligned_host_addrs: true, + }; + let mut result: Result> = Ok(0); + syscall_panic.call( + 100, + string.len() as u64, + 42, + 84, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); + } + + #[test] + fn test_syscall_sol_log() { + let string = "Gaggablaghblagh!"; + let addr = string.as_ptr() as *const _ as u64; + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { remaining: 1000000 })); + let log = Rc::new(RefCell::new(vec![])); + let logger: Rc> = + Rc::new(RefCell::new(MockLogger { log: log.clone() })); + let mut syscall_sol_log = SyscallLog { + compute_meter, + logger, + loader_id: &bpf_loader::id(), + enforce_aligned_host_addrs: true, + }; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: string.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); + assert_eq!(log.borrow().len(), 1); + assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!"); + + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 101, // AccessViolation + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, 101, string.len() as u64); + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64 * 2, // AccessViolation + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, 100, string.len() as u64 * 2); + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (string.len() as u64 * 2) - 1, + })); + let logger: Rc> = Rc::new(RefCell::new(MockLogger { log })); + let mut syscall_sol_log = SyscallLog { + compute_meter, + logger, + loader_id: &bpf_loader::id(), + enforce_aligned_host_addrs: true, + }; + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_eq!( + Err(EbpfError::UserError(BpfError::SyscallError( + SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) + ))), + result + ); + } + + #[test] + fn test_syscall_sol_log_u64() { + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: std::u64::MAX, + })); + let log = Rc::new(RefCell::new(vec![])); + let logger: Rc> = + Rc::new(RefCell::new(MockLogger { log: log.clone() })); + let mut syscall_sol_log_u64 = SyscallLogU64 { + cost: 0, + compute_meter, + logger, + }; + let memory_mapping = MemoryMapping::new::(vec![], &DEFAULT_CONFIG).unwrap(); + + let mut result: Result> = Ok(0); + syscall_sol_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result); + result.unwrap(); + + assert_eq!(log.borrow().len(), 1); + assert_eq!(log.borrow()[0], "Program log: 0x1, 0x2, 0x3, 0x4, 0x5"); + } + + #[test] + fn test_syscall_sol_pubkey() { + let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap(); + let addr = &pubkey.as_ref()[0] as *const _ as u64; + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { remaining: 2 })); + let log = Rc::new(RefCell::new(vec![])); + let logger: Rc> = + Rc::new(RefCell::new(MockLogger { log: log.clone() })); + let mut syscall_sol_pubkey = SyscallLogPubkey { + cost: 1, + compute_meter, + logger, + loader_id: &bpf_loader::id(), + enforce_aligned_host_addrs: true, + }; + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: addr, + vm_addr: 100, + len: 32, + vm_gap_shift: 63, + is_writable: false, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + assert_eq!(log.borrow().len(), 1); + assert_eq!( + log.borrow()[0], + "Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN" + ); + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call( + 101, // AccessViolation + 32, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, 101, 32); + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call(100, 32, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!( + Err(EbpfError::UserError(BpfError::SyscallError( + SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) + ))), + result + ); + } + + #[test] + fn test_syscall_sol_alloc_free() { + // large alloc + { + let heap = AlignedMemory::new(100, HOST_ALIGN); + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion::new_from_slice( + heap.as_slice(), + MM_HEAP_START, + 0, + true, + )], + &DEFAULT_CONFIG, + ) + .unwrap(); + let mut syscall = SyscallAllocFree { + aligned: true, + allocator: BpfAllocator::new(heap, MM_HEAP_START), + }; + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_ne!(result.unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(u64::MAX, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); + } + // many small unaligned allocs + { + let heap = AlignedMemory::new(100, HOST_ALIGN); + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion::new_from_slice( + heap.as_slice(), + MM_HEAP_START, + 0, + true, + )], + &DEFAULT_CONFIG, + ) + .unwrap(); + let mut syscall = SyscallAllocFree { + aligned: false, + allocator: BpfAllocator::new(heap, MM_HEAP_START), + }; + for _ in 0..100 { + let mut result: Result> = Ok(0); + syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_ne!(result.unwrap(), 0); + } + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); + } + // many small aligned allocs + { + let heap = AlignedMemory::new(100, HOST_ALIGN); + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion::new_from_slice( + heap.as_slice(), + MM_HEAP_START, + 0, + true, + )], + &DEFAULT_CONFIG, + ) + .unwrap(); + let mut syscall = SyscallAllocFree { + aligned: true, + allocator: BpfAllocator::new(heap, MM_HEAP_START), + }; + for _ in 0..12 { + let mut result: Result> = Ok(0); + syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_ne!(result.unwrap(), 0); } + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); } - } else { - Ok(None) + // aligned allocs + + fn check_alignment() { + let heap = AlignedMemory::new(100, HOST_ALIGN); + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion::new_from_slice( + heap.as_slice(), + MM_HEAP_START, + 0, + true, + )], + &DEFAULT_CONFIG, + ) + .unwrap(); + let mut syscall = SyscallAllocFree { + aligned: true, + allocator: BpfAllocator::new(heap, MM_HEAP_START), + }; + let mut result: Result> = Ok(0); + syscall.call( + size_of::() as u64, + 0, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + let address = result.unwrap(); + assert_ne!(address, 0); + assert_eq!((address as *const u8).align_offset(align_of::()), 0); + } + check_alignment::(); + check_alignment::(); + check_alignment::(); + check_alignment::(); + check_alignment::(); } -} -/// Call process instruction, common to both Rust and C -fn call<'a>( - syscall: &mut dyn SyscallInvokeSigned<'a>, - instruction_addr: u64, - account_infos_addr: u64, - account_infos_len: u64, - signers_seeds_addr: u64, - signers_seeds_len: u64, - memory_mapping: &MemoryMapping, -) -> Result> { - let ( - message, - executables, - accounts, - account_refs, - caller_write_privileges, - demote_sysvar_write_locks, - ) = { - let invoke_context = syscall.get_context()?; + #[test] + fn test_syscall_sha256() { + let bytes1 = "Gaggablaghblagh!"; + let bytes2 = "flurbos"; - invoke_context - .get_compute_meter() - .consume(invoke_context.get_bpf_compute_budget().invoke_units)?; + struct MockSlice { + pub addr: u64, + pub len: usize, + } + let mock_slice1 = MockSlice { + addr: 4096, + len: bytes1.len(), + }; + let mock_slice2 = MockSlice { + addr: 8192, + len: bytes2.len(), + }; + let bytes_to_hash = [mock_slice1, mock_slice2]; + let hash_result = [0; HASH_BYTES]; + let ro_len = bytes_to_hash.len() as u64; + let ro_va = 96; + let rw_va = 192; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bytes1.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: bytes1.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bytes2.as_ptr() as *const _ as u64, + vm_addr: 8192, + len: bytes2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bytes_to_hash.as_ptr() as *const _ as u64, + vm_addr: 96, + len: 32, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: hash_result.as_ptr() as *const _ as u64, + vm_addr: rw_va, + len: HASH_BYTES as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (bytes1.len() + bytes2.len()) as u64, + })); + let mut syscall = SyscallSha256 { + sha256_base_cost: 0, + sha256_byte_cost: 2, + compute_meter, + loader_id: &bpf_loader_deprecated::id(), + enforce_aligned_host_addrs: true, + }; - let enforce_aligned_host_addrs = - invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()); + let mut result: Result> = Ok(0); + syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + + let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes(); + assert_eq!(hash_result, hash_local); + let mut result: Result> = Ok(0); + syscall.call( + ro_va - 1, // AccessViolation + ro_len, + rw_va, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, ro_va - 1, ro_len); + let mut result: Result> = Ok(0); + syscall.call( + ro_va, + ro_len + 1, // AccessViolation + rw_va, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, ro_va, ro_len + 1); + let mut result: Result> = Ok(0); + syscall.call( + ro_va, + ro_len, + rw_va - 1, // AccessViolation + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64); - let caller_program_id = invoke_context - .get_caller() - .map_err(SyscallError::InstructionError)?; + syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result); + assert_eq!( + Err(EbpfError::UserError(BpfError::SyscallError( + SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) + ))), + result + ); + } - // Translate and verify caller's data + #[test] + fn test_syscall_get_sysvar() { + // Test clock sysvar + { + let got_clock = Clock::default(); + let got_clock_va = 2048; - let instruction = syscall.translate_instruction( - instruction_addr, - &memory_mapping, - enforce_aligned_host_addrs, - )?; - let signers = syscall.translate_signers( - caller_program_id, - signers_seeds_addr, - signers_seeds_len, - memory_mapping, - enforce_aligned_host_addrs, - )?; - let keyed_account_refs = invoke_context - .get_keyed_accounts() - .map_err(SyscallError::InstructionError)? - .iter() - .collect::>(); - let (message, callee_program_id, callee_program_id_index) = - MessageProcessor::create_message( - &instruction, - &keyed_account_refs, - &signers, - &invoke_context, + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: &got_clock as *const _ as u64, + vm_addr: got_clock_va, + len: size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }], + &DEFAULT_CONFIG, ) - .map_err(SyscallError::InstructionError)?; - let caller_write_privileges = message - .account_keys - .iter() - .map(|key| { - if let Some(keyed_account) = keyed_account_refs - .iter() - .find(|keyed_account| key == keyed_account.unsigned_key()) - { - keyed_account.is_writable() - } else { - false - } - }) - .collect::>(); - check_authorized_program(&callee_program_id, &instruction.data, &invoke_context)?; - let (accounts, account_refs) = syscall.translate_accounts( - &message.account_keys, - &caller_write_privileges, - callee_program_id_index, - account_infos_addr, - account_infos_len, - memory_mapping, - )?; + .unwrap(); - // Construct executables + let src_clock = Clock { + slot: 1, + epoch_start_timestamp: 2, + epoch: 3, + leader_schedule_epoch: 4, + unix_timestamp: 5, + }; + let mut invoke_context = MockInvokeContext::new(vec![]); + let mut data = vec![]; + bincode::serialize_into(&mut data, &src_clock).unwrap(); + invoke_context + .sysvars + .push((sysvar::clock::id(), Some(Rc::new(data)))); - let program_account = accounts - .get(callee_program_id_index) - .ok_or_else(|| { - ic_msg!(invoke_context, "Unknown program {}", callee_program_id,); - SyscallError::InstructionError(InstructionError::MissingAccount) - })? - .clone(); - let programdata_executable = - get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?; - let mut executables = vec![(callee_program_id, program_account)]; - if let Some(executable) = programdata_executable { - executables.push(executable); + let mut syscall = SyscallGetClockSysvar { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + + syscall.call(got_clock_va, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + assert_eq!(got_clock, src_clock); } - // Record the instruction + // Test epoch_schedule sysvar + { + let got_epochschedule = EpochSchedule::default(); + let got_epochschedule_va = 2048; - invoke_context.record_instruction(&instruction); + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: &got_epochschedule as *const _ as u64, + vm_addr: got_epochschedule_va, + len: size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); - ( - message, - executables, - accounts, - account_refs, - caller_write_privileges, - invoke_context.is_feature_active(&demote_sysvar_write_locks::id()), - ) - }; + let src_epochschedule = EpochSchedule { + slots_per_epoch: 1, + leader_schedule_slot_offset: 2, + warmup: false, + first_normal_epoch: 3, + first_normal_slot: 4, + }; + let mut invoke_context = MockInvokeContext::new(vec![]); + let mut data = vec![]; + bincode::serialize_into(&mut data, &src_epochschedule).unwrap(); + invoke_context + .sysvars + .push((sysvar::epoch_schedule::id(), Some(Rc::new(data)))); - // Process instruction + let mut syscall = SyscallGetEpochScheduleSysvar { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); - #[allow(clippy::deref_addrof)] - match MessageProcessor::process_cross_program_instruction( - &message, - &executables, - &accounts, - &caller_write_privileges, - *(&mut *(syscall.get_context_mut()?)), - ) { - Ok(()) => (), - Err(err) => { - return Err(SyscallError::InstructionError(err).into()); + syscall.call( + got_epochschedule_va, + 0, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); + assert_eq!(got_epochschedule, src_epochschedule); } - } - // Copy results back to caller - { - let invoke_context = syscall.get_context()?; - for (i, (account, account_ref)) in accounts.iter().zip(account_refs).enumerate() { - let account = account.borrow(); - if let Some(mut account_ref) = account_ref { - if message.is_writable(i, demote_sysvar_write_locks) && !account.executable() { - *account_ref.lamports = account.lamports(); - *account_ref.owner = *account.owner(); - if account_ref.data.len() != account.data().len() { - if !account_ref.data.is_empty() { - // Only support for `CreateAccount` at this time. - // Need a way to limit total realloc size across multiple CPI calls - ic_msg!( - invoke_context, - "Inner instructions do not support realloc, only SystemProgram::CreateAccount", - ); - return Err(SyscallError::InstructionError( - InstructionError::InvalidRealloc, - ) - .into()); - } - if account.data().len() - > account_ref.data.len() + MAX_PERMITTED_DATA_INCREASE - { - ic_msg!( - invoke_context, - "SystemProgram::CreateAccount data size limited to {} in inner instructions", - MAX_PERMITTED_DATA_INCREASE - ); - return Err(SyscallError::InstructionError( - InstructionError::InvalidRealloc, - ) - .into()); - } - if invoke_context.is_feature_active(&update_data_on_realloc::id()) { - account_ref.data = translate_slice_mut::( - memory_mapping, - account_ref.vm_data_addr, - account.data().len() as u64, - &bpf_loader_deprecated::id(), // Don't care since it is byte aligned - true, - )?; - } else { - let _ = translate( - memory_mapping, - AccessType::Store, - account_ref.vm_data_addr, - account.data().len() as u64, - )?; - } - *account_ref.ref_to_len_in_vm = account.data().len() as u64; - *account_ref.serialized_len_ptr = account.data().len() as u64; - } - account_ref - .data - .copy_from_slice(&account.data()[0..account_ref.data.len()]); - } - } - } - } + // Test fees sysvar + { + let got_fees = Fees::default(); + let got_fees_va = 2048; + + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: &got_fees as *const _ as u64, + vm_addr: got_fees_va, + len: size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); - Ok(SUCCESS) -} + let src_fees = Fees { + fee_calculator: FeeCalculator { + lamports_per_signature: 1, + }, + }; + let mut invoke_context = MockInvokeContext::new(vec![]); + let mut data = vec![]; + bincode::serialize_into(&mut data, &src_fees).unwrap(); + invoke_context + .sysvars + .push((sysvar::fees::id(), Some(Rc::new(data)))); -#[cfg(test)] -mod tests { - use super::*; - use solana_rbpf::{ - ebpf::HOST_ALIGN, memory_region::MemoryRegion, user_error::UserError, vm::Config, - }; - use solana_sdk::{ - bpf_loader, - fee_calculator::FeeCalculator, - hash::hashv, - process_instruction::{MockComputeMeter, MockInvokeContext, MockLogger}, - }; - use std::str::FromStr; + let mut syscall = SyscallGetFeesSysvar { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); - const DEFAULT_CONFIG: Config = Config { - max_call_depth: 20, - stack_frame_size: 4_096, - enable_instruction_meter: true, - enable_instruction_tracing: false, - }; + syscall.call(got_fees_va, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + assert_eq!(got_fees, src_fees); + } - macro_rules! assert_access_violation { - ($result:expr, $va:expr, $len:expr) => { - match $result { - Err(EbpfError::AccessViolation(_, _, va, len, _)) if $va == va && len == len => (), - _ => panic!(), - } - }; - } + // Test rent sysvar + { + let got_rent = Rent::default(); + let got_rent_va = 2048; - #[test] - fn test_translate() { - const START: u64 = 100; - const LENGTH: u64 = 1000; - let data = vec![0u8; LENGTH as usize]; - let addr = data.as_ptr() as u64; - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion::new_from_slice(&data, START, 0, false)], - &DEFAULT_CONFIG, - ) - .unwrap(); + let memory_mapping = MemoryMapping::new::( + vec![MemoryRegion { + host_addr: &got_rent as *const _ as u64, + vm_addr: got_rent_va, + len: size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }], + &DEFAULT_CONFIG, + ) + .unwrap(); - let cases = vec![ - (true, START, 0, addr), - (true, START, 1, addr), - (true, START, LENGTH, addr), - (true, START + 1, LENGTH - 1, addr + 1), - (false, START + 1, LENGTH, 0), - (true, START + LENGTH - 1, 1, addr + LENGTH - 1), - (true, START + LENGTH, 0, addr + LENGTH), - (false, START + LENGTH, 1, 0), - (false, START, LENGTH + 1, 0), - (false, 0, 0, 0), - (false, 0, 1, 0), - (false, START - 1, 0, 0), - (false, START - 1, 1, 0), - (true, START + LENGTH / 2, LENGTH / 2, addr + LENGTH / 2), - ]; - for (ok, start, length, value) in cases { - if ok { - assert_eq!( - translate(&memory_mapping, AccessType::Load, start, length).unwrap(), - value - ) - } else { - assert!(translate(&memory_mapping, AccessType::Load, start, length).is_err()) - } + let src_rent = Rent { + lamports_per_byte_year: 1, + exemption_threshold: 2.0, + burn_percent: 3, + }; + let mut invoke_context = MockInvokeContext::new(vec![]); + let mut data = vec![]; + bincode::serialize_into(&mut data, &src_rent).unwrap(); + invoke_context + .sysvars + .push((sysvar::rent::id(), Some(Rc::new(data)))); + + let mut syscall = SyscallGetRentSysvar { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + + syscall.call(got_rent_va, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + assert_eq!(got_rent, src_rent); } } - #[test] - fn test_translate_type() { - // Pubkey - let pubkey = solana_sdk::pubkey::new_rand(); - let addr = &pubkey as *const _ as u64; + // Bignum testing convenience functions + // Creates new empty big_num + fn new_bignum() -> u64 { + let mut bn = 0u64; + let bn_addr = &mut bn as *mut _ as u64; let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }], - &DEFAULT_CONFIG, - ) - .unwrap(); - let translated_pubkey = - translate_type::(&memory_mapping, 100, &bpf_loader::id(), true).unwrap(); - assert_eq!(pubkey, *translated_pubkey); - - // Instruction - let instruction = Instruction::new_with_bincode( - solana_sdk::pubkey::new_rand(), - &"foobar", - vec![AccountMeta::new(solana_sdk::pubkey::new_rand(), false)], - ); - let addr = &instruction as *const _ as u64; - let mut memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, + host_addr: bn_addr, vm_addr: 96, - len: std::mem::size_of::() as u64, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }], &DEFAULT_CONFIG, ) .unwrap(); - let translated_instruction = - translate_type::(&memory_mapping, 96, &bpf_loader::id(), true).unwrap(); - assert_eq!(instruction, *translated_instruction); - memory_mapping.resize_region::(0, 1).unwrap(); - assert!( - translate_type::(&memory_mapping, 100, &bpf_loader::id(), true).is_err() - ); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumNew { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(96, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + bn } - #[test] - fn test_translate_slice() { - // zero len - let good_data = vec![1u8, 2, 3, 4, 5]; - let data: Vec = vec![]; - assert_eq!(0x1 as *const u8, data.as_ptr()); - let addr = good_data.as_ptr() as *const _ as u64; + // creates new bignum with u32 value + fn new_u32_bignum(val: u32) -> u64 { + let mut bn = 0u64; + let bn_addr = &mut bn as *mut _ as u64; let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: good_data.len() as u64, + host_addr: bn_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }], &DEFAULT_CONFIG, ) .unwrap(); - let translated_data = translate_slice::( - &memory_mapping, - data.as_ptr() as u64, - 0, - &bpf_loader::id(), - true, - ) - .unwrap(); - assert_eq!(data, translated_data); - assert_eq!(0, translated_data.len()); - // u8 - let mut data = vec![1u8, 2, 3, 4, 5]; - let addr = data.as_ptr() as *const _ as u64; + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumFromU32 { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(96, val as u64, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + bn + } + // creates new bignum with bytes array + fn new_bytes_bignum(val_array: &[u8]) -> u64 { + let mut bn = 0u64; + let bn_addr = &mut bn as *mut _ as u64; + let val_len = val_array.len(); let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: data.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }], + vec![ + MemoryRegion { + host_addr: bn_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: val_array.as_ptr() as *const _ as u64, + vm_addr: 8, + len: val_len as u64, + vm_gap_shift: 63, + is_writable: false, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); - let translated_data = translate_slice::( - &memory_mapping, - 100, - data.len() as u64, - &bpf_loader::id(), - true, + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumFromBytes { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(96, 8, val_len as u64, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + bn + } + #[test] + fn test_syscall_bignum_new() { + let bn = new_bignum(); + let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + println!("New BigNum with 0 {:?}", braw); + } + + #[test] + fn test_syscall_bignum_from_u32() { + let bn = new_u32_bignum(20u32); + let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + println!("Reconst {:?}", braw); + } + #[test] + fn test_syscall_bignum_from_bytes() { + let val = [0u8, 0u8, 1u8, 0u8]; + let bn = new_bytes_bignum(&val); + let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + println!("Reconst {:?}", braw); + } + #[test] + fn test_syscall_bignum_to_bytes() { + let val = [0u8, 0u8, 1u8, 0u8]; + let mut bn = new_bytes_bignum(&val); + let bn_addr = &mut bn as *mut _ as u64; + let bytes_buf = [0u8; 256]; + let mut bytes_len = bytes_buf.len(); + let bytes_len_addr = &mut bytes_len as *mut _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_addr, + vm_addr: 1024, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bytes_buf.as_ptr() as *const _ as u64, + vm_addr: 8, + len: bytes_len as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: bytes_len_addr, + vm_addr: 2048, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, ) .unwrap(); - assert_eq!(data, translated_data); - data[0] = 10; - assert_eq!(data, translated_data); - assert!(translate_slice::( - &memory_mapping, - data.as_ptr() as u64, - u64::MAX, - &bpf_loader::id(), - true, - ) - .is_err()); - assert!(translate_slice::( - &memory_mapping, - 100 - 1, - data.len() as u64, - &bpf_loader::id(), - true, - ) - .is_err()); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumToBytes { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(1024, 8, 2048, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + let resb = bytes_buf[0..bytes_len].to_vec(); + assert_eq!(1, resb[0]); + } + + #[test] + fn test_syscall_bignum_mod_exp() { + let mut bn = 0u64; + let bn_addr = &mut bn as *mut _ as u64; + + let bn_self_ptr = new_u32_bignum(2); + let bn_exponent_ptr = new_u32_bignum(3); + let bn_modulus_ptr = new_u32_bignum(7); + + let bn_self_addr = &bn_self_ptr as *const _ as u64; + let bn_exponent_addr = &bn_exponent_ptr as *const _ as u64; + let bn_modulus_addr = &bn_modulus_ptr as *const _ as u64; - // u64 - let mut data = vec![1u64, 2, 3, 4, 5]; - let addr = data.as_ptr() as *const _ as u64; let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, - vm_addr: 96, - len: (data.len() * size_of::()) as u64, - vm_gap_shift: 63, - is_writable: false, - }], + vec![ + MemoryRegion { + host_addr: bn_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: bn_self_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_exponent_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_modulus_addr, + vm_addr: 24, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); - let translated_data = translate_slice::( - &memory_mapping, - 96, - data.len() as u64, - &bpf_loader::id(), - true, - ) - .unwrap(); - assert_eq!(data, translated_data); - data[0] = 10; - assert_eq!(data, translated_data); - assert!( - translate_slice::(&memory_mapping, 96, u64::MAX, &bpf_loader::id(), true,) - .is_err() - ); - // Pubkeys - let mut data = vec![solana_sdk::pubkey::new_rand(); 5]; - let addr = data.as_ptr() as *const _ as u64; + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumModExp { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(96, 8, 16, 24, 0, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + println!("Reconst {:?}", braw); + } + + #[test] + fn test_syscall_bignum_add() { + let mut sum = 0u64; + let sum_addr = &mut sum as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(2); + let bn_3_ptr = new_u32_bignum(3); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_addr = &bn_3_ptr as *const _ as u64; let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: (data.len() * std::mem::size_of::()) as u64, - vm_gap_shift: 63, - is_writable: false, - }], + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: sum_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); - let translated_data = translate_slice::( - &memory_mapping, - 100, - data.len() as u64, - &bpf_loader::id(), - true, + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumAdd { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(sum as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(5).unwrap()); + // println!("2+3 = {:?}", braw); + } + #[test] + fn test_syscall_bignum_sub() { + let mut diff = 0u64; + let diff_addr = &mut diff as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(2); + let bn_3_ptr = new_u32_bignum(3); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_addr = &bn_3_ptr as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: diff_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, ) .unwrap(); - assert_eq!(data, translated_data); - data[0] = solana_sdk::pubkey::new_rand(); // Both should point to same place - assert_eq!(data, translated_data); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumSub { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(diff as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_dec_str("-1").unwrap()); + // println!("2-3 = {:?}", braw); } - #[test] - fn test_translate_string_and_do() { - let string = "Gaggablaghblagh!"; - let addr = string.as_ptr() as *const _ as u64; + fn test_syscall_bignum_mul() { + let mut prod = 0u64; + let prod_addr = &mut prod as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(2); + let bn_3_ptr = new_u32_bignum(3); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_addr = &bn_3_ptr as *const _ as u64; let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: string.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }], + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: prod_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); - assert_eq!( - 42, - translate_string_and_do( - &memory_mapping, - 100, - string.len() as u64, - &bpf_loader::id(), - true, - &mut |string: &str| { - assert_eq!(string, "Gaggablaghblagh!"); - Ok(42) - } - ) - .unwrap() - ); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumMul { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(prod as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(6).unwrap()); + // println!("2*3 = {:?}", braw); } - #[test] - #[should_panic(expected = "UserError(SyscallError(Abort))")] - fn test_syscall_abort() { - let memory_mapping = - MemoryMapping::new::(vec![MemoryRegion::default()], &DEFAULT_CONFIG) - .unwrap(); - let mut result: Result> = Ok(0); - SyscallAbort::call( - &mut SyscallAbort {}, - 0, - 0, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); + fn test_syscall_bignum_div() { + let mut quot = 0u64; + let quot_addr = &mut quot as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(4); + let bn_3_ptr = new_u32_bignum(2); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_addr = &bn_3_ptr as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: quot_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumDiv { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); result.unwrap(); + let braw: &BigNum = unsafe { &*(quot as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(2).unwrap()); + // println!("4/2 = {:?}", braw); } - #[test] - #[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")] - fn test_syscall_sol_panic() { - let string = "Gaggablaghblagh!"; - let addr = string.as_ptr() as *const _ as u64; + fn test_syscall_bignum_exp() { + let mut exp = 0u64; + let exp_addr = &mut exp as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(4); + let bn_3_ptr = new_u32_bignum(2); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_addr = &bn_3_ptr as *const _ as u64; let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: string.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }], + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: exp_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); - let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: string.len() as u64 - 1, + remaining: (20 + 20) as u64, })); - let mut syscall_panic = SyscallPanic { + let mut syscall = SyscallBigNumExp { + cost: 1, compute_meter, loader_id: &bpf_loader::id(), - enforce_aligned_host_addrs: true, }; let mut result: Result> = Ok(0); - syscall_panic.call( - 100, - string.len() as u64, - 42, - 84, - 0, - &memory_mapping, - &mut result, - ); - assert_eq!( - Err(EbpfError::UserError(BpfError::SyscallError( - SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) - ))), - result - ); - + syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(exp as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(16).unwrap()); + // println!("4^2 = {:?}", braw); + } + #[test] + fn test_syscall_bignum_sqr() { + let mut sqr = 0u64; + let sqr_addr = &mut sqr as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(4); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: sqr_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: string.len() as u64, + remaining: (20 + 20) as u64, })); - let mut syscall_panic = SyscallPanic { + let mut syscall = SyscallBigNumSqr { + cost: 1, compute_meter, loader_id: &bpf_loader::id(), - enforce_aligned_host_addrs: true, }; let mut result: Result> = Ok(0); - syscall_panic.call( - 100, - string.len() as u64, - 42, - 84, - 0, - &memory_mapping, - &mut result, - ); + syscall.call(8, 96, 0, 0, 0, &memory_mapping, &mut result); result.unwrap(); + let braw: &BigNum = unsafe { &*(sqr as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(16).unwrap()); + // println!("4^2 = {:?}", braw); } - #[test] - fn test_syscall_sol_log() { - let string = "Gaggablaghblagh!"; - let addr = string.as_ptr() as *const _ as u64; + fn test_syscall_bignum_mod_sqr() { + let mut mod_sqr = 0u64; + let mod_sqr_addr = &mut mod_sqr as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(15); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_ptr = new_u32_bignum(7); + let bn_3_addr = &bn_3_ptr as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: mod_sqr_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { remaining: 1000000 })); - let log = Rc::new(RefCell::new(vec![])); - let logger: Rc> = - Rc::new(RefCell::new(MockLogger { log: log.clone() })); - let mut syscall_sol_log = SyscallLog { + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumModSqr { + cost: 1, compute_meter, - logger, loader_id: &bpf_loader::id(), - enforce_aligned_host_addrs: true, }; + let mut result: Result> = Ok(0); + syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(mod_sqr as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(1).unwrap()); + // println!("(15 % 7)^2 = {:?}", braw); + } + + #[test] + fn test_syscall_bignum_mod_mul() { + let mut mod_mul = 0u64; + let mod_mul_addr = &mut mod_mul as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(3); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_ptr = new_u32_bignum(3); + let bn_3_addr = &bn_3_ptr as *const _ as u64; + let bn_4_ptr = new_u32_bignum(7); + let bn_4_addr = &bn_4_ptr as *const _ as u64; let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: string.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }], + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_4_addr, + vm_addr: 24, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: mod_mul_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); - - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 100, - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - result.unwrap(); - assert_eq!(log.borrow().len(), 1); - assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!"); - - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 101, // AccessViolation - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_access_violation!(result, 101, string.len() as u64); - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 100, - string.len() as u64 * 2, // AccessViolation - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_access_violation!(result, 100, string.len() as u64 * 2); - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 100, - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: (string.len() as u64 * 2) - 1, + remaining: (20 + 20) as u64, })); - let logger: Rc> = Rc::new(RefCell::new(MockLogger { log })); - let mut syscall_sol_log = SyscallLog { + let mut syscall = SyscallBigNumModMul { + cost: 1, compute_meter, - logger, loader_id: &bpf_loader::id(), - enforce_aligned_host_addrs: true, }; let mut result: Result> = Ok(0); - syscall_sol_log.call( - 100, - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); + syscall.call(8, 16, 24, 96, 0, &memory_mapping, &mut result); result.unwrap(); - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 100, - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_eq!( - Err(EbpfError::UserError(BpfError::SyscallError( - SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) - ))), - result - ); + let braw: &BigNum = unsafe { &*(mod_mul as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(2).unwrap()); + // println!("(3 * 3) % 7 = {:?}", braw); } - #[test] - fn test_syscall_sol_log_u64() { + #[should_panic(expected="UserError(SyscallError(BigNumberModInvError))")] + fn test_syscall_bignum_mod_inv() { + let mut mod_inv = 0u64; + let mod_inv_addr = &mut mod_inv as *mut _ as u64; + let bn_2_ptr = new_u32_bignum(3); + let bn_2_addr = &bn_2_ptr as *const _ as u64; + let bn_3_ptr = new_u32_bignum(3); + let bn_3_addr = &bn_3_ptr as *const _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_2_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_3_addr, + vm_addr: 32, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: mod_inv_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: std::u64::MAX, + remaining: (20 + 20) as u64, })); - let log = Rc::new(RefCell::new(vec![])); - let logger: Rc> = - Rc::new(RefCell::new(MockLogger { log: log.clone() })); - let mut syscall_sol_log_u64 = SyscallLogU64 { - cost: 0, + let mut syscall = SyscallBigNumModInv { + cost: 1, compute_meter, - logger, + loader_id: &bpf_loader::id(), }; - let memory_mapping = MemoryMapping::new::(vec![], &DEFAULT_CONFIG).unwrap(); - let mut result: Result> = Ok(0); - syscall_sol_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result); + syscall.call(8, 32, 96, 0, 0, &memory_mapping, &mut result); result.unwrap(); - - assert_eq!(log.borrow().len(), 1); - assert_eq!(log.borrow()[0], "Program log: 0x1, 0x2, 0x3, 0x4, 0x5"); + // let braw: &BigNum = unsafe { &*(mod_inv as *mut BigNum) }; + // println!("(9 % 7)^2 = {:?}", braw); } - #[test] - fn test_syscall_sol_pubkey() { - let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap(); - let addr = &pubkey.as_ref()[0] as *const _ as u64; + fn test_syscall_bignum_hashed_generator() { + let nonce = b"hgen_facelift"; + let mut hg = nonce.len() as u64; + let hg_addr = &mut hg as *mut _ as u64; + let nonce_addr = nonce as *const _ as u64; + let bn_u_ptr = new_u32_bignum(11); + let bn_u_addr = &bn_u_ptr as *const _ as u64; + let bn_a_ptr = new_u32_bignum(59); + let bn_a_addr = &bn_a_ptr as *const _ as u64; + let bn_n_ptr = new_u32_bignum(7); + let bn_n_addr = &bn_n_ptr as *const _ as u64; + + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_u_addr, + vm_addr: 2048, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_a_addr, + vm_addr: 4096, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_n_addr, + vm_addr: 8192, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: nonce_addr, + vm_addr: 1024, + len: nonce.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: hg_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { remaining: 2 })); - let log = Rc::new(RefCell::new(vec![])); - let logger: Rc> = - Rc::new(RefCell::new(MockLogger { log: log.clone() })); - let mut syscall_sol_pubkey = SyscallLogPubkey { + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumHg { cost: 1, compute_meter, - logger, loader_id: &bpf_loader::id(), - enforce_aligned_host_addrs: true, }; + let mut result: Result> = Ok(0); + syscall.call(2048, 4096, 8192, 1024, 96, &memory_mapping, &mut result); + result.unwrap(); + let braw: &BigNum = unsafe { &*(hg_addr as *mut BigNum) }; + assert_eq!(*braw, BigNum::from_u32(0).unwrap()); + } + #[test] + fn test_syscall_bignum_drop() { + let mut bn = new_bignum(); + let bn_addr = &mut bn as *mut _ as u64; + assert_ne!(bn, 0); + println!("After new BigNum address = {}", bn); + let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + println!("New BigNum initialized to {:?}", braw); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { - host_addr: addr, - vm_addr: 100, - len: 32, + host_addr: bn_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }], &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumDrop { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; let mut result: Result> = Ok(0); - syscall_sol_pubkey.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 0, 0, 0, 0, &memory_mapping, &mut result); result.unwrap(); - assert_eq!(log.borrow().len(), 1); - assert_eq!( - log.borrow()[0], - "Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN" - ); - let mut result: Result> = Ok(0); - syscall_sol_pubkey.call( - 101, // AccessViolation - 32, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_access_violation!(result, 101, 32); - let mut result: Result> = Ok(0); - syscall_sol_pubkey.call(100, 32, 0, 0, 0, &memory_mapping, &mut result); - assert_eq!( - Err(EbpfError::UserError(BpfError::SyscallError( - SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) - ))), - result - ); - } - - #[test] - fn test_syscall_sol_alloc_free() { - // large alloc - { - let heap = AlignedMemory::new(100, HOST_ALIGN); - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion::new_from_slice( - heap.as_slice(), - MM_HEAP_START, - 0, - true, - )], - &DEFAULT_CONFIG, - ) - .unwrap(); - let mut syscall = SyscallAllocFree { - aligned: true, - allocator: BpfAllocator::new(heap, MM_HEAP_START), - }; - let mut result: Result> = Ok(0); - syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_ne!(result.unwrap(), 0); - let mut result: Result> = Ok(0); - syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_eq!(result.unwrap(), 0); - let mut result: Result> = Ok(0); - syscall.call(u64::MAX, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_eq!(result.unwrap(), 0); - } - // many small unaligned allocs - { - let heap = AlignedMemory::new(100, HOST_ALIGN); - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion::new_from_slice( - heap.as_slice(), - MM_HEAP_START, - 0, - true, - )], - &DEFAULT_CONFIG, - ) - .unwrap(); - let mut syscall = SyscallAllocFree { - aligned: false, - allocator: BpfAllocator::new(heap, MM_HEAP_START), - }; - for _ in 0..100 { - let mut result: Result> = Ok(0); - syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_ne!(result.unwrap(), 0); - } - let mut result: Result> = Ok(0); - syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_eq!(result.unwrap(), 0); - } - // many small aligned allocs - { - let heap = AlignedMemory::new(100, HOST_ALIGN); - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion::new_from_slice( - heap.as_slice(), - MM_HEAP_START, - 0, - true, - )], - &DEFAULT_CONFIG, - ) - .unwrap(); - let mut syscall = SyscallAllocFree { - aligned: true, - allocator: BpfAllocator::new(heap, MM_HEAP_START), - }; - for _ in 0..12 { - let mut result: Result> = Ok(0); - syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_ne!(result.unwrap(), 0); - } - let mut result: Result> = Ok(0); - syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); - assert_eq!(result.unwrap(), 0); - } - // aligned allocs - - fn check_alignment() { - let heap = AlignedMemory::new(100, HOST_ALIGN); - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion::new_from_slice( - heap.as_slice(), - MM_HEAP_START, - 0, - true, - )], - &DEFAULT_CONFIG, - ) - .unwrap(); - let mut syscall = SyscallAllocFree { - aligned: true, - allocator: BpfAllocator::new(heap, MM_HEAP_START), - }; - let mut result: Result> = Ok(0); - syscall.call( - size_of::() as u64, - 0, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - let address = result.unwrap(); - assert_ne!(address, 0); - assert_eq!((address as *const u8).align_offset(align_of::()), 0); - } - check_alignment::(); - check_alignment::(); - check_alignment::(); - check_alignment::(); - check_alignment::(); + assert_eq!(bn, 0); + // println!("After drop BigNum address = {}", bn); } #[test] - fn test_syscall_sha256() { - let bytes1 = "Gaggablaghblagh!"; - let bytes2 = "flurbos"; + fn test_syscall_blake3_digest() { + let data = [7u8, 3u8, 1u8, 15u8]; + let data_len = data.len(); + let data_len_addr = &data_len as *const _ as u64; + let digest = [0u8; 32]; + let mut digest_len = digest.len(); + let digest_len_addr = &mut digest_len as *mut _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: data.as_ptr() as *const _ as u64, + vm_addr: 8, + len: data_len as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: data_len_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: digest.as_ptr() as *const _ as u64, + vm_addr: 16, + len: digest_len as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: digest_len_addr, + vm_addr: 1024, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBlake3Digest { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(8, 96, 16, 1024, 0, &memory_mapping, &mut result); + result.unwrap(); + let resb = digest[0..digest_len].to_vec(); + assert_eq!( + resb, + vec![ + 19, 245, 57, 187, 33, 163, 77, 67, 98, 172, 159, 13, 83, 252, 212, 176, 31, 81, + 186, 58, 239, 119, 15, 13, 212, 68, 167, 226, 233, 141, 216, 51 + ] + ); + // println!("This is result {:?}", resb); + } + #[test] + fn test_syscall_bignum_hash_to_prime() { + let nonce = b"hash_to_prime"; + let mut htp = nonce.len() as u64; + let htp_addr = &mut htp as *mut _ as u64; + let nonce_addr = nonce as *const _ as u64; + let bn_u_ptr = new_u32_bignum(11); + let bn_u_addr = &bn_u_ptr as *const _ as u64; + let bn_a_ptr = new_u32_bignum(59); + let bn_a_addr = &bn_a_ptr as *const _ as u64; + let bn_z_ptr = new_u32_bignum(7); + let bn_z_addr = &bn_z_ptr as *const _ as u64; - struct MockSlice { - pub addr: u64, - pub len: usize, - } - let mock_slice1 = MockSlice { - addr: 4096, - len: bytes1.len(), - }; - let mock_slice2 = MockSlice { - addr: 8192, - len: bytes2.len(), - }; - let bytes_to_hash = [mock_slice1, mock_slice2]; - let hash_result = [0; HASH_BYTES]; - let ro_len = bytes_to_hash.len() as u64; - let ro_va = 96; - let rw_va = 192; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bytes1.as_ptr() as *const _ as u64, + host_addr: bn_u_addr, + vm_addr: 2048, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bn_a_addr, vm_addr: 4096, - len: bytes1.len() as u64, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bytes2.as_ptr() as *const _ as u64, + host_addr: bn_z_addr, vm_addr: 8192, - len: bytes2.len() as u64, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bytes_to_hash.as_ptr() as *const _ as u64, - vm_addr: 96, - len: 32, + host_addr: nonce_addr, + vm_addr: 1024, + len: nonce.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: hash_result.as_ptr() as *const _ as u64, - vm_addr: rw_va, - len: HASH_BYTES as u64, + host_addr: htp_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, }, @@ -2788,237 +5155,24 @@ mod tests { .unwrap(); let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: (bytes1.len() + bytes2.len()) as u64, + remaining: 10_000 as u64, })); - let mut syscall = SyscallSha256 { - sha256_base_cost: 0, - sha256_byte_cost: 2, + let mut syscall = SyscallBigNumberHashToPrime { + cost: 1, compute_meter, - loader_id: &bpf_loader_deprecated::id(), - enforce_aligned_host_addrs: true, + loader_id: &bpf_loader::id(), }; - let mut result: Result> = Ok(0); - syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result); + syscall.call(2048, 4096, 8192, 1024, 96, &memory_mapping, &mut result); result.unwrap(); - - let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes(); - assert_eq!(hash_result, hash_local); - let mut result: Result> = Ok(0); - syscall.call( - ro_va - 1, // AccessViolation - ro_len, - rw_va, - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_access_violation!(result, ro_va - 1, ro_len); - let mut result: Result> = Ok(0); - syscall.call( - ro_va, - ro_len + 1, // AccessViolation - rw_va, - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_access_violation!(result, ro_va, ro_len + 1); - let mut result: Result> = Ok(0); - syscall.call( - ro_va, - ro_len, - rw_va - 1, // AccessViolation - 0, - 0, - &memory_mapping, - &mut result, - ); - assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64); - - syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result); + let braw: &BigNum = unsafe { &*(htp as *mut BigNum) }; assert_eq!( - Err(EbpfError::UserError(BpfError::SyscallError( - SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) - ))), - result - ); - } - - #[test] - fn test_syscall_get_sysvar() { - // Test clock sysvar - { - let got_clock = Clock::default(); - let got_clock_va = 2048; - - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: &got_clock as *const _ as u64, - vm_addr: got_clock_va, - len: size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let src_clock = Clock { - slot: 1, - epoch_start_timestamp: 2, - epoch: 3, - leader_schedule_epoch: 4, - unix_timestamp: 5, - }; - let mut invoke_context = MockInvokeContext::new(vec![]); - let mut data = vec![]; - bincode::serialize_into(&mut data, &src_clock).unwrap(); - invoke_context - .sysvars - .push((sysvar::clock::id(), Some(Rc::new(data)))); - - let mut syscall = SyscallGetClockSysvar { - invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - - syscall.call(got_clock_va, 0, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - assert_eq!(got_clock, src_clock); - } - - // Test epoch_schedule sysvar - { - let got_epochschedule = EpochSchedule::default(); - let got_epochschedule_va = 2048; - - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: &got_epochschedule as *const _ as u64, - vm_addr: got_epochschedule_va, - len: size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let src_epochschedule = EpochSchedule { - slots_per_epoch: 1, - leader_schedule_slot_offset: 2, - warmup: false, - first_normal_epoch: 3, - first_normal_slot: 4, - }; - let mut invoke_context = MockInvokeContext::new(vec![]); - let mut data = vec![]; - bincode::serialize_into(&mut data, &src_epochschedule).unwrap(); - invoke_context - .sysvars - .push((sysvar::epoch_schedule::id(), Some(Rc::new(data)))); - - let mut syscall = SyscallGetEpochScheduleSysvar { - invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - - syscall.call( - got_epochschedule_va, - 0, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - result.unwrap(); - assert_eq!(got_epochschedule, src_epochschedule); - } - - // Test fees sysvar - { - let got_fees = Fees::default(); - let got_fees_va = 2048; - - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: &got_fees as *const _ as u64, - vm_addr: got_fees_va, - len: size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let src_fees = Fees { - fee_calculator: FeeCalculator { - lamports_per_signature: 1, - }, - }; - let mut invoke_context = MockInvokeContext::new(vec![]); - let mut data = vec![]; - bincode::serialize_into(&mut data, &src_fees).unwrap(); - invoke_context - .sysvars - .push((sysvar::fees::id(), Some(Rc::new(data)))); - - let mut syscall = SyscallGetFeesSysvar { - invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - - syscall.call(got_fees_va, 0, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - assert_eq!(got_fees, src_fees); - } - - // Test rent sysvar - { - let got_rent = Rent::default(); - let got_rent_va = 2048; - - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: &got_rent as *const _ as u64, - vm_addr: got_rent_va, - len: size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], - &DEFAULT_CONFIG, + *braw, + BigNum::from_dec_str( + "23816539405324371056039456701279617701270933313491427172544877039730238224951" ) - .unwrap(); - - let src_rent = Rent { - lamports_per_byte_year: 1, - exemption_threshold: 2.0, - burn_percent: 3, - }; - let mut invoke_context = MockInvokeContext::new(vec![]); - let mut data = vec![]; - bincode::serialize_into(&mut data, &src_rent).unwrap(); - invoke_context - .sysvars - .push((sysvar::rent::id(), Some(Rc::new(data)))); - - let mut syscall = SyscallGetRentSysvar { - invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - - syscall.call(got_rent_va, 0, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - assert_eq!(got_rent, src_rent); - } + .unwrap() + ); + // println!("Hash to prime = {:?}", braw); } } diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 2e4712906bdac6..c1dd897810c39a 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -437,6 +437,223 @@ static uint64_t sol_sha256( const uint8_t *result ); +/** + * BigNum sol_bignum_new + * + * @param ptr location where new object address dropped + */ +static uint64_t sol_bignum_new( + const uint64_t *ptr +); + +/** + * BigNum sol_bignum_from_u32 + * + * @param ptr location where new object address dropped + * @param val_u32 unsigned 32 bit value to assign to the new object + */ +static uint64_t sol_bignum_from_u32( + const uint64_t *ptr, + const uint32_t val_u32 +); +/** + * BigNum sol_bignum_from_bytes + * + * @param ptr location where new object address dropped + * @param bytes pointer to unsigned byte array + * @param byte_len size of bytes array + */ +static uint64_t sol_bignum_from_bytes( + const uint64_t *ptr, + const SolBytes *bytes, + const uint64_t byte_len +); +/** + * BigNum sol_bignum_to_bytes + * + * @param ptr object address created with sol_bignum_new (read/write) + * @param bytes pointer to unsigned byte array + * @param byte_len maximum size of bytes array + */ +/** + * Size of Public key in bytes + */ +#define SIZE_BIGNUMBYTES 256 + +/** + * Public key + */ +typedef struct { + uint8_t x[SIZE_BIGNUMBYTES]; +} SolBigNumBuf; + +static uint64_t sol_bignum_to_bytes( + const uint64_t *ptr, + const SolBigNumBuf *bytes, + const uint64_t *byte_len +); + +/** + * @param u_ptr bignum address + * @param a_ptr bignum address + * @param n_ptr bignum address + * @param nonce_ptr + * @param hg_ptr hashed generated return bignum address + */ + +static uint64_t sol_bignum_hashed_generator ( + const uint64_t *u_ptr, + const uint64_t *a_ptr, + const uint64_t *n_ptr, + const uint64_t *nonce_ptr, + const uint64_t *hg_ptr +); + +/** + * @param u_ptr bignum address + * @param a_ptr bignum address + * @param z_ptr bignum address + * @param nonce_ptr + * @param htp_ptr prime generated return bignum address + */ + +static uint64_t sol_bignum_hash_to_prime ( + const uint64_t *u_ptr, + const uint64_t *a_ptr, + const uint64_t *z_ptr, + const uint64_t *nonce_ptr, + const uint64_t *htp_ptr +); + +/** + * BigNum sol_bignum_add + * Performs add and returns bignum for sum + * @param self_ptr self bignum address + * @param rhs_ptr bignum address to add with self + * @param sum_ptr object address of resulting sum + + */ +static uint64_t sol_bignum_add( + const uint64_t *self_ptr, + const uint64_t *rhs_ptr, + const uint64_t *sum_ptr +); +/** + * BigNum sol_bignum_sub + * Performs subtraction and returns bignum for difference + * @param self_ptr self bignum address + * @param rhs_ptr bignum address number to sub from self + * @param diff_ptr object address of resulting difference + + */ +static uint64_t sol_bignum_sub( + const uint64_t *self_ptr, + const uint64_t *rhs_ptr, + const uint64_t *diff_ptr +); +/** + * BigNum sol_bignum_mul + * Performs multiplication and returns bignum for product + * @param self_ptr self bignum address + * @param rhs_ptr bignum address number to multiple self by + * @param product_ptr object address of resulting product + + */ +static uint64_t sol_bignum_mul( + const uint64_t *self_ptr, + const uint64_t *rhs_ptr, + const uint64_t *product_ptr +); +/** + * BigNum sol_bignum_div + * Performs division and returns bignum for product + * @param self_ptr self bignum address + * @param rhs_ptr bignum address number to divide self by + * @param quotient_ptr object address of resulting quotient + */ +static uint64_t sol_bignum_div( + const uint64_t *self_ptr, + const uint64_t *rhs_ptr, + const uint64_t *quotient_ptr +); + +/** + * BigNum sol_bignum_exp + * @param self_ptr self bignum address + * @param exponent_ptr exponent bignum address + * @param exp_res_ptr object address of resulting self^exp + */ +static uint64_t sol_bignum_exp( + const uint64_t *self_ptr, + const uint64_t *self_exponent_ptr, + const uint64_t *exp_res_ptr +); + +/** + * BigNum sol_bignum_sqr + * @param self_ptr self bignum address + c + */ +static uint64_t sol_bignum_sqr( + const uint64_t *self_ptr, + const uint64_t *sqr_res_ptr +); + +/** + * BigNum sol_bignum_mod_mul + * Performs (base * multiplier) % modulus and updates self_ptr BigNum + * @param self_ptr base bignum address (i.e. self -- read) + * @param multiplier_ptr - The number that self_ptr is multiplied by + * @param modulus_ptr the modulus applied to the product of self*multiplier + * @param mod_exp_ptr object address of resulting BigNum + */ +static uint64_t sol_bignum_mod_mul( + const uint64_t *self_ptr, + const uint64_t *multiplier_ptr, + const uint64_t *modulus_ptr, + const uint64_t *mod_mul_ptr +); + +/** + * BigNum sol_bignum_mod_inverse + * Performs (base * multiplier) % modulus and updates self_ptr BigNum + * @param self_ptr base bignum address (i.e. self -- read) + * @param modulus_ptr the modulus applied to the product of self*multiplier + * @param mod_exp_ptr object address of resulting BigNum + */ +static uint64_t sol_bignum_mod_inverse( + const uint64_t *self_ptr, + const uint64_t *modulus_ptr, + const uint64_t *mod_mul_ptr +); + + +/** + * BigNum sol_bignum_mod_exp + * Performs base^exponent % modulus and updates self_ptr BigNum + * @param mod_exp_ptr object address of resulting BigNum + * @param self_ptr base bignum address (i.e. self -- read) + * @param exponent_ptr exponent bignum address (read) + * @param modulus_ptr modulus bignum address (read) + */ +static uint64_t sol_bignum_mod_exp( + const uint64_t *mod_exp_ptr, + const uint64_t *self_ptr, + const uint64_t *base_ptr, + const uint64_t *exponent_ptr, + const uint64_t *modulus_ptr +); + +/** + * BigNum drop + * + * @param ptr object address created with sol_bignum_new + */ +static uint64_t sol_bignum_drop( + const uint64_t *ptr +); + + /** * Account Meta */ diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index e95fa5f109b5ad..1353a124334dd0 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -36,6 +36,9 @@ blake3 = "0.3.7" curve25519-dalek = "2.1.0" rand = "0.7.0" solana-logger = { path = "../../logger", version = "=1.7.0" } +hkdf = "0.11.0" +num-bigint = "0.4.0" +openssl = "0.10.32" [dev-dependencies] static_assertions = "1.1.0" diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs new file mode 100644 index 00000000000000..10dd218d5a1da5 --- /dev/null +++ b/sdk/program/src/bignum.rs @@ -0,0 +1,704 @@ +//! @brief Solana Rust-based BigNumber for bpf-programs + +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use std::fmt; + +#[repr(transparent)] +#[derive( + BorshSerialize, + BorshDeserialize, + BorshSchema, + // Clone, + Default, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + AbiExample, +)] + +pub struct BigNumber(u64); + +// Syscall interfaces +#[cfg(target_arch = "bpf")] +extern "C" { + fn sol_bignum_new(bignum_ptr: *mut u64) -> u64; + fn sol_bignum_from_u32(bignum_ptr: *mut u64, val: u64) -> u64; + fn sol_bignum_from_bytes(bignum_ptr: *mut u64, bytes_ptr: *const u64, bytes_len: u64) -> u64; + fn sol_bignum_to_bytes(bignum_ptr: *const u64, bytes_ptr: *mut u8, bytes_len: *mut u64) -> u64; + fn sol_bignum_add(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; + fn sol_bignum_sub(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; + fn sol_bignum_mul(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; + fn sol_bignum_div(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; + fn sol_bignum_sqr(self_ptr: *const u64, bignum_ptr: *mut u64) -> u64; + fn sol_bignum_exp(self_ptr: *const u64, exponent_ptr: *const u64, bignum_ptr: *mut u64) -> u64; + fn sol_bignum_mod_sqr( + self_ptr: *const u64, + modulus_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + fn sol_bignum_mod_mul( + self_ptr: *const u64, + multiplier_ptr: *const u64, + modulus_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + fn sol_bignum_mod_inv( + self_ptr: *const u64, + modulus_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + fn sol_bignum_mod_exp( + bignum_ptr: *mut u64, + self_ptr: *const u64, + exponent_ptr: *const u64, + modulus_ptr: *const u64, + ) -> u64; + fn sol_bignum_hashed_generator( + self_ptr: *const u64, + a: *const u64, + n: *const u64, + nonce: *const u64, + hg_ptr: *mut u64, + ) -> u64; + fn sol_bignum_hash_to_prime( + u: *const u64, + a: *const u64, + z: *const u64, + nonce: *const u64, + htp_ptr: *mut u64, + ) -> u64; + fn sol_log_bignum(bignum_addr: *const u64) -> u64; + fn sol_bignum_drop(bignum_ptr: *mut u64) -> u64; + fn sol_blake3_digest( + data_ptr: *const u8, + data_len: *const u64, + digest_ptr: *mut u8, + digest_len: *mut u64, + ) -> u64; +} + +impl BigNumber { + /// Returns a BigNumber with initial value of 0 + pub fn new() -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let bbox = Box::new(BigNum::new().unwrap()); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + Self(bignum_ptr) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_new(&mut bignum_ptr as *mut _ as *mut u64); + } + BigNumber::from(bignum_ptr) + } + } + /// Returns a BigNumber with initial value set to a u32 value + pub fn from_u32(val: u32) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let bbox = Box::new(BigNum::from_u32(val).unwrap()); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + Self(bignum_ptr) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_from_u32(&mut bignum_ptr as *mut _ as *mut u64, val as u64); + } + BigNumber::from(bignum_ptr) + } + } + /// Returns a BigNumber with value set to big endian array of bytes + pub fn from_bytes(val: &[u8]) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let bbox = Box::new(BigNum::from_slice(val).unwrap()); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + Self(bignum_ptr) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_from_bytes( + &mut bignum_ptr as *mut _ as *mut u64, + val.as_ptr() as *const _ as *const u64, + val.len() as u64, + ); + } + BigNumber::from(bignum_ptr) + } + } + /// Returns an array of bytes (big endian) of self + pub fn to_bytes(&self) -> Vec { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let braw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + braw.as_ref().to_vec() + } + #[cfg(target_arch = "bpf")] + { + let mut my_buffer = [0u8; 256]; + let mut my_buffer_len = my_buffer.len(); + unsafe { + sol_bignum_to_bytes( + &self.0 as *const _ as *const u64, + &mut my_buffer as *mut _ as *mut u8, + &mut my_buffer_len as *mut _ as *mut u64, + ); + }; + my_buffer[0..my_buffer_len].to_vec() + } + } + /// Add BigNumbers + pub fn add(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + BigNumRef::checked_add(&mut bbox, my_raw, rhs_ptr).unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_add( + &self.0 as *const _ as *const u64, + &rhs.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + /// Subtract BigNumbers + pub fn sub(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + BigNumRef::checked_sub(&mut *bbox, my_raw, rhs_ptr).unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_sub( + &self.0 as *const _ as *const u64, + &rhs.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + /// Multiple BigNumbers + pub fn mul(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + BigNumRef::checked_mul( + &mut *bbox, + my_raw, + rhs_ptr, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_mul( + &self.0 as *const _ as *const u64, + &rhs.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + + /// Mod multiplier (self * multiplier) % modulus + pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let mut new_self = Box::new(BigNum::new().unwrap()); + let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let multiplier_ptr: &BigNum = unsafe { &*(multiplier.0 as *const BigNum) }; + let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + new_self + .mod_mul( + myself_ptr, + multiplier_ptr, + modulus_ptr, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(new_self); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_mod_mul( + &self.0 as *const _ as *const u64, + &multiplier.0 as *const _ as *const u64, + &modulus.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + /// Finds the inverse of modulus on self + pub fn mod_inv(&self, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let mut new_self = Box::new(BigNum::new().unwrap()); + let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + new_self + .mod_inverse(myself_ptr, modulus_ptr, &mut BigNumContext::new().unwrap()) + .unwrap(); + let rwptr = Box::into_raw(new_self); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_mod_inv( + &self.0 as *const _ as *const u64, + &modulus.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + + /// Divide BigNumbers + pub fn div(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + BigNumRef::checked_div( + &mut *bbox, + my_raw, + rhs_ptr, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_div( + &self.0 as *const _ as *const u64, + &rhs.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + /// Square BigNumbers + pub fn sqr(&self) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + BigNumRef::sqr(&mut *bbox, my_raw, &mut BigNumContext::new().unwrap()).unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_sqr( + &self.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + /// Square BigNumbers + pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let my_mod: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + BigNumRef::mod_sqr( + &mut *bbox, + my_raw, + my_mod, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_mod_sqr( + &self.0 as *const _ as *const u64, + &modulus.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + /// Square BigNumbers + pub fn exp(&self, exponent: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; + let mut bbox = Box::new(BigNum::new().unwrap()); + BigNumRef::exp( + &mut *bbox, + my_raw, + exponent_ptr, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(bbox); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = 0u64; + unsafe { + sol_bignum_exp( + &self.0 as *const _ as *const u64, + &exponent.0 as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + + /// Compute modular exponentiation (self ^ rhs mod order) and return the result + pub fn mod_exp(&self, exponent: &BigNumber, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let mut new_self = Box::new(BigNum::new().unwrap()); + let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; + let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + new_self + .mod_exp( + myself_ptr, + exponent_ptr, + modulus_ptr, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(new_self); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let bignum_ptr = &mut 0u64; + unsafe { + sol_bignum_mod_exp( + &mut *bignum_ptr as *mut _ as *mut u64, + &self.0 as *const _ as *const u64, + &exponent.0 as *const _ as *const u64, + &modulus.0 as *const _ as *const u64, + ); + } + Self(*bignum_ptr) + } + } + + /// Hashed Generator + pub fn hashed_generator(&self, a: &BigNumber, n: &BigNumber, nonce: &[u8]) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use hkdf::Hkdf; + use openssl::bn::{BigNum, BigNumContext}; + + let u_bn = unsafe { &*(self.0 as *mut BigNum) }; + let a_bn = unsafe { &*(a.0 as *mut BigNum) }; + let n_bn = unsafe { &*(n.0 as *mut BigNum) }; + println!("u:{}", u_bn); + println!("a:{}", a_bn); + println!("n:{}", n_bn); + // hash_generator + let mut transcript = u_bn.as_ref().to_vec(); + transcript.append(&mut a_bn.as_ref().to_vec()); + transcript.extend_from_slice(nonce); + println!("t:{:?}", transcript); + let length = n_bn.num_bytes(); + println!("len:{}", length); + let h = Hkdf::::new( + Some(b"SST_SALT_HASH_TO_GENERATOR_"), + transcript.as_slice().as_ref(), + ); + let mut okm = vec![0u8; length as usize]; + h.expand(b"", &mut okm).unwrap(); + println!("okm:{:?}", okm); + let okm_bn = BigNum::from_slice(okm.as_slice()).unwrap(); + + let mut res_bn = Box::new(BigNum::new().unwrap()); + res_bn + .mod_sqr( + okm_bn.as_ref(), + n_bn.as_ref(), + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let rwptr = Box::into_raw(res_bn); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = nonce.len() as u64; + unsafe { + sol_bignum_hashed_generator( + &self.0 as *const _ as *const u64, + &a.0 as *const _ as *const u64, + &n.0 as *const _ as *const u64, + nonce as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + + /// Hashed Generator + pub fn hash_to_prime(u: &BigNumber, a: &BigNumber, z: &BigNumber, nonce: &[u8]) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use blake3::traits::digest::Digest; + use openssl::bn::{BigNum, BigNumContext}; + let u_bn = unsafe { &*(u.0 as *mut BigNum) }; + let a_bn = unsafe { &*(a.0 as *mut BigNum) }; + let z_bn = unsafe { &*(z.0 as *mut BigNum) }; + + let mut input = u_bn.as_ref().to_vec(); + input.extend_from_slice(&a_bn.as_ref().to_vec()); + input.extend_from_slice(&z_bn.as_ref().to_vec()); + input.extend_from_slice(nonce); + // println!("t:{:?}",input); + + let mut i = 1u32; + let offset = input.len(); + input.extend_from_slice(&i.to_be_bytes()[..]); + let end = input.len(); + let ctx = &mut BigNumContext::new().unwrap(); + let mut num; + loop { + let mut hash = blake3::Hasher::digest(input.as_slice()); + // Force it to be odd + hash[31] |= 1; + // Only need 256 bits just borrow the bottom 32 bytes + // There should be plenty of primes below 2^256 + // and we want this to be reasonably fast + //num = BigNumber::from_bytes(&hash[32..]); + num = BigNum::from_slice(&hash).unwrap(); + if num.is_prime(15, ctx).unwrap() { + // msg!("num_bytes:{:?}",num.to_bytes().to_vec()); + // msg!("i:{}",i); + break; + } + i += 1; + let i_bytes = i.to_be_bytes(); + input[offset..end].clone_from_slice(&i_bytes[..]); + } + let res_bn = Box::new(num); + let rwptr = Box::into_raw(res_bn); + Self(rwptr as u64) + } + #[cfg(target_arch = "bpf")] + { + let mut bignum_ptr = nonce.len() as u64; + unsafe { + sol_bignum_hash_to_prime( + &u.0 as *const _ as *const u64, + &a.0 as *const _ as *const u64, + &z.0 as *const _ as *const u64, + nonce as *const _ as *const u64, + &mut bignum_ptr as *mut _ as *mut u64, + ); + } + Self(bignum_ptr) + } + } + + /// Log a `BigNum` from a program + pub fn log(&self) { + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_log(&self.to_string()); + #[cfg(target_arch = "bpf")] + { + unsafe { sol_log_bignum(&self.0 as *const _ as *const u64) }; + } + } +} + +impl fmt::Debug for BigNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let braw: &BigNum = unsafe { &*(self.0 as *mut BigNum) }; + write!(f, "{}", braw) + } + #[cfg(target_arch = "bpf")] + { + write!(f, "{}", 0) + } + } +} + +impl fmt::Display for BigNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let braw: &BigNum = unsafe { &*(self.0 as *mut BigNum) }; + write!(f, "{}", braw) + } + #[cfg(target_arch = "bpf")] + { + write!(f, "{}", 0) + } + } +} + +impl AsRef for BigNumber { + fn as_ref(&self) -> &u64 { + &self.0 + } +} + +impl From for BigNumber { + fn from(ptr: u64) -> Self { + Self(ptr) + } +} + +/// Drop - removes the underlying BigNum +impl Drop for BigNumber { + fn drop(&mut self) { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + drop(unsafe { Box::from_raw(self.0 as *mut BigNum) }); + } + #[cfg(target_arch = "bpf")] + { + unsafe { + sol_bignum_drop(&mut self.0 as *mut _ as *mut u64); + } + } + } +} +/// Clone - creates a new BigNumber replicating itself +impl Clone for BigNumber { + fn clone(&self) -> Self { + BigNumber::from_bytes(self.to_bytes().as_slice()) + } +} + +/// Returns an array of bytes (big endian) of self +pub fn blake3_digest(data: &[u8]) -> Vec { + #[cfg(not(target_arch = "bpf"))] + { + use blake3::traits::digest::Digest; + blake3::Hasher::digest(data).to_vec() + } + #[cfg(target_arch = "bpf")] + { + let data_len = data.len(); + let mut digest = [0u8; 32]; + let mut digest_len = digest.len(); + unsafe { + sol_blake3_digest( + data.as_ptr() as *const _ as *const u8, + &data_len as *const _ as *const u64, + digest.as_mut_ptr() as *mut _ as *mut u8, + &mut digest_len as *mut _ as *mut u64, + ); + }; + digest[0..digest_len].to_vec() + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_bignumber_new() { + let bn1 = BigNumber::new(); + println!("{:?}", bn1); + } + + #[test] + fn test_bignumber_hashed_generator() { + let bn_u = BigNumber::from_u32(11); + let bn_a = BigNumber::from_u32(59); + let bn_n = BigNumber::from_u32(7); + let nonce = b"hgen"; + let result = bn_u.hashed_generator(&bn_a, &bn_n, nonce); + println!("Hashed generator result = {}", result); + } + + #[test] + fn test_bignumber_clone() { + let bn_u = BigNumber::from_u32(11); + let bn_u2 = bn_u.clone(); + println!("bn_u = {}", bn_u); + println!("bn_u2 = {}", bn_u2); + } +} diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index fcac9c4faa750a..82bdc8164e17b5 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -6,6 +6,7 @@ extern crate self as solana_program; pub mod account_info; +pub mod bignum; pub mod borsh; pub mod bpf_loader; pub mod bpf_loader_deprecated; diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index d591c84ac7477a..56fc738af512c8 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -165,6 +165,44 @@ pub struct BpfComputeBudget { pub cpi_bytes_per_unit: u64, /// Base number of compute units consumed to get a sysvar pub sysvar_base_cost: u64, + /// Base number of compute units consumed to call BIGNUM NEW + pub bignum_new_base_cost: u64, + /// Base number of compute units consumed to call BigNum new from u32 value + pub bignum_from_u32_base_cost: u64, + /// Base number of compute units consumed to call BigNum new from big endian byte array + pub bignum_from_bytes_base_cost: u64, + /// Base number of compute units consumed to extract big endian byte array from BigNumb + pub bignum_to_bytes_base_cost: u64, + /// Base number of compute units consumed to drop/dealloc BigNum + pub bignum_drop_base_cost: u64, + /// Incremental number of units consumed to drop/dealloc BigNum (based on bytes) + pub bignum_mod_exp_base_cost: u64, + /// Number of compute units consumed by logging a `BigNum` + pub log_bignum_cost: u64, + /// Number of compute units consumed by BigNum add + pub bignum_add_cost: u64, + /// Number of compute units consumed by BigNum subtract + pub bignum_sub_cost: u64, + /// Number of compute units consumed by BigNum mutliply + pub bignum_mul_cost: u64, + /// Number of compute units consumed by BigNum divide + pub bignum_div_cost: u64, + /// Number of compute units consumed by BigNum exp + pub bignum_exp_cost: u64, + /// Number of compute units consumed by BigNum sqr + pub bignum_sqr_cost: u64, + /// Number of compute units consumed by BigNum mod_sqr + pub bignum_mod_sqr_cost: u64, + /// Number of compute units consumed by BigNum mod_mul + pub bignum_mod_mul_cost: u64, + /// Number of compute units consumed by BigNum mod_inv + pub bignum_mod_inv_cost: u64, + /// Number of compute units consumed by BigNum hashed_generator + pub bignum_hashed_generator_cost: u64, + /// Number of compute units consumed by Blake3 digest + pub blake3_digest_base_cost: u64, + /// Number of compute units consumed by BigNum hash_to_prime + pub bignum_hash_to_prime_cost: u64, } impl Default for BpfComputeBudget { fn default() -> Self { @@ -188,6 +226,25 @@ impl BpfComputeBudget { max_cpi_instruction_size: 1280, // IPv6 Min MTU size cpi_bytes_per_unit: 250, // ~50MB at 200,000 units sysvar_base_cost: 100, + bignum_new_base_cost: 100, + bignum_drop_base_cost: 100, + bignum_from_u32_base_cost: 100, + bignum_from_bytes_base_cost: 100, + bignum_to_bytes_base_cost: 100, + bignum_mod_exp_base_cost: 100, + log_bignum_cost: 100, + bignum_add_cost: 15, + bignum_sub_cost: 15, + bignum_mul_cost: 30, + bignum_div_cost: 30, + bignum_exp_cost: 30, + bignum_sqr_cost: 15, + bignum_mod_sqr_cost: 30, + bignum_mod_mul_cost: 45, + bignum_mod_inv_cost: 45, + bignum_hashed_generator_cost: 100, + blake3_digest_base_cost: 85, + bignum_hash_to_prime_cost: 20000, } } } From 2cd8645591ec285788e4b0ddeffa8c9dfc8fca2c Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 6 May 2021 13:39:03 -0400 Subject: [PATCH 02/45] Removed extra whitespaces --- programs/bpf_loader/src/syscalls.rs | 2 +- sdk/bpf/c/inc/solana_sdk.h | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index b8a4e2da7b29e9..8bae832f7bc702 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4996,7 +4996,7 @@ mod tests { syscall.call(2048, 4096, 8192, 1024, 96, &memory_mapping, &mut result); result.unwrap(); let braw: &BigNum = unsafe { &*(hg_addr as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(0).unwrap()); + assert_eq!(*braw, BigNum::from_u32(0).unwrap()); } #[test] fn test_syscall_bignum_drop() { diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index c1dd897810c39a..dcbb796a4bd7f1 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -497,9 +497,9 @@ static uint64_t sol_bignum_to_bytes( * @param u_ptr bignum address * @param a_ptr bignum address * @param n_ptr bignum address - * @param nonce_ptr + * @param nonce_ptr * @param hg_ptr hashed generated return bignum address - */ + */ static uint64_t sol_bignum_hashed_generator ( const uint64_t *u_ptr, @@ -513,9 +513,9 @@ static uint64_t sol_bignum_hashed_generator ( * @param u_ptr bignum address * @param a_ptr bignum address * @param z_ptr bignum address - * @param nonce_ptr + * @param nonce_ptr * @param htp_ptr prime generated return bignum address - */ + */ static uint64_t sol_bignum_hash_to_prime ( const uint64_t *u_ptr, @@ -531,7 +531,7 @@ static uint64_t sol_bignum_hash_to_prime ( * @param self_ptr self bignum address * @param rhs_ptr bignum address to add with self * @param sum_ptr object address of resulting sum - + */ static uint64_t sol_bignum_add( const uint64_t *self_ptr, @@ -544,7 +544,7 @@ static uint64_t sol_bignum_add( * @param self_ptr self bignum address * @param rhs_ptr bignum address number to sub from self * @param diff_ptr object address of resulting difference - + */ static uint64_t sol_bignum_sub( const uint64_t *self_ptr, @@ -557,7 +557,7 @@ static uint64_t sol_bignum_sub( * @param self_ptr self bignum address * @param rhs_ptr bignum address number to multiple self by * @param product_ptr object address of resulting product - + */ static uint64_t sol_bignum_mul( const uint64_t *self_ptr, @@ -595,7 +595,7 @@ static uint64_t sol_bignum_exp( c */ static uint64_t sol_bignum_sqr( - const uint64_t *self_ptr, + const uint64_t *self_ptr, const uint64_t *sqr_res_ptr ); @@ -605,10 +605,10 @@ static uint64_t sol_bignum_sqr( * @param self_ptr base bignum address (i.e. self -- read) * @param multiplier_ptr - The number that self_ptr is multiplied by * @param modulus_ptr the modulus applied to the product of self*multiplier - * @param mod_exp_ptr object address of resulting BigNum + * @param mod_exp_ptr object address of resulting BigNum */ -static uint64_t sol_bignum_mod_mul( - const uint64_t *self_ptr, +static uint64_t sol_bignum_mod_mul( + const uint64_t *self_ptr, const uint64_t *multiplier_ptr, const uint64_t *modulus_ptr, const uint64_t *mod_mul_ptr @@ -619,10 +619,10 @@ static uint64_t sol_bignum_mod_mul( * Performs (base * multiplier) % modulus and updates self_ptr BigNum * @param self_ptr base bignum address (i.e. self -- read) * @param modulus_ptr the modulus applied to the product of self*multiplier - * @param mod_exp_ptr object address of resulting BigNum + * @param mod_exp_ptr object address of resulting BigNum */ -static uint64_t sol_bignum_mod_inverse( - const uint64_t *self_ptr, +static uint64_t sol_bignum_mod_inverse( + const uint64_t *self_ptr, const uint64_t *modulus_ptr, const uint64_t *mod_mul_ptr ); From 03af7519e1ca7a29ed2ee25c2cd6b31e0d4e99fd Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Tue, 11 May 2021 06:04:40 -0400 Subject: [PATCH 03/45] Updated for review comments --- programs/bpf_loader/Cargo.toml | 7 +- programs/bpf_loader/src/syscalls.rs | 88 ++++++------- sdk/program/src/bignum.rs | 197 +++++++++++++++++++--------- 3 files changed, 180 insertions(+), 112 deletions(-) diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index 9bf99839155a2b..8e09fb1f82e8c5 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -11,19 +11,20 @@ edition = "2018" [dependencies] bincode = "1.3.1" +blake3 = "0.3.7" byteorder = "1.3.4" +hkdf = "0.11.0" log = "0.4.11" num-derive = "0.3" num-traits = "0.2" +openssl = "0.10.32" rand_core = "0.6.2" solana-measure = { path = "../../measure", version = "=1.7.0" } solana-runtime = { path = "../../runtime", version = "=1.7.0" } solana-sdk = { path = "../../sdk", version = "=1.7.0" } solana_rbpf = "=0.2.8" thiserror = "1.0" -hkdf = "0.11.0" -blake3 = "0.3.7" -openssl = "0.10.32" + [dev-dependencies] rand = "0.7.3" diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 8bae832f7bc702..0cc1bba350659e 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1162,7 +1162,7 @@ macro_rules! calc_bignum_cost { } /// BIGNUM sol_bignum_new -pub struct SyscallBigNumNew<'a> { +struct SyscallBigNumNew<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1178,6 +1178,8 @@ impl<'a> SyscallObject for SyscallBigNumNew<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { + question_mark!(self.compute_meter.consume(self.cost), result); + let big_number = question_mark!( translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), result @@ -1186,12 +1188,11 @@ impl<'a> SyscallObject for SyscallBigNumNew<'a> { let rwptr = Box::into_raw(bbox); let bignum_ptr = rwptr as u64; *big_number = bignum_ptr; - question_mark!(self.compute_meter.consume(self.cost), result); *result = Ok(0) } } -pub struct SyscallBigNumFromU32<'a> { +struct SyscallBigNumFromU32<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1213,18 +1214,18 @@ impl<'a> SyscallObject for SyscallBigNumFromU32<'a> { ); let bbox = Box::new(BigNum::from_u32(u32_val as u32).unwrap()); let bytes = bbox.num_bytes() as f64; - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - *big_number = bignum_ptr; question_mark!( self.compute_meter .consume(self.cost + calc_bignum_cost!(bytes)), result ); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + *big_number = bignum_ptr; *result = Ok(0) } } -pub struct SyscallBigNumFromBytes<'a> { +struct SyscallBigNumFromBytes<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1249,19 +1250,19 @@ impl<'a> SyscallObject for SyscallBigNumFromBytes<'a> { result ); let bytes: f64 = byte_slice.len() as f64; - let bbox = Box::new(BigNum::from_slice(byte_slice).unwrap()); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - *big_number = bignum_ptr; question_mark!( self.compute_meter .consume(self.cost + calc_bignum_cost!(bytes)), result ); + let bbox = Box::new(BigNum::from_slice(byte_slice).unwrap()); + let rwptr = Box::into_raw(bbox); + let bignum_ptr = rwptr as u64; + *big_number = bignum_ptr; *result = Ok(0) } } -pub struct SyscallBigNumToBytes<'a> { +struct SyscallBigNumToBytes<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1292,23 +1293,23 @@ impl<'a> SyscallObject for SyscallBigNumToBytes<'a> { let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; let bn_bytes = bn_self.as_ref().to_vec(); let bytes = bn_bytes.len() as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); let mut index = 0; for byte in bn_bytes.iter() { bytes_buffer[index] = *byte; index += 1; } *bytes_len = index as u64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); *result = Ok(0) } } /// BIGNUM sol_bignum_mod_exp -pub struct SyscallBigNumModExp<'a> { +struct SyscallBigNumModExp<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1346,6 +1347,11 @@ impl<'a> SyscallObject for SyscallBigNumModExp<'a> { let bn_exponent = unsafe { &*(*exponent_bignum_address as *const BigNum) }.as_ref(); let bn_modulus = (unsafe { &*(*modulus_bignum_address as *const BigNum) }).as_ref(); let bytes = (bn_self.num_bytes() + bn_exponent.num_bytes() + bn_modulus.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); let ctx = &mut BigNumContext::new().unwrap(); match mod_exp_bn.mod_exp(bn_self, bn_exponent, bn_modulus, ctx) { Ok(()) => { @@ -1356,15 +1362,10 @@ impl<'a> SyscallObject for SyscallBigNumModExp<'a> { } Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), } - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); } } /// Add BigNums -pub struct SyscallBigNumAdd<'a> { +struct SyscallBigNumAdd<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1416,7 +1417,7 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { } /// Subtract BigNums -pub struct SyscallBigNumSub<'a> { +struct SyscallBigNumSub<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1466,7 +1467,7 @@ impl<'a> SyscallObject for SyscallBigNumSub<'a> { } } /// Subtract BigNums -pub struct SyscallBigNumMul<'a> { +struct SyscallBigNumMul<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1521,7 +1522,7 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { }; } } -pub struct SyscallBigNumDiv<'a> { +struct SyscallBigNumDiv<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1576,7 +1577,7 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { }; } } -pub struct SyscallBigNumExp<'a> { +struct SyscallBigNumExp<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1631,7 +1632,7 @@ impl<'a> SyscallObject for SyscallBigNumExp<'a> { }; } } -pub struct SyscallBigNumSqr<'a> { +struct SyscallBigNumSqr<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1676,7 +1677,7 @@ impl<'a> SyscallObject for SyscallBigNumSqr<'a> { }; } } -pub struct SyscallBigNumModSqr<'a> { +struct SyscallBigNumModSqr<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1732,7 +1733,7 @@ impl<'a> SyscallObject for SyscallBigNumModSqr<'a> { } } -pub struct SyscallBigNumModMul<'a> { +struct SyscallBigNumModMul<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1794,7 +1795,7 @@ impl<'a> SyscallObject for SyscallBigNumModMul<'a> { } } -pub struct SyscallBigNumModInv<'a> { +struct SyscallBigNumModInv<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1845,12 +1846,12 @@ impl<'a> SyscallObject for SyscallBigNumModInv<'a> { Err(_e) => { // println!("{}", e); *result = Err(SyscallError::BigNumberModInvError.into()) - }, + } }; } } -pub struct SyscallBigNumHg<'a> { +struct SyscallBigNumHg<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1899,10 +1900,6 @@ impl<'a> SyscallObject for SyscallBigNumHg<'a> { result ); - // println!("u:{}",u_bn); - // println!("a:{}",a_bn); - // println!("n:{}",n_bn); - // hash_generator let mut transcript = u_bn.as_ref().to_vec(); transcript.append(&mut a_bn.as_ref().to_vec()); @@ -1931,7 +1928,7 @@ impl<'a> SyscallObject for SyscallBigNumHg<'a> { } } /// BIGNUM sol_bignum_drop -pub struct SyscallBigNumDrop<'a> { +struct SyscallBigNumDrop<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -1947,19 +1944,19 @@ impl<'a> SyscallObject for SyscallBigNumDrop<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { + question_mark!(self.compute_meter.consume(self.cost), result); let big_number = question_mark!( translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), result ); drop(unsafe { Box::from_raw(*big_number as *mut BigNum) }); *big_number = 0u64; - question_mark!(self.compute_meter.consume(self.cost), result); *result = Ok(0) } } /// Log BigNum values -pub struct SyscallLogBigNum<'a> { +struct SyscallLogBigNum<'a> { cost: u64, compute_meter: Rc>, logger: Rc>, @@ -1993,7 +1990,7 @@ impl<'a> SyscallObject for SyscallLogBigNum<'a> { } } -pub struct SyscallBlake3Digest<'a> { +struct SyscallBlake3Digest<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -2052,7 +2049,7 @@ impl<'a> SyscallObject for SyscallBlake3Digest<'a> { } /// Finds a valid prime from hash of u, a, z, nonce -pub struct SyscallBigNumberHashToPrime<'a> { +struct SyscallBigNumberHashToPrime<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, @@ -2122,11 +2119,8 @@ impl<'a> SyscallObject for SyscallBigNumberHashToPrime<'a> { // Only need 256 bits just borrow the bottom 32 bytes // There should be plenty of primes below 2^256 // and we want this to be reasonably fast - //num = BigNumber::from_bytes(&hash[32..]); num = BigNum::from_slice(&hash).unwrap(); if num.is_prime(15, ctx).unwrap() { - // msg!("num_bytes:{:?}",num.to_bytes().to_vec()); - // msg!("i:{}",i); break; } i += 1; @@ -4878,7 +4872,7 @@ mod tests { // println!("(3 * 3) % 7 = {:?}", braw); } #[test] - #[should_panic(expected="UserError(SyscallError(BigNumberModInvError))")] + #[should_panic(expected = "UserError(SyscallError(BigNumberModInvError))")] fn test_syscall_bignum_mod_inv() { let mut mod_inv = 0u64; let mod_inv_addr = &mut mod_inv as *mut _ as u64; diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 10dd218d5a1da5..06c4144761e020 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -20,65 +20,6 @@ use std::fmt; pub struct BigNumber(u64); -// Syscall interfaces -#[cfg(target_arch = "bpf")] -extern "C" { - fn sol_bignum_new(bignum_ptr: *mut u64) -> u64; - fn sol_bignum_from_u32(bignum_ptr: *mut u64, val: u64) -> u64; - fn sol_bignum_from_bytes(bignum_ptr: *mut u64, bytes_ptr: *const u64, bytes_len: u64) -> u64; - fn sol_bignum_to_bytes(bignum_ptr: *const u64, bytes_ptr: *mut u8, bytes_len: *mut u64) -> u64; - fn sol_bignum_add(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; - fn sol_bignum_sub(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; - fn sol_bignum_mul(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; - fn sol_bignum_div(self_ptr: *const u64, rhs_ptr: *const u64, return_ptr: *mut u64) -> u64; - fn sol_bignum_sqr(self_ptr: *const u64, bignum_ptr: *mut u64) -> u64; - fn sol_bignum_exp(self_ptr: *const u64, exponent_ptr: *const u64, bignum_ptr: *mut u64) -> u64; - fn sol_bignum_mod_sqr( - self_ptr: *const u64, - modulus_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - fn sol_bignum_mod_mul( - self_ptr: *const u64, - multiplier_ptr: *const u64, - modulus_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - fn sol_bignum_mod_inv( - self_ptr: *const u64, - modulus_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - fn sol_bignum_mod_exp( - bignum_ptr: *mut u64, - self_ptr: *const u64, - exponent_ptr: *const u64, - modulus_ptr: *const u64, - ) -> u64; - fn sol_bignum_hashed_generator( - self_ptr: *const u64, - a: *const u64, - n: *const u64, - nonce: *const u64, - hg_ptr: *mut u64, - ) -> u64; - fn sol_bignum_hash_to_prime( - u: *const u64, - a: *const u64, - z: *const u64, - nonce: *const u64, - htp_ptr: *mut u64, - ) -> u64; - fn sol_log_bignum(bignum_addr: *const u64) -> u64; - fn sol_bignum_drop(bignum_ptr: *mut u64) -> u64; - fn sol_blake3_digest( - data_ptr: *const u8, - data_len: *const u64, - digest_ptr: *mut u8, - digest_len: *mut u64, - ) -> u64; -} - impl BigNumber { /// Returns a BigNumber with initial value of 0 pub fn new() -> Self { @@ -92,6 +33,9 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_new(bignum_ptr: *mut u64) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_new(&mut bignum_ptr as *mut _ as *mut u64); @@ -99,6 +43,7 @@ impl BigNumber { BigNumber::from(bignum_ptr) } } + /// Returns a BigNumber with initial value set to a u32 value pub fn from_u32(val: u32) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -111,6 +56,9 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_from_u32(bignum_ptr: *mut u64, val: u64) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_from_u32(&mut bignum_ptr as *mut _ as *mut u64, val as u64); @@ -118,6 +66,7 @@ impl BigNumber { BigNumber::from(bignum_ptr) } } + /// Returns a BigNumber with value set to big endian array of bytes pub fn from_bytes(val: &[u8]) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -130,6 +79,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_from_bytes( + bignum_ptr: *mut u64, + bytes_ptr: *const u64, + bytes_len: u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_from_bytes( @@ -141,6 +97,7 @@ impl BigNumber { BigNumber::from(bignum_ptr) } } + /// Returns an array of bytes (big endian) of self pub fn to_bytes(&self) -> Vec { #[cfg(not(target_arch = "bpf"))] @@ -151,6 +108,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_to_bytes( + bignum_ptr: *const u64, + bytes_ptr: *mut u8, + bytes_len: *mut u64, + ) -> u64; + } let mut my_buffer = [0u8; 256]; let mut my_buffer_len = my_buffer.len(); unsafe { @@ -163,6 +127,7 @@ impl BigNumber { my_buffer[0..my_buffer_len].to_vec() } } + /// Add BigNumbers pub fn add(&self, rhs: &BigNumber) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -173,10 +138,17 @@ impl BigNumber { let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; BigNumRef::checked_add(&mut bbox, my_raw, rhs_ptr).unwrap(); let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) + Self(rwptr as u64) } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_add( + self_ptr: *const u64, + rhs_ptr: *const u64, + return_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_add( @@ -188,6 +160,7 @@ impl BigNumber { Self(bignum_ptr) } } + /// Subtract BigNumbers pub fn sub(&self, rhs: &BigNumber) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -202,6 +175,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_sub( + self_ptr: *const u64, + rhs_ptr: *const u64, + return_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_sub( @@ -213,6 +193,7 @@ impl BigNumber { Self(bignum_ptr) } } + /// Multiple BigNumbers pub fn mul(&self, rhs: &BigNumber) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -233,6 +214,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_mul( + self_ptr: *const u64, + rhs_ptr: *const u64, + return_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_mul( @@ -267,6 +255,14 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_mod_mul( + self_ptr: *const u64, + multiplier_ptr: *const u64, + modulus_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_mod_mul( @@ -279,6 +275,7 @@ impl BigNumber { Self(bignum_ptr) } } + /// Finds the inverse of modulus on self pub fn mod_inv(&self, modulus: &BigNumber) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -295,6 +292,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_mod_inv( + self_ptr: *const u64, + modulus_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_mod_inv( @@ -327,6 +331,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_div( + self_ptr: *const u64, + rhs_ptr: *const u64, + return_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_div( @@ -338,6 +349,7 @@ impl BigNumber { Self(bignum_ptr) } } + /// Square BigNumbers pub fn sqr(&self) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -351,6 +363,12 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_sqr( + self_ptr: *const u64, + modulus_ptr: *const u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_sqr( @@ -361,6 +379,7 @@ impl BigNumber { Self(bignum_ptr) } } + /// Square BigNumbers pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -381,6 +400,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_mod_sqr( + self_ptr: *const u64, + modulus_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_mod_sqr( @@ -392,6 +418,7 @@ impl BigNumber { Self(bignum_ptr) } } + /// Square BigNumbers pub fn exp(&self, exponent: &BigNumber) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -412,6 +439,13 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_exp( + self_ptr: *const u64, + exponent_ptr: *const u64, + bignum_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = 0u64; unsafe { sol_bignum_exp( @@ -446,6 +480,14 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_mod_exp( + bignum_ptr: *mut u64, + self_ptr: *const u64, + exponent_ptr: *const u64, + modulus_ptr: *const u64, + ) -> u64; + } let bignum_ptr = &mut 0u64; unsafe { sol_bignum_mod_exp( @@ -458,7 +500,6 @@ impl BigNumber { Self(*bignum_ptr) } } - /// Hashed Generator pub fn hashed_generator(&self, a: &BigNumber, n: &BigNumber, nonce: &[u8]) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -501,6 +542,15 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_hashed_generator( + self_ptr: *const u64, + a: *const u64, + n: *const u64, + nonce: *const u64, + hg_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = nonce.len() as u64; unsafe { sol_bignum_hashed_generator( @@ -515,7 +565,7 @@ impl BigNumber { } } - /// Hashed Generator + /// Hash to Prime pub fn hash_to_prime(u: &BigNumber, a: &BigNumber, z: &BigNumber, nonce: &[u8]) -> Self { #[cfg(not(target_arch = "bpf"))] { @@ -561,6 +611,15 @@ impl BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_hash_to_prime( + u: *const u64, + a: *const u64, + z: *const u64, + nonce: *const u64, + htp_ptr: *mut u64, + ) -> u64; + } let mut bignum_ptr = nonce.len() as u64; unsafe { sol_bignum_hash_to_prime( @@ -581,6 +640,9 @@ impl BigNumber { crate::program_stubs::sol_log(&self.to_string()); #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_log_bignum(bignum_addr: *const u64) -> u64; + } unsafe { sol_log_bignum(&self.0 as *const _ as *const u64) }; } } @@ -638,6 +700,9 @@ impl Drop for BigNumber { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_bignum_drop(bignum_ptr: *mut u64) -> u64; + } unsafe { sol_bignum_drop(&mut self.0 as *mut _ as *mut u64); } @@ -660,6 +725,14 @@ pub fn blake3_digest(data: &[u8]) -> Vec { } #[cfg(target_arch = "bpf")] { + extern "C" { + fn sol_blake3_digest( + data_ptr: *const u8, + data_len: *const u64, + digest_ptr: *mut u8, + digest_len: *mut u64, + ) -> u64; + } let data_len = data.len(); let mut digest = [0u8; 32]; let mut digest_len = digest.len(); From 30358602b0a2a08feb1a8bbcfec728ad6d6ad59d Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Wed, 12 May 2021 04:14:45 -0400 Subject: [PATCH 04/45] BPF test bignum --- programs/bpf/Cargo.lock | 56 +++++++++++++++++++++++++++++++++- programs/bpf/Cargo.toml | 1 + programs/bpf/build.rs | 1 + programs/bpf/tests/programs.rs | 1 + 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 75d96031fd4ba0..669e040aba4e5a 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -649,6 +649,16 @@ dependencies = [ "subtle 2.2.2", ] +[[package]] +name = "crypto-mac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array 0.14.3", + "subtle 2.2.2", +] + [[package]] name = "curve25519-dalek" version = "2.1.0" @@ -857,7 +867,7 @@ version = "3.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d52ff39419d3e16961ecfb9e32f5042bdaacf9a4cc553d2d688057117bae49b" dependencies = [ - "num-bigint", + "num-bigint 0.3.2", "num-traits", "proc-macro2 1.0.24", "quote 1.0.6", @@ -1221,6 +1231,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "hkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +dependencies = [ + "digest 0.9.0", + "hmac 0.11.0", +] + [[package]] name = "hmac" version = "0.7.1" @@ -1261,6 +1281,16 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.0", + "digest 0.9.0", +] + [[package]] name = "hmac-drbg" version = "0.2.0" @@ -1746,6 +1776,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-derive" version = "0.2.5" @@ -2756,10 +2797,13 @@ name = "solana-bpf-loader-program" version = "1.7.0" dependencies = [ "bincode", + "blake3", "byteorder 1.3.4", + "hkdf", "log", "num-derive 0.3.0", "num-traits", + "openssl", "rand_core 0.6.2", "sha3", "solana-measure", @@ -2813,6 +2857,13 @@ dependencies = [ "solana-program 1.7.0", ] +[[package]] +name = "solana-bpf-rust-bignum" +version = "1.7.0" +dependencies = [ + "solana-program 1.7.0", +] + [[package]] name = "solana-bpf-rust-call-depth" version = "1.7.0" @@ -3353,11 +3404,14 @@ dependencies = [ "bv", "curve25519-dalek 2.1.0", "hex", + "hkdf", "itertools 0.9.0", "lazy_static", "log", + "num-bigint 0.4.0", "num-derive 0.3.0", "num-traits", + "openssl", "rand 0.7.3", "rustc_version", "rustversion", diff --git a/programs/bpf/Cargo.toml b/programs/bpf/Cargo.toml index 81b04307026d48..d1356873e8617a 100644 --- a/programs/bpf/Cargo.toml +++ b/programs/bpf/Cargo.toml @@ -44,6 +44,7 @@ members = [ "rust/128bit", "rust/128bit_dep", "rust/alloc", + "rust/bignum", "rust/call_depth", "rust/caller_access", "rust/custom_heap", diff --git a/programs/bpf/build.rs b/programs/bpf/build.rs index a044671a04175a..a287fd6a290a61 100644 --- a/programs/bpf/build.rs +++ b/programs/bpf/build.rs @@ -60,6 +60,7 @@ fn main() { let rust_programs = [ "128bit", "alloc", + "bignum", "call_depth", "caller_access", "custom_heap", diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 65cae0ec9178d4..df5b6b80287f04 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -432,6 +432,7 @@ fn test_program_bpf_sanity() { programs.extend_from_slice(&[ ("solana_bpf_rust_128bit", true), ("solana_bpf_rust_alloc", true), + ("solana_bpf_rust_bignum", true), ("solana_bpf_rust_custom_heap", true), ("solana_bpf_rust_dep_crate", true), ("solana_bpf_rust_external_spend", false), From 2b1f3e1f6ff9935bada2404e4c1c40064a8eeb71 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Wed, 12 May 2021 07:09:55 -0400 Subject: [PATCH 05/45] BigNumber BPF testing --- programs/bpf/rust/bignum/src/lib.rs | 81 +++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index fc9df2c3a2b3fe..cae2fd7847999e 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -1,15 +1,75 @@ //! @brief BigNumber Syscall test extern crate solana_program; -use solana_program::{custom_panic_default, msg}; +use solana_program::{ + bignum::BigNumber, + custom_panic_default, msg, +}; +const LONG_DEC_STRING:&str = "1470463693494555670176851280755142329532258274256991544781479988\ + 712408107190720087233560906792937436573943189716784305633216335039\ + 300236370809933808677983409391545753391897467230180786617074456716\ + 591448871466263060696957107957862111484694673874424855359234132302\ + 162208163361387727626078022804936564470716886986414133429438273232\ + 416190048073715996321578752244853524209178212395809614878549824744\ + 227969245726015222693764433413133633359171080169137831743765672068\ + 374040331773668233371864426354886263106537340208256187214278963052\ + 996538599452325797319977413534714912781503130883692806087195354368\ + 8304190675878204079994222"; + +/// Compares the array of numbers return from BigNumbers +fn compare_bignum_equal(lhs:&BigNumber, rhs:&BigNumber) -> bool { + lhs.to_bytes() == rhs.to_bytes() +} + +/// BigNumber construction +fn test_constructors() { + msg!("BigNumber constructors"); + let _base_0 = BigNumber::new(); + let _new_0 = BigNumber::from_u32(0); + let _new_long = BigNumber::from_bytes(LONG_DEC_STRING.as_bytes()); +} + +/// BigNumber simple number and simple maths +fn test_basic_maths() { + msg!("BigNumber Basic Maths"); + let lhs = BigNumber::from_u32(3); + let rhs = BigNumber::from_u32(4); + let add_res = lhs.add(&rhs); + assert!(compare_bignum_equal(&add_res, &BigNumber::from_u32(7))); + let sub_res = rhs.sub(&lhs); + assert!(compare_bignum_equal(&sub_res, &BigNumber::from_u32(1))); + let lhs = BigNumber::from_u32(20); + let rhs = BigNumber::from_u32(10); + let div_res = lhs.div(&rhs); + assert!(compare_bignum_equal(&div_res, &BigNumber::from_u32(2))); + let mul_res = rhs.mul(&lhs); + assert!(compare_bignum_equal(&mul_res, &BigNumber::from_u32(200))); +} + +/// BigNumber bigger numbers and complex maths +fn test_complex_maths() { + msg!("BigNumber Complex Maths"); + let base_2 = BigNumber::from_u32(3); + let base_3 = BigNumber::from_u32(3); + let exp_base_3 = base_3.clone(); + let modulus_7 = BigNumber::from_u32(7); + assert!(compare_bignum_equal(&base_3.mod_mul(&exp_base_3, &modulus_7), &BigNumber::from_u32(2))); + let base_15 = BigNumber::from_u32(15); + assert!(compare_bignum_equal(&base_15.mod_sqr(&modulus_7), &BigNumber::from_u32(1))); + assert_eq!(base_15.sqr().to_bytes(), [225]); + assert_eq!(base_15.exp(&base_2).to_bytes(), [13, 47]); + assert_eq!(base_3.mod_inv(&modulus_7).to_bytes(), [5]); + assert!(true); +} #[no_mangle] pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { msg!("bignum"); - - - 0 + test_constructors(); + test_basic_maths(); + test_complex_maths(); + 0u64 } custom_panic_default!(); @@ -17,4 +77,17 @@ custom_panic_default!(); #[cfg(test)] mod test { use super::*; + + #[test] + fn test_basic_constructors_pass() { + test_constructors(); + } + #[test] + fn test_simple_maths_pass() { + test_basic_maths(); + } + #[test] + fn test_complex_maths_pass() { + test_complex_maths(); + } } From 01ed0b9d229749506e0065fed170cac1310741b1 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 06:50:17 -0400 Subject: [PATCH 06/45] Addressing white spaces and removed blake3 hash, hash-to-prime and hash-generator --- Cargo.lock | 2 - programs/bpf/Cargo.lock | 2 - programs/bpf/rust/bignum/src/lib.rs | 32 +- programs/bpf_loader/Cargo.toml | 2 - programs/bpf_loader/src/syscalls.rs | 474 +--------------------------- sdk/bpf/c/inc/solana_sdk.h | 35 +- sdk/program/src/bignum.rs | 181 +---------- sdk/src/process_instruction.rs | 11 +- 8 files changed, 25 insertions(+), 714 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8747bdcbee5984..87a016c4122a88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4121,9 +4121,7 @@ name = "solana-bpf-loader-program" version = "1.7.0" dependencies = [ "bincode", - "blake3", "byteorder", - "hkdf", "log 0.4.11", "num-derive", "num-traits", diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 2944339cfd6647..ab6b76fe104966 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -2799,9 +2799,7 @@ name = "solana-bpf-loader-program" version = "1.7.0" dependencies = [ "bincode", - "blake3", "byteorder 1.3.4", - "hkdf", "log", "num-derive 0.3.0", "num-traits", diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index cae2fd7847999e..450894bb7be43b 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -1,12 +1,9 @@ //! @brief BigNumber Syscall test extern crate solana_program; -use solana_program::{ - bignum::BigNumber, - custom_panic_default, msg, -}; +use solana_program::{bignum::BigNumber, custom_panic_default, msg}; -const LONG_DEC_STRING:&str = "1470463693494555670176851280755142329532258274256991544781479988\ +const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ 300236370809933808677983409391545753391897467230180786617074456716\ 591448871466263060696957107957862111484694673874424855359234132302\ @@ -18,16 +15,23 @@ const LONG_DEC_STRING:&str = "14704636934945556701768512807551423295322582742569 8304190675878204079994222"; /// Compares the array of numbers return from BigNumbers -fn compare_bignum_equal(lhs:&BigNumber, rhs:&BigNumber) -> bool { +fn compare_bignum_equal(lhs: &BigNumber, rhs: &BigNumber) -> bool { lhs.to_bytes() == rhs.to_bytes() } /// BigNumber construction fn test_constructors() { msg!("BigNumber constructors"); - let _base_0 = BigNumber::new(); - let _new_0 = BigNumber::from_u32(0); - let _new_long = BigNumber::from_bytes(LONG_DEC_STRING.as_bytes()); + let base_bn_0 = BigNumber::new(); + base_bn_0.log(); + let new_bn_0 = BigNumber::from_u32(0); + new_bn_0.log(); + let max_bn_u32 = BigNumber::from_u32(u32::MAX); + max_bn_u32.log(); + let new_bn_from_long_str = BigNumber::from_bytes(LONG_DEC_STRING.as_bytes()); + new_bn_from_long_str.log(); + let empty_bn = BigNumber::from_bytes(&[0u8]); + empty_bn.log(); } /// BigNumber simple number and simple maths @@ -54,9 +58,15 @@ fn test_complex_maths() { let base_3 = BigNumber::from_u32(3); let exp_base_3 = base_3.clone(); let modulus_7 = BigNumber::from_u32(7); - assert!(compare_bignum_equal(&base_3.mod_mul(&exp_base_3, &modulus_7), &BigNumber::from_u32(2))); + assert!(compare_bignum_equal( + &base_3.mod_mul(&exp_base_3, &modulus_7), + &BigNumber::from_u32(2) + )); let base_15 = BigNumber::from_u32(15); - assert!(compare_bignum_equal(&base_15.mod_sqr(&modulus_7), &BigNumber::from_u32(1))); + assert!(compare_bignum_equal( + &base_15.mod_sqr(&modulus_7), + &BigNumber::from_u32(1) + )); assert_eq!(base_15.sqr().to_bytes(), [225]); assert_eq!(base_15.exp(&base_2).to_bytes(), [13, 47]); assert_eq!(base_3.mod_inv(&modulus_7).to_bytes(), [5]); diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index 6b9640baaade70..9b2386832acb67 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -11,9 +11,7 @@ edition = "2018" [dependencies] bincode = "1.3.1" -blake3 = "0.3.7" byteorder = "1.3.4" -hkdf = "0.11.0" log = "0.4.11" num-derive = "0.3" num-traits = "0.2" diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 312a16e95cd2fc..0fe28f5f9e8c2a 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1,7 +1,5 @@ use crate::{alloc, BpfError}; use alloc::Alloc; -use blake3::traits::digest::Digest; -use hkdf::Hkdf; use openssl::bn::*; use solana_rbpf::{ aligned_memory::AlignedMemory, @@ -97,11 +95,8 @@ pub enum SyscallError { BigNumberModMulError, #[error("BigNumber: mod_inv error")] BigNumberModInvError, - #[error("BigNumber: hash generator error")] - BigNumberHgError, - #[error("BigNumber: hash_to_primeerror")] - BigNumberHtpError, } + impl From for EbpfError { fn from(error: SyscallError) -> Self { EbpfError::UserError(error.into()) @@ -198,15 +193,6 @@ pub fn register_syscalls( syscall_registry.register_syscall_by_name(b"sol_bignum_mod_sqr", SyscallBigNumModSqr::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mod_mul", SyscallBigNumModMul::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mod_inv", SyscallBigNumModInv::call)?; - // Compound functions - syscall_registry - .register_syscall_by_name(b"sol_bignum_hashed_generator", SyscallBigNumHg::call)?; - - syscall_registry.register_syscall_by_name(b"sol_blake3_digest", SyscallBlake3Digest::call)?; - syscall_registry.register_syscall_by_name( - b"sol_bignum_hash_to_prime", - SyscallBigNumberHashToPrime::call, - )?; Ok(syscall_registry) } @@ -447,31 +433,6 @@ pub fn bind_syscall_context_objects<'a>( None, )?; - vm.bind_syscall_context_object( - Box::new(SyscallBigNumHg { - cost: bpf_compute_budget.bignum_hashed_generator_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallBlake3Digest { - cost: bpf_compute_budget.blake3_digest_base_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallBigNumberHashToPrime { - cost: bpf_compute_budget.bignum_hash_to_prime_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; bind_feature_gated_syscall_context_object!( vm, invoke_context.is_feature_active(&keccak256_syscall_enabled::id()), @@ -1925,82 +1886,6 @@ impl<'a> SyscallObject for SyscallBigNumModInv<'a> { } } -struct SyscallBigNumHg<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumHg<'a> { - fn call( - &mut self, - u_addr: u64, - a_addr: u64, - n_addr: u64, - nonce_addr: u64, - hg_result_addr: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - // Get the 3 BigNums (u, a, n) - let bn_u_ptr = question_mark!( - translate_type::(memory_mapping, u_addr, self.loader_id, true), - result - ); - let bn_a_ptr = question_mark!( - translate_type::(memory_mapping, a_addr, self.loader_id, true), - result - ); - let bn_n_ptr = question_mark!( - translate_type::(memory_mapping, n_addr, self.loader_id, true), - result - ); - let hg_result_address = question_mark!( - translate_type_mut::(memory_mapping, hg_result_addr, self.loader_id, true), - result - ); - let nonce_len = unsafe { *(hg_result_address as *mut u64) }; - let nonce_ptr = question_mark!( - translate_slice::(memory_mapping, nonce_addr, nonce_len, self.loader_id, true), - result - ); - - let u_bn = unsafe { &*(*bn_u_ptr as *mut BigNum) }; - let a_bn = unsafe { &*(*bn_a_ptr as *mut BigNum) }; - let n_bn = unsafe { &*(*bn_n_ptr as *mut BigNum) }; - let bytes = (u_bn.num_bytes() + a_bn.num_bytes() + n_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - - // hash_generator - let mut transcript = u_bn.as_ref().to_vec(); - transcript.append(&mut a_bn.as_ref().to_vec()); - // transcript.extend_from_slice(nonce_ptr.as_ref()); - transcript.extend_from_slice(nonce_ptr); - // println!("t:{:?}",transcript); - let length = n_bn.num_bytes(); - // println!("len:{}",length); - let h = Hkdf::::new( - Some(b"SST_SALT_HASH_TO_GENERATOR_"), - transcript.as_slice().as_ref(), - ); - let mut okm = vec![0u8; length as usize]; - h.expand(b"", &mut okm).unwrap(); - // println!("okm:{:?}", okm); - - let okm_bn = BigNum::from_slice(okm.as_slice()).unwrap(); - - let mut res_bn = Box::new(BigNum::new().unwrap()); - res_bn - .mod_sqr(okm_bn.as_ref(), n_bn, &mut BigNumContext::new().unwrap()) - .unwrap(); - let rwptr = Box::into_raw(res_bn); - *hg_result_address = rwptr as u64; - *result = Ok(0) - } -} /// BIGNUM sol_bignum_drop struct SyscallBigNumDrop<'a> { cost: u64, @@ -2064,151 +1949,6 @@ impl<'a> SyscallObject for SyscallLogBigNum<'a> { } } -struct SyscallBlake3Digest<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBlake3Digest<'a> { - fn call( - &mut self, - bytes_addr: u64, - bytes_len_addr: u64, - digest_addr: u64, - digest_len_addr: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - let bytes_len = question_mark!( - translate_type::(memory_mapping, bytes_len_addr, self.loader_id, true), - result - ); - let bytes = question_mark!( - translate_slice::(memory_mapping, bytes_addr, *bytes_len, self.loader_id, true), - result - ); - let digest_len = question_mark!( - translate_type_mut::(memory_mapping, digest_len_addr, self.loader_id, true), - result - ); - let digest_bytes = question_mark!( - translate_slice_mut::( - memory_mapping, - digest_addr, - *digest_len, - self.loader_id, - true - ), - result - ); - - // println!("bytes-----syscall:{:?}", bytes); - let digest = blake3::Hasher::digest(bytes); - // println!("digest-----syscall:{:?}", digest.as_slice().to_vec()); - let mut index = 0; - for byte in digest.iter() { - digest_bytes[index] = *byte; - index += 1; - } - *digest_len = index as u64; - let bytes = (*bytes_len + *digest_len) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - *result = Ok(0) - } -} - -/// Finds a valid prime from hash of u, a, z, nonce -struct SyscallBigNumberHashToPrime<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumberHashToPrime<'a> { - fn call( - &mut self, - u_addr: u64, - a_addr: u64, - z_addr: u64, - nonce_addr: u64, - htp_result_addr: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - // Get the 3 BigNums pointers (u, a, z) - let bn_u_ptr = question_mark!( - translate_type::(memory_mapping, u_addr, self.loader_id, true), - result - ); - let bn_a_ptr = question_mark!( - translate_type::(memory_mapping, a_addr, self.loader_id, true), - result - ); - let bn_z_ptr = question_mark!( - translate_type::(memory_mapping, z_addr, self.loader_id, true), - result - ); - // Get the result location, on inbound it contains the nonce length - let htp_result_address = question_mark!( - translate_type_mut::(memory_mapping, htp_result_addr, self.loader_id, true), - result - ); - // Get the nonce - let nonce_len = unsafe { *(htp_result_address as *mut u64) }; - let nonce_ptr = question_mark!( - translate_slice::(memory_mapping, nonce_addr, nonce_len, self.loader_id, true), - result - ); - - let u_bn = unsafe { &*(*bn_u_ptr as *mut BigNum) }; - let a_bn = unsafe { &*(*bn_a_ptr as *mut BigNum) }; - let z_bn = unsafe { &*(*bn_z_ptr as *mut BigNum) }; - let bytes = (u_bn.num_bytes() + a_bn.num_bytes() + z_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - - let mut input = u_bn.as_ref().to_vec(); - input.extend_from_slice(&a_bn.as_ref().to_vec()); - input.extend_from_slice(&z_bn.as_ref().to_vec()); - input.extend_from_slice(nonce_ptr); - // println!("t:{:?}",input); - - let mut i = 1u32; - let offset = input.len(); - input.extend_from_slice(&i.to_be_bytes()[..]); - let end = input.len(); - let ctx = &mut BigNumContext::new().unwrap(); - let mut num; - loop { - let mut hash = blake3::Hasher::digest(input.as_slice()); - // Force it to be odd - hash[31] |= 1; - // Only need 256 bits just borrow the bottom 32 bytes - // There should be plenty of primes below 2^256 - // and we want this to be reasonably fast - num = BigNum::from_slice(&hash).unwrap(); - if num.is_prime(15, ctx).unwrap() { - break; - } - i += 1; - let i_bytes = i.to_be_bytes(); - input[offset..end].clone_from_slice(&i_bytes[..]); - } - println!("HashToPrimeLoop:{}", i); - let res_bn = Box::new(num); - let rwptr = Box::into_raw(res_bn); - *htp_result_address = rwptr as u64; - *result = Ok(0) - } -} - fn get_sysvar( id: &Pubkey, var_addr: u64, @@ -4996,76 +4736,7 @@ mod tests { // let braw: &BigNum = unsafe { &*(mod_inv as *mut BigNum) }; // println!("(9 % 7)^2 = {:?}", braw); } - #[test] - fn test_syscall_bignum_hashed_generator() { - let nonce = b"hgen_facelift"; - let mut hg = nonce.len() as u64; - let hg_addr = &mut hg as *mut _ as u64; - let nonce_addr = nonce as *const _ as u64; - let bn_u_ptr = new_u32_bignum(11); - let bn_u_addr = &bn_u_ptr as *const _ as u64; - let bn_a_ptr = new_u32_bignum(59); - let bn_a_addr = &bn_a_ptr as *const _ as u64; - let bn_n_ptr = new_u32_bignum(7); - let bn_n_addr = &bn_n_ptr as *const _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: bn_u_addr, - vm_addr: 2048, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bn_a_addr, - vm_addr: 4096, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bn_n_addr, - vm_addr: 8192, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: nonce_addr, - vm_addr: 1024, - len: nonce.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: hg_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); - let mut syscall = SyscallBigNumHg { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(2048, 4096, 8192, 1024, 96, &memory_mapping, &mut result); - result.unwrap(); - let braw: &BigNum = unsafe { &*(hg_addr as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(0).unwrap()); - } #[test] fn test_syscall_bignum_drop() { let mut bn = new_bignum(); @@ -5099,148 +4770,5 @@ mod tests { syscall.call(96, 0, 0, 0, 0, &memory_mapping, &mut result); result.unwrap(); assert_eq!(bn, 0); - // println!("After drop BigNum address = {}", bn); - } - - #[test] - fn test_syscall_blake3_digest() { - let data = [7u8, 3u8, 1u8, 15u8]; - let data_len = data.len(); - let data_len_addr = &data_len as *const _ as u64; - let digest = [0u8; 32]; - let mut digest_len = digest.len(); - let digest_len_addr = &mut digest_len as *mut _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: data.as_ptr() as *const _ as u64, - vm_addr: 8, - len: data_len as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: data_len_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: digest.as_ptr() as *const _ as u64, - vm_addr: 16, - len: digest_len as u64, - vm_gap_shift: 63, - is_writable: true, - }, - MemoryRegion { - host_addr: digest_len_addr, - vm_addr: 1024, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); - let mut syscall = SyscallBlake3Digest { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(8, 96, 16, 1024, 0, &memory_mapping, &mut result); - result.unwrap(); - let resb = digest[0..digest_len].to_vec(); - assert_eq!( - resb, - vec![ - 19, 245, 57, 187, 33, 163, 77, 67, 98, 172, 159, 13, 83, 252, 212, 176, 31, 81, - 186, 58, 239, 119, 15, 13, 212, 68, 167, 226, 233, 141, 216, 51 - ] - ); - // println!("This is result {:?}", resb); - } - #[test] - fn test_syscall_bignum_hash_to_prime() { - let nonce = b"hash_to_prime"; - let mut htp = nonce.len() as u64; - let htp_addr = &mut htp as *mut _ as u64; - let nonce_addr = nonce as *const _ as u64; - let bn_u_ptr = new_u32_bignum(11); - let bn_u_addr = &bn_u_ptr as *const _ as u64; - let bn_a_ptr = new_u32_bignum(59); - let bn_a_addr = &bn_a_ptr as *const _ as u64; - let bn_z_ptr = new_u32_bignum(7); - let bn_z_addr = &bn_z_ptr as *const _ as u64; - - let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: bn_u_addr, - vm_addr: 2048, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bn_a_addr, - vm_addr: 4096, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bn_z_addr, - vm_addr: 8192, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: nonce_addr, - vm_addr: 1024, - len: nonce.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: htp_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: 10_000 as u64, - })); - let mut syscall = SyscallBigNumberHashToPrime { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(2048, 4096, 8192, 1024, 96, &memory_mapping, &mut result); - result.unwrap(); - let braw: &BigNum = unsafe { &*(htp as *mut BigNum) }; - assert_eq!( - *braw, - BigNum::from_dec_str( - "23816539405324371056039456701279617701270933313491427172544877039730238224951" - ) - .unwrap() - ); - // println!("Hash to prime = {:?}", braw); } } diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 2256427eb6372a..2466c50970c175 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -511,38 +511,6 @@ static uint64_t sol_bignum_to_bytes( const uint64_t *byte_len ); -/** - * @param u_ptr bignum address - * @param a_ptr bignum address - * @param n_ptr bignum address - * @param nonce_ptr - * @param hg_ptr hashed generated return bignum address - */ - -static uint64_t sol_bignum_hashed_generator ( - const uint64_t *u_ptr, - const uint64_t *a_ptr, - const uint64_t *n_ptr, - const uint64_t *nonce_ptr, - const uint64_t *hg_ptr -); - -/** - * @param u_ptr bignum address - * @param a_ptr bignum address - * @param z_ptr bignum address - * @param nonce_ptr - * @param htp_ptr prime generated return bignum address - */ - -static uint64_t sol_bignum_hash_to_prime ( - const uint64_t *u_ptr, - const uint64_t *a_ptr, - const uint64_t *z_ptr, - const uint64_t *nonce_ptr, - const uint64_t *htp_ptr -); - /** * BigNum sol_bignum_add * Performs add and returns bignum for sum @@ -610,7 +578,7 @@ static uint64_t sol_bignum_exp( /** * BigNum sol_bignum_sqr * @param self_ptr self bignum address - c + * @param uint64_t *sqr_res_ptr */ static uint64_t sol_bignum_sqr( const uint64_t *self_ptr, @@ -671,7 +639,6 @@ static uint64_t sol_bignum_drop( const uint64_t *ptr ); - /** * Account Meta */ diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 06c4144761e020..5d8b325199a806 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -8,7 +8,6 @@ use std::fmt; BorshSerialize, BorshDeserialize, BorshSchema, - // Clone, Default, Eq, PartialEq, @@ -364,10 +363,7 @@ impl BigNumber { #[cfg(target_arch = "bpf")] { extern "C" { - fn sol_bignum_sqr( - self_ptr: *const u64, - modulus_ptr: *const u64, - ) -> u64; + fn sol_bignum_sqr(self_ptr: *const u64, modulus_ptr: *const u64) -> u64; } let mut bignum_ptr = 0u64; unsafe { @@ -500,139 +496,6 @@ impl BigNumber { Self(*bignum_ptr) } } - /// Hashed Generator - pub fn hashed_generator(&self, a: &BigNumber, n: &BigNumber, nonce: &[u8]) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use hkdf::Hkdf; - use openssl::bn::{BigNum, BigNumContext}; - - let u_bn = unsafe { &*(self.0 as *mut BigNum) }; - let a_bn = unsafe { &*(a.0 as *mut BigNum) }; - let n_bn = unsafe { &*(n.0 as *mut BigNum) }; - println!("u:{}", u_bn); - println!("a:{}", a_bn); - println!("n:{}", n_bn); - // hash_generator - let mut transcript = u_bn.as_ref().to_vec(); - transcript.append(&mut a_bn.as_ref().to_vec()); - transcript.extend_from_slice(nonce); - println!("t:{:?}", transcript); - let length = n_bn.num_bytes(); - println!("len:{}", length); - let h = Hkdf::::new( - Some(b"SST_SALT_HASH_TO_GENERATOR_"), - transcript.as_slice().as_ref(), - ); - let mut okm = vec![0u8; length as usize]; - h.expand(b"", &mut okm).unwrap(); - println!("okm:{:?}", okm); - let okm_bn = BigNum::from_slice(okm.as_slice()).unwrap(); - - let mut res_bn = Box::new(BigNum::new().unwrap()); - res_bn - .mod_sqr( - okm_bn.as_ref(), - n_bn.as_ref(), - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(res_bn); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_hashed_generator( - self_ptr: *const u64, - a: *const u64, - n: *const u64, - nonce: *const u64, - hg_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = nonce.len() as u64; - unsafe { - sol_bignum_hashed_generator( - &self.0 as *const _ as *const u64, - &a.0 as *const _ as *const u64, - &n.0 as *const _ as *const u64, - nonce as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } - - /// Hash to Prime - pub fn hash_to_prime(u: &BigNumber, a: &BigNumber, z: &BigNumber, nonce: &[u8]) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use blake3::traits::digest::Digest; - use openssl::bn::{BigNum, BigNumContext}; - let u_bn = unsafe { &*(u.0 as *mut BigNum) }; - let a_bn = unsafe { &*(a.0 as *mut BigNum) }; - let z_bn = unsafe { &*(z.0 as *mut BigNum) }; - - let mut input = u_bn.as_ref().to_vec(); - input.extend_from_slice(&a_bn.as_ref().to_vec()); - input.extend_from_slice(&z_bn.as_ref().to_vec()); - input.extend_from_slice(nonce); - // println!("t:{:?}",input); - - let mut i = 1u32; - let offset = input.len(); - input.extend_from_slice(&i.to_be_bytes()[..]); - let end = input.len(); - let ctx = &mut BigNumContext::new().unwrap(); - let mut num; - loop { - let mut hash = blake3::Hasher::digest(input.as_slice()); - // Force it to be odd - hash[31] |= 1; - // Only need 256 bits just borrow the bottom 32 bytes - // There should be plenty of primes below 2^256 - // and we want this to be reasonably fast - //num = BigNumber::from_bytes(&hash[32..]); - num = BigNum::from_slice(&hash).unwrap(); - if num.is_prime(15, ctx).unwrap() { - // msg!("num_bytes:{:?}",num.to_bytes().to_vec()); - // msg!("i:{}",i); - break; - } - i += 1; - let i_bytes = i.to_be_bytes(); - input[offset..end].clone_from_slice(&i_bytes[..]); - } - let res_bn = Box::new(num); - let rwptr = Box::into_raw(res_bn); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_hash_to_prime( - u: *const u64, - a: *const u64, - z: *const u64, - nonce: *const u64, - htp_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = nonce.len() as u64; - unsafe { - sol_bignum_hash_to_prime( - &u.0 as *const _ as *const u64, - &a.0 as *const _ as *const u64, - &z.0 as *const _ as *const u64, - nonce as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } /// Log a `BigNum` from a program pub fn log(&self) { @@ -716,38 +579,6 @@ impl Clone for BigNumber { } } -/// Returns an array of bytes (big endian) of self -pub fn blake3_digest(data: &[u8]) -> Vec { - #[cfg(not(target_arch = "bpf"))] - { - use blake3::traits::digest::Digest; - blake3::Hasher::digest(data).to_vec() - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_blake3_digest( - data_ptr: *const u8, - data_len: *const u64, - digest_ptr: *mut u8, - digest_len: *mut u64, - ) -> u64; - } - let data_len = data.len(); - let mut digest = [0u8; 32]; - let mut digest_len = digest.len(); - unsafe { - sol_blake3_digest( - data.as_ptr() as *const _ as *const u8, - &data_len as *const _ as *const u64, - digest.as_mut_ptr() as *mut _ as *mut u8, - &mut digest_len as *mut _ as *mut u64, - ); - }; - digest[0..digest_len].to_vec() - } -} - #[cfg(test)] mod tests { use super::*; @@ -757,16 +588,6 @@ mod tests { println!("{:?}", bn1); } - #[test] - fn test_bignumber_hashed_generator() { - let bn_u = BigNumber::from_u32(11); - let bn_a = BigNumber::from_u32(59); - let bn_n = BigNumber::from_u32(7); - let nonce = b"hgen"; - let result = bn_u.hashed_generator(&bn_a, &bn_n, nonce); - println!("Hashed generator result = {}", result); - } - #[test] fn test_bignumber_clone() { let bn_u = BigNumber::from_u32(11); diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index 56fc738af512c8..140430ba5a1cb1 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -197,12 +197,6 @@ pub struct BpfComputeBudget { pub bignum_mod_mul_cost: u64, /// Number of compute units consumed by BigNum mod_inv pub bignum_mod_inv_cost: u64, - /// Number of compute units consumed by BigNum hashed_generator - pub bignum_hashed_generator_cost: u64, - /// Number of compute units consumed by Blake3 digest - pub blake3_digest_base_cost: u64, - /// Number of compute units consumed by BigNum hash_to_prime - pub bignum_hash_to_prime_cost: u64, } impl Default for BpfComputeBudget { fn default() -> Self { @@ -231,7 +225,7 @@ impl BpfComputeBudget { bignum_from_u32_base_cost: 100, bignum_from_bytes_base_cost: 100, bignum_to_bytes_base_cost: 100, - bignum_mod_exp_base_cost: 100, + bignum_mod_exp_base_cost: 100, log_bignum_cost: 100, bignum_add_cost: 15, bignum_sub_cost: 15, @@ -242,9 +236,6 @@ impl BpfComputeBudget { bignum_mod_sqr_cost: 30, bignum_mod_mul_cost: 45, bignum_mod_inv_cost: 45, - bignum_hashed_generator_cost: 100, - blake3_digest_base_cost: 85, - bignum_hash_to_prime_cost: 20000, } } } From 61b56c026ddb522070e766a2d3fe58a68de1a450 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 06:56:56 -0400 Subject: [PATCH 07/45] Remove println statements --- programs/bpf_loader/src/syscalls.rs | 23 ++--------------------- sdk/program/src/bignum.rs | 3 --- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 0fe28f5f9e8c2a..a2fe5edb8a1280 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1878,10 +1878,7 @@ impl<'a> SyscallObject for SyscallBigNumModInv<'a> { *result_mod_sqr_address = mod_sqr_ptr; *result = Ok(0) } - Err(_e) => { - // println!("{}", e); - *result = Err(SyscallError::BigNumberModInvError.into()) - } + Err(_e) => *result = Err(SyscallError::BigNumberModInvError.into()), }; } } @@ -4143,21 +4140,18 @@ mod tests { fn test_syscall_bignum_new() { let bn = new_bignum(); let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; - println!("New BigNum with 0 {:?}", braw); } #[test] fn test_syscall_bignum_from_u32() { let bn = new_u32_bignum(20u32); let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; - println!("Reconst {:?}", braw); } #[test] fn test_syscall_bignum_from_bytes() { let val = [0u8, 0u8, 1u8, 0u8]; let bn = new_bytes_bignum(&val); let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; - println!("Reconst {:?}", braw); } #[test] fn test_syscall_bignum_to_bytes() { @@ -4271,8 +4265,7 @@ mod tests { let mut result: Result> = Ok(0); syscall.call(96, 8, 16, 24, 0, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; - println!("Reconst {:?}", braw); + let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; } #[test] @@ -4324,7 +4317,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(sum as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(5).unwrap()); - // println!("2+3 = {:?}", braw); } #[test] fn test_syscall_bignum_sub() { @@ -4375,7 +4367,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(diff as *mut BigNum) }; assert_eq!(*braw, BigNum::from_dec_str("-1").unwrap()); - // println!("2-3 = {:?}", braw); } #[test] fn test_syscall_bignum_mul() { @@ -4426,7 +4417,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(prod as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(6).unwrap()); - // println!("2*3 = {:?}", braw); } #[test] fn test_syscall_bignum_div() { @@ -4477,7 +4467,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(quot as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(2).unwrap()); - // println!("4/2 = {:?}", braw); } #[test] fn test_syscall_bignum_exp() { @@ -4528,7 +4517,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(exp as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(16).unwrap()); - // println!("4^2 = {:?}", braw); } #[test] fn test_syscall_bignum_sqr() { @@ -4570,7 +4558,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(sqr as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(16).unwrap()); - // println!("4^2 = {:?}", braw); } #[test] fn test_syscall_bignum_mod_sqr() { @@ -4622,7 +4609,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(mod_sqr as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(1).unwrap()); - // println!("(15 % 7)^2 = {:?}", braw); } #[test] @@ -4683,7 +4669,6 @@ mod tests { result.unwrap(); let braw: &BigNum = unsafe { &*(mod_mul as *mut BigNum) }; assert_eq!(*braw, BigNum::from_u32(2).unwrap()); - // println!("(3 * 3) % 7 = {:?}", braw); } #[test] #[should_panic(expected = "UserError(SyscallError(BigNumberModInvError))")] @@ -4733,8 +4718,6 @@ mod tests { let mut result: Result> = Ok(0); syscall.call(8, 32, 96, 0, 0, &memory_mapping, &mut result); result.unwrap(); - // let braw: &BigNum = unsafe { &*(mod_inv as *mut BigNum) }; - // println!("(9 % 7)^2 = {:?}", braw); } #[test] @@ -4742,9 +4725,7 @@ mod tests { let mut bn = new_bignum(); let bn_addr = &mut bn as *mut _ as u64; assert_ne!(bn, 0); - println!("After new BigNum address = {}", bn); let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; - println!("New BigNum initialized to {:?}", braw); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: bn_addr, diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 5d8b325199a806..5d52b5df65ba73 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -585,14 +585,11 @@ mod tests { #[test] fn test_bignumber_new() { let bn1 = BigNumber::new(); - println!("{:?}", bn1); } #[test] fn test_bignumber_clone() { let bn_u = BigNumber::from_u32(11); let bn_u2 = bn_u.clone(); - println!("bn_u = {}", bn_u); - println!("bn_u2 = {}", bn_u2); } } From 2d8b538e34b358de2f64b353daec7243aa204c65 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 07:02:19 -0400 Subject: [PATCH 08/45] Fix check failures --- sdk/program/src/bignum.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 5d52b5df65ba73..2c7b0f76e2d62d 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -585,11 +585,13 @@ mod tests { #[test] fn test_bignumber_new() { let bn1 = BigNumber::new(); + assert_eq!(bn1.to_bytes(), BigNumber::new().to_bytes()); } #[test] fn test_bignumber_clone() { let bn_u = BigNumber::from_u32(11); let bn_u2 = bn_u.clone(); + assert_eq!(bn_u2.to_bytes(), bn_u.to_bytes()); } } From 2fffc0aa0b923a26c7deff9324b5a11cc6642dd5 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 07:11:51 -0400 Subject: [PATCH 09/45] Fix unused var check failures --- programs/bpf_loader/src/syscalls.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index a2fe5edb8a1280..e6ce8f7b87cdd3 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4139,19 +4139,19 @@ mod tests { #[test] fn test_syscall_bignum_new() { let bn = new_bignum(); - let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; } #[test] fn test_syscall_bignum_from_u32() { let bn = new_u32_bignum(20u32); - let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; } #[test] fn test_syscall_bignum_from_bytes() { let val = [0u8, 0u8, 1u8, 0u8]; let bn = new_bytes_bignum(&val); - let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; } #[test] fn test_syscall_bignum_to_bytes() { @@ -4725,7 +4725,6 @@ mod tests { let mut bn = new_bignum(); let bn_addr = &mut bn as *mut _ as u64; assert_ne!(bn, 0); - let braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: bn_addr, From 4ce98c8d1cca17a588cec41f20ac3cc57721d853 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 07:21:15 -0400 Subject: [PATCH 10/45] Removed hkdf as hashes removed from bignum and correct BPF test --- Cargo.lock | 31 ----------------------------- programs/bpf/rust/bignum/src/lib.rs | 1 - sdk/program/Cargo.toml | 1 - 3 files changed, 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87a016c4122a88..a1da5524e8ebfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -873,16 +873,6 @@ dependencies = [ "subtle 2.2.2", ] -[[package]] -name = "crypto-mac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" -dependencies = [ - "generic-array 0.14.3", - "subtle 2.2.2", -] - [[package]] name = "csv" version = "1.1.3" @@ -1679,16 +1669,6 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" -[[package]] -name = "hkdf" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" -dependencies = [ - "digest 0.9.0", - "hmac 0.11.0", -] - [[package]] name = "hmac" version = "0.7.1" @@ -1729,16 +1709,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.0", - "digest 0.9.0", -] - [[package]] name = "hmac-drbg" version = "0.2.0" @@ -4999,7 +4969,6 @@ dependencies = [ "bv", "curve25519-dalek 2.1.0", "hex", - "hkdf", "itertools", "lazy_static", "log 0.4.11", diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 450894bb7be43b..85c2a38b7b407c 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -70,7 +70,6 @@ fn test_complex_maths() { assert_eq!(base_15.sqr().to_bytes(), [225]); assert_eq!(base_15.exp(&base_2).to_bytes(), [13, 47]); assert_eq!(base_3.mod_inv(&modulus_7).to_bytes(), [5]); - assert!(true); } #[no_mangle] diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 9e9801a29ee8b7..1dda229f47d8a3 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -37,7 +37,6 @@ blake3 = "0.3.7" curve25519-dalek = "2.1.0" rand = "0.7.0" solana-logger = { path = "../../logger", version = "=1.7.0" } -hkdf = "0.11.0" num-bigint = "0.4.0" openssl = "0.10.32" From a1725b100b2c3cc0ecdc500e6a49890ceef3f414 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 07:32:53 -0400 Subject: [PATCH 11/45] Removed hkdf ref --- programs/bpf/Cargo.lock | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index ab6b76fe104966..72547c028cc677 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -1233,16 +1233,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "hkdf" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" -dependencies = [ - "digest 0.9.0", - "hmac 0.11.0", -] - [[package]] name = "hmac" version = "0.7.1" @@ -3405,7 +3395,6 @@ dependencies = [ "bv", "curve25519-dalek 2.1.0", "hex", - "hkdf", "itertools 0.9.0", "lazy_static", "log", From ff09a5728fcf1f1f782b80af717411dbbbf85808 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 13 May 2021 07:42:58 -0400 Subject: [PATCH 12/45] Fixes for Cargo.lock --- programs/bpf/Cargo.lock | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 72547c028cc677..f5109b2d159dc3 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -651,16 +651,6 @@ dependencies = [ "subtle 2.2.2", ] -[[package]] -name = "crypto-mac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" -dependencies = [ - "generic-array 0.14.3", - "subtle 2.2.2", -] - [[package]] name = "curve25519-dalek" version = "2.1.0" @@ -1273,16 +1263,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.0", - "digest 0.9.0", -] - [[package]] name = "hmac-drbg" version = "0.2.0" From 1d13a79081560fae20d413a186feacf0cb617c7f Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Fri, 14 May 2021 09:34:52 -0400 Subject: [PATCH 13/45] Fixed BigNumToString syscall buffer overflow --- programs/bpf/rust/bignum/src/lib.rs | 11 +- programs/bpf_loader/src/syscalls.rs | 164 +++++++++++++++++++++++----- sdk/bpf/c/inc/solana_sdk.h | 11 ++ sdk/program/src/bignum.rs | 41 +++++-- sdk/src/process_instruction.rs | 3 + 5 files changed, 191 insertions(+), 39 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 85c2a38b7b407c..1eaf8a04276654 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -28,8 +28,13 @@ fn test_constructors() { new_bn_0.log(); let max_bn_u32 = BigNumber::from_u32(u32::MAX); max_bn_u32.log(); - let new_bn_from_long_str = BigNumber::from_bytes(LONG_DEC_STRING.as_bytes()); + let big_string_as_bytes = LONG_DEC_STRING.as_bytes(); + let new_bn_from_long_str = BigNumber::from_bytes(big_string_as_bytes); new_bn_from_long_str.log(); + let new_bn_size = new_bn_from_long_str.size_in_bytes(); + assert_eq!(new_bn_size, big_string_as_bytes.len()); + let new_long_str_from_bn = new_bn_from_long_str.to_bytes(); + assert_eq!(new_long_str_from_bn, big_string_as_bytes); let empty_bn = BigNumber::from_bytes(&[0u8]); empty_bn.log(); } @@ -54,7 +59,6 @@ fn test_basic_maths() { /// BigNumber bigger numbers and complex maths fn test_complex_maths() { msg!("BigNumber Complex Maths"); - let base_2 = BigNumber::from_u32(3); let base_3 = BigNumber::from_u32(3); let exp_base_3 = base_3.clone(); let modulus_7 = BigNumber::from_u32(7); @@ -67,9 +71,6 @@ fn test_complex_maths() { &base_15.mod_sqr(&modulus_7), &BigNumber::from_u32(1) )); - assert_eq!(base_15.sqr().to_bytes(), [225]); - assert_eq!(base_15.exp(&base_2).to_bytes(), [13, 47]); - assert_eq!(base_3.mod_inv(&modulus_7).to_bytes(), [5]); } #[no_mangle] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index e6ce8f7b87cdd3..a7fff9e1c23ac6 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -77,6 +77,8 @@ pub enum SyscallError { TooManyAccounts, #[error("BigNumber: Modular exponentiation error")] BigNumberModExpError, + #[error("BigNumber: Bytes would exceed buffer provided")] + BigNumberToBytesError, #[error("BigNumber: add error")] BigNumberAddError, #[error("BigNumber: sub error")] @@ -175,6 +177,8 @@ pub fn register_syscalls( // Bignum syscall names syscall_registry.register_syscall_by_name(b"sol_bignum_new", SyscallBigNumNew::call)?; + syscall_registry + .register_syscall_by_name(b"sol_bignum_size_in_bytes", SyscallBigNumSizeInBytes::call)?; syscall_registry .register_syscall_by_name(b"sol_bignum_from_u32", SyscallBigNumFromU32::call)?; syscall_registry @@ -309,6 +313,14 @@ pub fn bind_syscall_context_objects<'a>( }), None, )?; + vm.bind_syscall_context_object( + Box::new(SyscallBigNumSizeInBytes { + cost: bpf_compute_budget.bignum_size_base_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + None, + )?; vm.bind_syscall_context_object( Box::new(SyscallBigNumFromU32 { cost: bpf_compute_budget.bignum_from_u32_base_cost, @@ -1167,7 +1179,38 @@ impl<'a> SyscallObject for SyscallBigNumNew<'a> { *result = Ok(0) } } - +/// BigNum size in bytes returns the number of bytes +/// used by a BigNum +struct SyscallBigNumSizeInBytes<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumSizeInBytes<'a> { + fn call( + &mut self, + bn_self: u64, + bytes_len_addr: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); + let self_bignum_address = question_mark!( + translate_type::(memory_mapping, bn_self, self.loader_id, true), + result + ); + let bytes_len = question_mark!( + translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), + result + ); + let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; + *bytes_len = bn_self.num_bytes() as u64; + *result = Ok(0) + } +} struct SyscallBigNumFromU32<'a> { cost: u64, compute_meter: Rc>, @@ -1238,6 +1281,7 @@ impl<'a> SyscallObject for SyscallBigNumFromBytes<'a> { *result = Ok(0) } } + struct SyscallBigNumToBytes<'a> { cost: u64, compute_meter: Rc>, @@ -1258,29 +1302,40 @@ impl<'a> SyscallObject for SyscallBigNumToBytes<'a> { translate_type::(memory_mapping, bn_self, self.loader_id, true), result ); - let bytes_len = question_mark!( - translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), + let bytes_buffer = question_mark!( + translate_slice_mut::( + memory_mapping, + bytes_addr, + *question_mark!( + translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), + result + ), + self.loader_id, + true + ), result ); - let bytes_buffer = question_mark!( - translate_slice_mut::(memory_mapping, bytes_addr, *bytes_len, self.loader_id, true), + let bytes_len = question_mark!( + translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), result ); + let in_length = *bytes_len; let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; let bn_bytes = bn_self.as_ref().to_vec(); - let bytes = bn_bytes.len() as f64; + let out_length = bn_bytes.len() as u64; question_mark!( self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), + .consume(self.cost + calc_bignum_cost!(out_length as f64)), result ); - let mut index = 0; - for byte in bn_bytes.iter() { - bytes_buffer[index] = *byte; - index += 1; + if in_length != out_length { + *bytes_len = 0u64; + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + (*bytes_buffer).copy_from_slice(&bn_bytes); + *bytes_len = out_length; + *result = Ok(0) } - *bytes_len = index as u64; - *result = Ok(0) } } @@ -3082,6 +3137,17 @@ mod tests { enable_instruction_meter: true, enable_instruction_tracing: false, }; + const LONG_DEC_STRING: &str = + "1470463693494555670176851280755142329532258274256991544781479988\ + 712408107190720087233560906792937436573943189716784305633216335039\ + 300236370809933808677983409391545753391897467230180786617074456716\ + 591448871466263060696957107957862111484694673874424855359234132302\ + 162208163361387727626078022804936564470716886986414133429438273232\ + 416190048073715996321578752244853524209178212395809614878549824744\ + 227969245726015222693764433413133633359171080169137831743765672068\ + 374040331773668233371864426354886263106537340208256187214278963052\ + 996538599452325797319977413534714912781503130883692806087195354368\ + 8304190675878204079994222"; macro_rules! assert_access_violation { ($result:expr, $va:expr, $len:expr) => { @@ -4112,7 +4178,7 @@ mod tests { }, MemoryRegion { host_addr: val_array.as_ptr() as *const _ as u64, - vm_addr: 8, + vm_addr: 1024, len: val_len as u64, vm_gap_shift: 63, is_writable: false, @@ -4124,7 +4190,7 @@ mod tests { let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, + remaining: (400) as u64, })); let mut syscall = SyscallBigNumFromBytes { cost: 1, @@ -4132,7 +4198,7 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, 8, val_len as u64, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 1024, val_len as u64, 0, 0, &memory_mapping, &mut result); result.unwrap(); bn } @@ -4142,6 +4208,48 @@ mod tests { let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; } + #[test] + fn test_syscall_bignum_size_in_bytes() { + let val = LONG_DEC_STRING.as_bytes(); + let mut bn = new_bytes_bignum(val); + let bn_addr = &mut bn as *mut _ as u64; + let mut bytes_len = 0u64; + let bytes_len_addr = &mut bytes_len as *mut _ as u64; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: bn_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bytes_len_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (400) as u64, + })); + let mut syscall = SyscallBigNumSizeInBytes { + cost: 100, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call(8, 96, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + assert_eq!(bytes_len, val.len() as u64); + } + #[test] fn test_syscall_bignum_from_u32() { let bn = new_u32_bignum(20u32); @@ -4155,31 +4263,33 @@ mod tests { } #[test] fn test_syscall_bignum_to_bytes() { - let val = [0u8, 0u8, 1u8, 0u8]; - let mut bn = new_bytes_bignum(&val); + let val = LONG_DEC_STRING.as_bytes(); + let mut bn = new_bytes_bignum(val); let bn_addr = &mut bn as *mut _ as u64; - let bytes_buf = [0u8; 256]; + let big_num: &BigNum = unsafe { &*(bn as *mut BigNum) }; + let existing_size = big_num.num_bytes() as usize; + let bytes_buf = vec![0u8; existing_size]; let mut bytes_len = bytes_buf.len(); let bytes_len_addr = &mut bytes_len as *mut _ as u64; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { host_addr: bn_addr, - vm_addr: 1024, + vm_addr: 8, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { host_addr: bytes_buf.as_ptr() as *const _ as u64, - vm_addr: 8, + vm_addr: 1024, len: bytes_len as u64, vm_gap_shift: 63, is_writable: true, }, MemoryRegion { host_addr: bytes_len_addr, - vm_addr: 2048, + vm_addr: 96, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -4191,18 +4301,18 @@ mod tests { let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, + remaining: (400) as u64, })); let mut syscall = SyscallBigNumToBytes { - cost: 1, + cost: 100, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(1024, 8, 2048, 0, 0, &memory_mapping, &mut result); + syscall.call(8, 1024, 96, 0, 0, &memory_mapping, &mut result); result.unwrap(); - let resb = bytes_buf[0..bytes_len].to_vec(); - assert_eq!(1, resb[0]); + assert_eq!(bytes_len, val.len()); + assert_eq!(big_num.as_ref().to_vec(), bytes_buf.to_vec()); } #[test] diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 2466c50970c175..d9d12a587549f1 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -464,6 +464,17 @@ static uint64_t sol_bignum_new( const uint64_t *ptr ); +/** + * BigNum sol_bignum_size_in_bytes + * + * @param self_ptr address of the BigNum ptr + * @parm byte_len address of where to return size + */ +static uint64_t sol_bignum_size_in_bytes( + const uint64_t *self_ptr, + const uint64_t *byte_len +); + /** * BigNum sol_bignum_from_u32 * diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 2c7b0f76e2d62d..f05a0c3461959e 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -43,6 +43,31 @@ impl BigNumber { } } + /// Returns the size, in bytes, of BigNum. Typically used in + /// assessing buffer size needed to fetch the bytes for serialization, etc. + pub fn size_in_bytes(&self) -> usize { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let self_bignum: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + self_bignum.num_bytes() as usize + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_size_in_bytes(bignum_ptr: *const u64, bytes_len: *mut u64) -> u64; + } + let mut bignum_size = 0u64; + unsafe { + sol_bignum_size_in_bytes( + &self.0 as *const _ as *const u64, + &mut bignum_size as *mut _ as *mut u64, + ); + } + bignum_size as usize + } + } + /// Returns a BigNumber with initial value set to a u32 value pub fn from_u32(val: u32) -> Self { #[cfg(not(target_arch = "bpf"))] @@ -97,7 +122,7 @@ impl BigNumber { } } - /// Returns an array of bytes (big endian) of self + /// Returns an array of bytes of self pub fn to_bytes(&self) -> Vec { #[cfg(not(target_arch = "bpf"))] { @@ -114,16 +139,18 @@ impl BigNumber { bytes_len: *mut u64, ) -> u64; } - let mut my_buffer = [0u8; 256]; - let mut my_buffer_len = my_buffer.len(); + // Get the BigNum size, allocate result vector + let mut bignum_size = self.size_in_bytes() as u64; + let mut my_buffer = Vec::::with_capacity(bignum_size as usize); unsafe { sol_bignum_to_bytes( &self.0 as *const _ as *const u64, - &mut my_buffer as *mut _ as *mut u8, - &mut my_buffer_len as *mut _ as *mut u64, + my_buffer.as_mut_ptr() as *mut _ as *mut u8, + &mut bignum_size as *mut _ as *mut u64, ); - }; - my_buffer[0..my_buffer_len].to_vec() + my_buffer.set_len(bignum_size as usize); + } + my_buffer.clone() } } diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index 140430ba5a1cb1..c7ff58f5a5bba7 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -167,6 +167,8 @@ pub struct BpfComputeBudget { pub sysvar_base_cost: u64, /// Base number of compute units consumed to call BIGNUM NEW pub bignum_new_base_cost: u64, + /// Base number of compute units consumed to call BigNum size in bytes query + pub bignum_size_base_cost: u64, /// Base number of compute units consumed to call BigNum new from u32 value pub bignum_from_u32_base_cost: u64, /// Base number of compute units consumed to call BigNum new from big endian byte array @@ -221,6 +223,7 @@ impl BpfComputeBudget { cpi_bytes_per_unit: 250, // ~50MB at 200,000 units sysvar_base_cost: 100, bignum_new_base_cost: 100, + bignum_size_base_cost: 100, bignum_drop_base_cost: 100, bignum_from_u32_base_cost: 100, bignum_from_bytes_base_cost: 100, From 6011f784e5428ea00ca0deb75f46254d71292f83 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Fri, 14 May 2021 10:05:43 -0400 Subject: [PATCH 14/45] Fix formatting --- programs/bpf_loader/src/syscalls.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index a7fff9e1c23ac6..f1e679c33d12b4 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4189,9 +4189,7 @@ mod tests { .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (400) as u64, - })); + Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); let mut syscall = SyscallBigNumFromBytes { cost: 1, compute_meter, @@ -4236,9 +4234,7 @@ mod tests { ) .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (400) as u64, - })); + Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); let mut syscall = SyscallBigNumSizeInBytes { cost: 100, compute_meter, @@ -4300,9 +4296,7 @@ mod tests { .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (400) as u64, - })); + Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); let mut syscall = SyscallBigNumToBytes { cost: 100, compute_meter, From ca1944e7ca3eee829e9d5c37033f956e12222c6f Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Sat, 15 May 2021 07:50:09 -0400 Subject: [PATCH 15/45] BigNumber new and from_u32 using vectors instead of Box --- programs/bpf/rust/bignum/src/lib.rs | 122 ++-- programs/bpf_loader/src/syscalls.rs | 592 ++++++--------- sdk/bpf/c/inc/solana_sdk.h | 12 +- sdk/program/src/bignum.rs | 1048 ++++++++++++++------------- sdk/src/process_instruction.rs | 16 +- 5 files changed, 819 insertions(+), 971 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 1eaf8a04276654..ce151095d0e9f9 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -3,7 +3,7 @@ extern crate solana_program; use solana_program::{bignum::BigNumber, custom_panic_default, msg}; -const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ +const _LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ 300236370809933808677983409391545753391897467230180786617074456716\ 591448871466263060696957107957862111484694673874424855359234132302\ @@ -15,70 +15,78 @@ const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256 8304190675878204079994222"; /// Compares the array of numbers return from BigNumbers -fn compare_bignum_equal(lhs: &BigNumber, rhs: &BigNumber) -> bool { - lhs.to_bytes() == rhs.to_bytes() -} +// fn compare_bignum_equal(lhs: &BigNumber, rhs: &BigNumber) -> bool { +// lhs.to_bytes() == rhs.to_bytes() +// } /// BigNumber construction fn test_constructors() { msg!("BigNumber constructors"); let base_bn_0 = BigNumber::new(); - base_bn_0.log(); + msg!("base_bn_0 {}", base_bn_0); + let default_0 = BigNumber::default(); + msg!("default_0 {}", default_0); + // base_bn_0.log(); + // let empty_bn = BigNumber::from_bytes(&[0u8]); + // msg!("empty_bn {}", empty_bn); + // empty_bn.log(); let new_bn_0 = BigNumber::from_u32(0); - new_bn_0.log(); + msg!("new_bn_0 {}", new_bn_0); + // new_bn_0.log(); let max_bn_u32 = BigNumber::from_u32(u32::MAX); - max_bn_u32.log(); - let big_string_as_bytes = LONG_DEC_STRING.as_bytes(); - let new_bn_from_long_str = BigNumber::from_bytes(big_string_as_bytes); - new_bn_from_long_str.log(); - let new_bn_size = new_bn_from_long_str.size_in_bytes(); - assert_eq!(new_bn_size, big_string_as_bytes.len()); - let new_long_str_from_bn = new_bn_from_long_str.to_bytes(); - assert_eq!(new_long_str_from_bn, big_string_as_bytes); - let empty_bn = BigNumber::from_bytes(&[0u8]); - empty_bn.log(); + msg!("max_bn_u32 {:?}", max_bn_u32.to_bytes()); + // max_bn_u32.log(); + // msg!("Big string len = {}", LONG_DEC_STRING.len()); + // let big_string_as_bytes = LONG_DEC_STRING.as_bytes(); + // let new_bn_from_long_str = BigNumber::from_bytes(big_string_as_bytes); + // let new_bn_size = new_bn_from_long_str.size_in_bytes(); + // msg!("Big string size in bytes = {}", new_bn_size); + // new_bn_from_long_str.log(); + // assert_eq!(new_bn_size, big_string_as_bytes.len()); + // let new_long_str_from_bn = new_bn_from_long_str.to_bytes(); + // assert_eq!(new_long_str_from_bn, big_string_as_bytes); } /// BigNumber simple number and simple maths -fn test_basic_maths() { - msg!("BigNumber Basic Maths"); - let lhs = BigNumber::from_u32(3); - let rhs = BigNumber::from_u32(4); - let add_res = lhs.add(&rhs); - assert!(compare_bignum_equal(&add_res, &BigNumber::from_u32(7))); - let sub_res = rhs.sub(&lhs); - assert!(compare_bignum_equal(&sub_res, &BigNumber::from_u32(1))); - let lhs = BigNumber::from_u32(20); - let rhs = BigNumber::from_u32(10); - let div_res = lhs.div(&rhs); - assert!(compare_bignum_equal(&div_res, &BigNumber::from_u32(2))); - let mul_res = rhs.mul(&lhs); - assert!(compare_bignum_equal(&mul_res, &BigNumber::from_u32(200))); -} +// fn test_basic_maths() { +// msg!("BigNumber Basic Maths"); +// let lhs = BigNumber::from_u32(3); +// let rhs = BigNumber::from_u32(4); +// let add_res = lhs.add(&rhs); +// assert!(compare_bignum_equal(&add_res, &BigNumber::from_u32(7))); +// let sub_res = rhs.sub(&lhs); +// assert!(compare_bignum_equal(&sub_res, &BigNumber::from_u32(1))); +// let lhs = BigNumber::from_u32(20); +// let rhs = BigNumber::from_u32(10); +// let div_res = lhs.div(&rhs); +// assert!(compare_bignum_equal(&div_res, &BigNumber::from_u32(2))); +// let mul_res = rhs.mul(&lhs); +// assert!(compare_bignum_equal(&mul_res, &BigNumber::from_u32(200))); +// } -/// BigNumber bigger numbers and complex maths -fn test_complex_maths() { - msg!("BigNumber Complex Maths"); - let base_3 = BigNumber::from_u32(3); - let exp_base_3 = base_3.clone(); - let modulus_7 = BigNumber::from_u32(7); - assert!(compare_bignum_equal( - &base_3.mod_mul(&exp_base_3, &modulus_7), - &BigNumber::from_u32(2) - )); - let base_15 = BigNumber::from_u32(15); - assert!(compare_bignum_equal( - &base_15.mod_sqr(&modulus_7), - &BigNumber::from_u32(1) - )); -} +// /// BigNumber bigger numbers and complex maths +// fn test_complex_maths() { +// msg!("BigNumber Complex Maths"); +// let base_3 = BigNumber::from_u32(3); +// let exp_base_3 = base_3.clone(); +// let modulus_7 = BigNumber::from_u32(7); +// assert!(compare_bignum_equal( +// &base_3.mod_mul(&exp_base_3, &modulus_7), +// &BigNumber::from_u32(2) +// )); +// let base_15 = BigNumber::from_u32(15); +// assert!(compare_bignum_equal( +// &base_15.mod_sqr(&modulus_7), +// &BigNumber::from_u32(1) +// )); +// } #[no_mangle] pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { msg!("bignum"); test_constructors(); - test_basic_maths(); - test_complex_maths(); + // test_basic_maths(); + // test_complex_maths(); 0u64 } @@ -92,12 +100,12 @@ mod test { fn test_basic_constructors_pass() { test_constructors(); } - #[test] - fn test_simple_maths_pass() { - test_basic_maths(); - } - #[test] - fn test_complex_maths_pass() { - test_complex_maths(); - } + // #[test] + // fn test_simple_maths_pass() { + // test_basic_maths(); + // } + // #[test] + // fn test_complex_maths_pass() { + // test_complex_maths(); + // } } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index f1e679c33d12b4..d210b559aa5cf1 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -176,17 +176,17 @@ pub fn register_syscalls( syscall_registry.register_syscall_by_name(b"sol_alloc_free_", SyscallAllocFree::call)?; // Bignum syscall names - syscall_registry.register_syscall_by_name(b"sol_bignum_new", SyscallBigNumNew::call)?; - syscall_registry - .register_syscall_by_name(b"sol_bignum_size_in_bytes", SyscallBigNumSizeInBytes::call)?; + // syscall_registry.register_syscall_by_name(b"sol_bignum_new", SyscallBigNumNew::call)?; + // syscall_registry + // .register_syscall_by_name(b"sol_bignum_size_in_bytes", SyscallBigNumSizeInBytes::call)?; syscall_registry .register_syscall_by_name(b"sol_bignum_from_u32", SyscallBigNumFromU32::call)?; syscall_registry .register_syscall_by_name(b"sol_bignum_from_bytes", SyscallBigNumFromBytes::call)?; - syscall_registry - .register_syscall_by_name(b"sol_bignum_to_bytes", SyscallBigNumToBytes::call)?; + // syscall_registry + // .register_syscall_by_name(b"sol_bignum_to_bytes", SyscallBigNumToBytes::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mod_exp", SyscallBigNumModExp::call)?; - syscall_registry.register_syscall_by_name(b"sol_bignum_drop", SyscallBigNumDrop::call)?; + // syscall_registry.register_syscall_by_name(b"sol_bignum_drop", SyscallBigNumDrop::call)?; syscall_registry.register_syscall_by_name(b"sol_log_bignum", SyscallLogBigNum::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_add", SyscallBigNumAdd::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_sub", SyscallBigNumSub::call)?; @@ -305,22 +305,22 @@ pub fn bind_syscall_context_objects<'a>( )?; // Bignum bindings - vm.bind_syscall_context_object( - Box::new(SyscallBigNumNew { - cost: bpf_compute_budget.bignum_new_base_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallBigNumSizeInBytes { - cost: bpf_compute_budget.bignum_size_base_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; + // vm.bind_syscall_context_object( + // Box::new(SyscallBigNumNew { + // cost: bpf_compute_budget.bignum_new_base_cost, + // compute_meter: invoke_context.get_compute_meter(), + // loader_id, + // }), + // None, + // )?; + // vm.bind_syscall_context_object( + // Box::new(SyscallBigNumSizeInBytes { + // cost: bpf_compute_budget.bignum_size_base_cost, + // compute_meter: invoke_context.get_compute_meter(), + // loader_id, + // }), + // None, + // )?; vm.bind_syscall_context_object( Box::new(SyscallBigNumFromU32 { cost: bpf_compute_budget.bignum_from_u32_base_cost, @@ -337,14 +337,14 @@ pub fn bind_syscall_context_objects<'a>( }), None, )?; - vm.bind_syscall_context_object( - Box::new(SyscallBigNumToBytes { - cost: bpf_compute_budget.bignum_to_bytes_base_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; + // vm.bind_syscall_context_object( + // Box::new(SyscallBigNumToBytes { + // cost: bpf_compute_budget.bignum_to_bytes_base_cost, + // compute_meter: invoke_context.get_compute_meter(), + // loader_id, + // }), + // None, + // )?; vm.bind_syscall_context_object( Box::new(SyscallBigNumModExp { @@ -354,14 +354,14 @@ pub fn bind_syscall_context_objects<'a>( }), None, )?; - vm.bind_syscall_context_object( - Box::new(SyscallBigNumDrop { - cost: bpf_compute_budget.bignum_drop_base_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; + // vm.bind_syscall_context_object( + // Box::new(SyscallBigNumDrop { + // cost: bpf_compute_budget.bignum_drop_base_cost, + // compute_meter: invoke_context.get_compute_meter(), + // loader_id, + // }), + // None, + // )?; vm.bind_syscall_context_object( Box::new(SyscallLogBigNum { @@ -1149,68 +1149,6 @@ macro_rules! calc_bignum_cost { }; } -/// BIGNUM sol_bignum_new -struct SyscallBigNumNew<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumNew<'a> { - fn call( - &mut self, - bn_addr: u64, - _arg2: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - question_mark!(self.compute_meter.consume(self.cost), result); - - let big_number = question_mark!( - translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), - result - ); - let bbox = Box::new(BigNum::new().unwrap()); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - *big_number = bignum_ptr; - *result = Ok(0) - } -} -/// BigNum size in bytes returns the number of bytes -/// used by a BigNum -struct SyscallBigNumSizeInBytes<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumSizeInBytes<'a> { - fn call( - &mut self, - bn_self: u64, - bytes_len_addr: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - question_mark!(self.compute_meter.consume(self.cost), result); - let self_bignum_address = question_mark!( - translate_type::(memory_mapping, bn_self, self.loader_id, true), - result - ); - let bytes_len = question_mark!( - translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), - result - ); - let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; - *bytes_len = bn_self.num_bytes() as u64; - *result = Ok(0) - } -} struct SyscallBigNumFromU32<'a> { cost: u64, compute_meter: Rc>, @@ -1219,29 +1157,31 @@ struct SyscallBigNumFromU32<'a> { impl<'a> SyscallObject for SyscallBigNumFromU32<'a> { fn call( &mut self, - bn_addr: u64, + bn_out_addr: u64, + u64_out_len: u64, u32_val: u64, - _arg3: u64, _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let big_number = question_mark!( - translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), - result - ); - let bbox = Box::new(BigNum::from_u32(u32_val as u32).unwrap()); - let bytes = bbox.num_bytes() as f64; question_mark!( self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), + .consume(self.cost + calc_bignum_cost!(u64_out_len as f64)), result ); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - *big_number = bignum_ptr; - *result = Ok(0) + let byte_slice = question_mark!( + translate_slice_mut::(memory_mapping, bn_out_addr, u64_out_len, self.loader_id, true), + result + ); + let bn_bytes = BigNum::from_u32(u32_val as u32).unwrap().to_vec(); + if bn_bytes.len() as u64 > u64_out_len { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } + else { + (*byte_slice).copy_from_slice(&bn_bytes); + *result = Ok(0) + } } } struct SyscallBigNumFromBytes<'a> { @@ -1282,62 +1222,62 @@ impl<'a> SyscallObject for SyscallBigNumFromBytes<'a> { } } -struct SyscallBigNumToBytes<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumToBytes<'a> { - fn call( - &mut self, - bn_self: u64, - bytes_addr: u64, - bytes_len_addr: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - let self_bignum_address = question_mark!( - translate_type::(memory_mapping, bn_self, self.loader_id, true), - result - ); - let bytes_buffer = question_mark!( - translate_slice_mut::( - memory_mapping, - bytes_addr, - *question_mark!( - translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), - result - ), - self.loader_id, - true - ), - result - ); - let bytes_len = question_mark!( - translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), - result - ); - let in_length = *bytes_len; - let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; - let bn_bytes = bn_self.as_ref().to_vec(); - let out_length = bn_bytes.len() as u64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(out_length as f64)), - result - ); - if in_length != out_length { - *bytes_len = 0u64; - *result = Err(SyscallError::BigNumberToBytesError.into()) - } else { - (*bytes_buffer).copy_from_slice(&bn_bytes); - *bytes_len = out_length; - *result = Ok(0) - } - } -} +// struct SyscallBigNumToBytes<'a> { +// cost: u64, +// compute_meter: Rc>, +// loader_id: &'a Pubkey, +// } +// impl<'a> SyscallObject for SyscallBigNumToBytes<'a> { +// fn call( +// &mut self, +// bn_self: u64, +// bytes_addr: u64, +// bytes_len_addr: u64, +// _arg4: u64, +// _arg5: u64, +// memory_mapping: &MemoryMapping, +// result: &mut Result>, +// ) { +// let self_bignum_address = question_mark!( +// translate_type::(memory_mapping, bn_self, self.loader_id, true), +// result +// ); +// let bytes_buffer = question_mark!( +// translate_slice_mut::( +// memory_mapping, +// bytes_addr, +// *question_mark!( +// translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), +// result +// ), +// self.loader_id, +// true +// ), +// result +// ); +// let bytes_len = question_mark!( +// translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), +// result +// ); +// let in_length = *bytes_len; +// let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; +// let bn_bytes = bn_self.as_ref().to_vec(); +// let out_length = bn_bytes.len() as u64; +// question_mark!( +// self.compute_meter +// .consume(self.cost + calc_bignum_cost!(out_length as f64)), +// result +// ); +// if in_length != out_length { +// *bytes_len = 0u64; +// *result = Err(SyscallError::BigNumberToBytesError.into()) +// } else { +// (*bytes_buffer).copy_from_slice(&bn_bytes); +// *bytes_len = out_length; +// *result = Ok(0) +// } +// } +// } // Keccak256 pub struct SyscallKeccak256<'a> { @@ -1939,32 +1879,32 @@ impl<'a> SyscallObject for SyscallBigNumModInv<'a> { } /// BIGNUM sol_bignum_drop -struct SyscallBigNumDrop<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumDrop<'a> { - fn call( - &mut self, - bn_addr: u64, - _arg2: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - question_mark!(self.compute_meter.consume(self.cost), result); - let big_number = question_mark!( - translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), - result - ); - drop(unsafe { Box::from_raw(*big_number as *mut BigNum) }); - *big_number = 0u64; - *result = Ok(0) - } -} +// struct SyscallBigNumDrop<'a> { +// cost: u64, +// compute_meter: Rc>, +// loader_id: &'a Pubkey, +// } +// impl<'a> SyscallObject for SyscallBigNumDrop<'a> { +// fn call( +// &mut self, +// bn_addr: u64, +// _arg2: u64, +// _arg3: u64, +// _arg4: u64, +// _arg5: u64, +// memory_mapping: &MemoryMapping, +// result: &mut Result>, +// ) { +// question_mark!(self.compute_meter.consume(self.cost), result); +// let big_number = question_mark!( +// translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), +// result +// ); +// drop(unsafe { Box::from_raw(*big_number as *mut BigNum) }); +// *big_number = 0u64; +// *result = Ok(0) +// } +// } /// Log BigNum values struct SyscallLogBigNum<'a> { @@ -3137,7 +3077,7 @@ mod tests { enable_instruction_meter: true, enable_instruction_tracing: false, }; - const LONG_DEC_STRING: &str = + const _LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ 300236370809933808677983409391545753391897467230180786617074456716\ @@ -4100,67 +4040,43 @@ mod tests { } } - // Bignum testing convenience functions - // Creates new empty big_num - fn new_bignum() -> u64 { - let mut bn = 0u64; - let bn_addr = &mut bn as *mut _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: bn_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); - let mut syscall = SyscallBigNumNew { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(96, 0, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - bn - } - // creates new bignum with u32 value - fn new_u32_bignum(val: u32) -> u64 { - let mut bn = 0u64; - let bn_addr = &mut bn as *mut _ as u64; + fn new_u32_bignum(val: u32) -> Vec { + let bignum_size = { + match val { + 0..=255 => 1, + 256..=65_535 => 2, + 65_536..=16_777_215 => 3, + _ => 4, + } + }; + let mut my_buffer = Vec::::with_capacity(bignum_size); let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: bn_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], + vec![ + MemoryRegion { + host_addr: my_buffer.as_mut_ptr() as *mut _ as u64, + vm_addr: 1024, + len: bignum_size as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], &DEFAULT_CONFIG, ) .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); + Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); let mut syscall = SyscallBigNumFromU32 { - cost: 1, + cost: 100, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, val as u64, 0, 0, 0, &memory_mapping, &mut result); + syscall.call(1024, bignum_size as u64, val as u64, 0, 0, &memory_mapping, &mut result); result.unwrap(); - bn + unsafe{my_buffer.set_len(bignum_size)}; + my_buffer } // creates new bignum with bytes array fn new_bytes_bignum(val_array: &[u8]) -> u64 { @@ -4200,56 +4116,16 @@ mod tests { result.unwrap(); bn } - #[test] - fn test_syscall_bignum_new() { - let bn = new_bignum(); - let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; - } - - #[test] - fn test_syscall_bignum_size_in_bytes() { - let val = LONG_DEC_STRING.as_bytes(); - let mut bn = new_bytes_bignum(val); - let bn_addr = &mut bn as *mut _ as u64; - let mut bytes_len = 0u64; - let bytes_len_addr = &mut bytes_len as *mut _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: bn_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bytes_len_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); - let mut syscall = SyscallBigNumSizeInBytes { - cost: 100, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(8, 96, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - assert_eq!(bytes_len, val.len() as u64); - } #[test] fn test_syscall_bignum_from_u32() { - let bn = new_u32_bignum(20u32); - let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + let bn_new = BigNum::new().unwrap(); + let bn_0 = BigNum::from_u32(0).unwrap(); + println!("bn_new_vec {:?}", bn_new.to_vec()); + println!("bn_0 {:?}", bn_0.to_vec()); + let bn_20 = new_u32_bignum(20u32); + let bn = BigNum::from_u32(20u32).unwrap().to_vec(); + assert_eq!(bn_20, bn); } #[test] fn test_syscall_bignum_from_bytes() { @@ -4257,57 +4133,57 @@ mod tests { let bn = new_bytes_bignum(&val); let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; } - #[test] - fn test_syscall_bignum_to_bytes() { - let val = LONG_DEC_STRING.as_bytes(); - let mut bn = new_bytes_bignum(val); - let bn_addr = &mut bn as *mut _ as u64; - let big_num: &BigNum = unsafe { &*(bn as *mut BigNum) }; - let existing_size = big_num.num_bytes() as usize; - let bytes_buf = vec![0u8; existing_size]; - let mut bytes_len = bytes_buf.len(); - let bytes_len_addr = &mut bytes_len as *mut _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: bn_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bytes_buf.as_ptr() as *const _ as u64, - vm_addr: 1024, - len: bytes_len as u64, - vm_gap_shift: 63, - is_writable: true, - }, - MemoryRegion { - host_addr: bytes_len_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); - let mut syscall = SyscallBigNumToBytes { - cost: 100, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(8, 1024, 96, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - assert_eq!(bytes_len, val.len()); - assert_eq!(big_num.as_ref().to_vec(), bytes_buf.to_vec()); - } + // #[test] + // fn test_syscall_bignum_to_bytes() { + // let val = LONG_DEC_STRING.as_bytes(); + // let mut bn = new_bytes_bignum(val); + // let bn_addr = &mut bn as *mut _ as u64; + // let big_num: &BigNum = unsafe { &*(bn as *mut BigNum) }; + // let existing_size = big_num.num_bytes() as usize; + // let bytes_buf = vec![0u8; existing_size]; + // let mut bytes_len = bytes_buf.len(); + // let bytes_len_addr = &mut bytes_len as *mut _ as u64; + // let memory_mapping = MemoryMapping::new::( + // vec![ + // MemoryRegion { + // host_addr: bn_addr, + // vm_addr: 8, + // len: std::mem::size_of::() as u64, + // vm_gap_shift: 63, + // is_writable: false, + // }, + // MemoryRegion { + // host_addr: bytes_buf.as_ptr() as *const _ as u64, + // vm_addr: 1024, + // len: bytes_len as u64, + // vm_gap_shift: 63, + // is_writable: true, + // }, + // MemoryRegion { + // host_addr: bytes_len_addr, + // vm_addr: 96, + // len: std::mem::size_of::() as u64, + // vm_gap_shift: 63, + // is_writable: true, + // }, + // ], + // &DEFAULT_CONFIG, + // ) + // .unwrap(); + + // let compute_meter: Rc> = + // Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); + // let mut syscall = SyscallBigNumToBytes { + // cost: 100, + // compute_meter, + // loader_id: &bpf_loader::id(), + // }; + // let mut result: Result> = Ok(0); + // syscall.call(8, 1024, 96, 0, 0, &memory_mapping, &mut result); + // result.unwrap(); + // assert_eq!(bytes_len, val.len()); + // assert_eq!(big_num.as_ref().to_vec(), bytes_buf.to_vec()); + // } #[test] fn test_syscall_bignum_mod_exp() { @@ -4823,36 +4699,4 @@ mod tests { syscall.call(8, 32, 96, 0, 0, &memory_mapping, &mut result); result.unwrap(); } - - #[test] - fn test_syscall_bignum_drop() { - let mut bn = new_bignum(); - let bn_addr = &mut bn as *mut _ as u64; - assert_ne!(bn, 0); - let memory_mapping = MemoryMapping::new::( - vec![MemoryRegion { - host_addr: bn_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }], - &DEFAULT_CONFIG, - ) - .unwrap(); - - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); - let mut syscall = SyscallBigNumDrop { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(96, 0, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - assert_eq!(bn, 0); - } } diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index e82e32b6a9f394..0aaea1216010a9 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -457,15 +457,6 @@ uint64_t sol_keccak256( const uint8_t *result ); -/** - * BigNum sol_bignum_new - * - * @param ptr location where new object address dropped - */ -static uint64_t sol_bignum_new( - const uint64_t *ptr -); - /** * BigNum sol_bignum_size_in_bytes * @@ -485,7 +476,8 @@ static uint64_t sol_bignum_size_in_bytes( */ static uint64_t sol_bignum_from_u32( const uint64_t *ptr, - const uint32_t val_u32 + const uint64_t ptr_size, + const uint64_t val_u32 ); /** * BigNum sol_bignum_from_bytes diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index f05a0c3461959e..2216bda59b84bc 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -8,7 +8,7 @@ use std::fmt; BorshSerialize, BorshDeserialize, BorshSchema, - Default, + Clone, Eq, PartialEq, Ord, @@ -17,533 +17,533 @@ use std::fmt; AbiExample, )] -pub struct BigNumber(u64); +pub struct BigNumber { + value: Vec, +} + +// pub struct BigNumber(u64); impl BigNumber { /// Returns a BigNumber with initial value of 0 pub fn new() -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::BigNum; - let bbox = Box::new(BigNum::new().unwrap()); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - Self(bignum_ptr) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_new(bignum_ptr: *mut u64) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_new(&mut bignum_ptr as *mut _ as *mut u64); - } - BigNumber::from(bignum_ptr) - } + let mut value = Vec::::new(); + value.push(0u8); + Self { value } } /// Returns the size, in bytes, of BigNum. Typically used in /// assessing buffer size needed to fetch the bytes for serialization, etc. pub fn size_in_bytes(&self) -> usize { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::BigNum; - let self_bignum: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - self_bignum.num_bytes() as usize - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_size_in_bytes(bignum_ptr: *const u64, bytes_len: *mut u64) -> u64; - } - let mut bignum_size = 0u64; - unsafe { - sol_bignum_size_in_bytes( - &self.0 as *const _ as *const u64, - &mut bignum_size as *mut _ as *mut u64, - ); - } - bignum_size as usize - } + self.value.len() } /// Returns a BigNumber with initial value set to a u32 value pub fn from_u32(val: u32) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::BigNum; - let bbox = Box::new(BigNum::from_u32(val).unwrap()); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - Self(bignum_ptr) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_from_u32(bignum_ptr: *mut u64, val: u64) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_from_u32(&mut bignum_ptr as *mut _ as *mut u64, val as u64); + if val == 0 { + let mut value = Vec::::new(); + value.push(0); + Self { value } + } else { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let value = BigNum::from_u32(val).unwrap().to_vec(); + Self { value } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_from_u32(bytes_ptr: *mut u8, bytes_len: u64, val: u64) -> u64; + } + let vec_size = { + match val { + 0..=255 => 1, + 256..=65_535 => 2, + 65_536..=16_777_215 => 3, + _ => 4, + } + }; + let mut value = Vec::::with_capacity(vec_size); + unsafe { + sol_bignum_from_u32( + value.as_mut_ptr() as *mut _ as *mut u8, + vec_size as u64, + val as u64, + ); + value.set_len(vec_size); + } + Self { value } } - BigNumber::from(bignum_ptr) } } /// Returns a BigNumber with value set to big endian array of bytes - pub fn from_bytes(val: &[u8]) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::BigNum; - let bbox = Box::new(BigNum::from_slice(val).unwrap()); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - Self(bignum_ptr) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_from_bytes( - bignum_ptr: *mut u64, - bytes_ptr: *const u64, - bytes_len: u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_from_bytes( - &mut bignum_ptr as *mut _ as *mut u64, - val.as_ptr() as *const _ as *const u64, - val.len() as u64, - ); - } - BigNumber::from(bignum_ptr) - } - } + // pub fn from_bytes(val: &[u8]) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::BigNum; + // let value = BigNum::from_slice(val).unwrap().to_vec(); + // // let bbox = Box::new(BigNum::from_slice(val).unwrap()); + // // let rwptr = Box::into_raw(bbox); + // // let bignum_ptr = rwptr as u64; + // // Self(bignum_ptr) + // Self {value} + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_from_bytes( + // bignum_ptr: *mut u64, + // bytes_ptr: *const u64, + // bytes_len: u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_from_bytes( + // &mut bignum_ptr as *mut _ as *mut u64, + // val.as_ptr() as *const _ as *const u64, + // val.len() as u64, + // ); + // } + // BigNumber::from(bignum_ptr) + // } + // } /// Returns an array of bytes of self pub fn to_bytes(&self) -> Vec { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::BigNum; - let braw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - braw.as_ref().to_vec() - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_to_bytes( - bignum_ptr: *const u64, - bytes_ptr: *mut u8, - bytes_len: *mut u64, - ) -> u64; - } - // Get the BigNum size, allocate result vector - let mut bignum_size = self.size_in_bytes() as u64; - let mut my_buffer = Vec::::with_capacity(bignum_size as usize); - unsafe { - sol_bignum_to_bytes( - &self.0 as *const _ as *const u64, - my_buffer.as_mut_ptr() as *mut _ as *mut u8, - &mut bignum_size as *mut _ as *mut u64, - ); - my_buffer.set_len(bignum_size as usize); - } - my_buffer.clone() - } + self.value.clone() + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::BigNum; + // let braw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // braw.as_ref().to_vec() + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_to_bytes( + // bignum_ptr: *const u64, + // bytes_ptr: *mut u8, + // bytes_len: *mut u64, + // ) -> u64; + // } + // // Get the BigNum size, allocate result vector + // let mut bignum_size = self.size_in_bytes() as u64; + // let mut my_buffer = Vec::::with_capacity(bignum_size as usize); + // unsafe { + // sol_bignum_to_bytes( + // &self.0 as *const _ as *const u64, + // my_buffer.as_mut_ptr() as *mut _ as *mut u8, + // &mut bignum_size as *mut _ as *mut u64, + // ); + // my_buffer.set_len(bignum_size as usize); + // } + // my_buffer.clone() + // } } - /// Add BigNumbers - pub fn add(&self, rhs: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - BigNumRef::checked_add(&mut bbox, my_raw, rhs_ptr).unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_add( - self_ptr: *const u64, - rhs_ptr: *const u64, - return_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_add( - &self.0 as *const _ as *const u64, - &rhs.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Add BigNumbers + // pub fn add(&self, rhs: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + // BigNumRef::checked_add(&mut bbox, my_raw, rhs_ptr).unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_add( + // self_ptr: *const u64, + // rhs_ptr: *const u64, + // return_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_add( + // &self.0 as *const _ as *const u64, + // &rhs.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Subtract BigNumbers - pub fn sub(&self, rhs: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - BigNumRef::checked_sub(&mut *bbox, my_raw, rhs_ptr).unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_sub( - self_ptr: *const u64, - rhs_ptr: *const u64, - return_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_sub( - &self.0 as *const _ as *const u64, - &rhs.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Subtract BigNumbers + // pub fn sub(&self, rhs: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + // BigNumRef::checked_sub(&mut *bbox, my_raw, rhs_ptr).unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_sub( + // self_ptr: *const u64, + // rhs_ptr: *const u64, + // return_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_sub( + // &self.0 as *const _ as *const u64, + // &rhs.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Multiple BigNumbers - pub fn mul(&self, rhs: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - BigNumRef::checked_mul( - &mut *bbox, - my_raw, - rhs_ptr, - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_mul( - self_ptr: *const u64, - rhs_ptr: *const u64, - return_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_mul( - &self.0 as *const _ as *const u64, - &rhs.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Multiple BigNumbers + // pub fn mul(&self, rhs: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + // BigNumRef::checked_mul( + // &mut *bbox, + // my_raw, + // rhs_ptr, + // &mut BigNumContext::new().unwrap(), + // ) + // .unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_mul( + // self_ptr: *const u64, + // rhs_ptr: *const u64, + // return_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_mul( + // &self.0 as *const _ as *const u64, + // &rhs.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Mod multiplier (self * multiplier) % modulus - pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext}; - let mut new_self = Box::new(BigNum::new().unwrap()); - let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let multiplier_ptr: &BigNum = unsafe { &*(multiplier.0 as *const BigNum) }; - let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - new_self - .mod_mul( - myself_ptr, - multiplier_ptr, - modulus_ptr, - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(new_self); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_mod_mul( - self_ptr: *const u64, - multiplier_ptr: *const u64, - modulus_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_mod_mul( - &self.0 as *const _ as *const u64, - &multiplier.0 as *const _ as *const u64, - &modulus.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Mod multiplier (self * multiplier) % modulus + // pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext}; + // let mut new_self = Box::new(BigNum::new().unwrap()); + // let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let multiplier_ptr: &BigNum = unsafe { &*(multiplier.0 as *const BigNum) }; + // let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + // new_self + // .mod_mul( + // myself_ptr, + // multiplier_ptr, + // modulus_ptr, + // &mut BigNumContext::new().unwrap(), + // ) + // .unwrap(); + // let rwptr = Box::into_raw(new_self); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_mod_mul( + // self_ptr: *const u64, + // multiplier_ptr: *const u64, + // modulus_ptr: *const u64, + // bignum_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_mod_mul( + // &self.0 as *const _ as *const u64, + // &multiplier.0 as *const _ as *const u64, + // &modulus.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Finds the inverse of modulus on self - pub fn mod_inv(&self, modulus: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext}; - let mut new_self = Box::new(BigNum::new().unwrap()); - let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - new_self - .mod_inverse(myself_ptr, modulus_ptr, &mut BigNumContext::new().unwrap()) - .unwrap(); - let rwptr = Box::into_raw(new_self); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_mod_inv( - self_ptr: *const u64, - modulus_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_mod_inv( - &self.0 as *const _ as *const u64, - &modulus.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Finds the inverse of modulus on self + // pub fn mod_inv(&self, modulus: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext}; + // let mut new_self = Box::new(BigNum::new().unwrap()); + // let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + // new_self + // .mod_inverse(myself_ptr, modulus_ptr, &mut BigNumContext::new().unwrap()) + // .unwrap(); + // let rwptr = Box::into_raw(new_self); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_mod_inv( + // self_ptr: *const u64, + // modulus_ptr: *const u64, + // bignum_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_mod_inv( + // &self.0 as *const _ as *const u64, + // &modulus.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Divide BigNumbers - pub fn div(&self, rhs: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - BigNumRef::checked_div( - &mut *bbox, - my_raw, - rhs_ptr, - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_div( - self_ptr: *const u64, - rhs_ptr: *const u64, - return_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_div( - &self.0 as *const _ as *const u64, - &rhs.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Divide BigNumbers + // pub fn div(&self, rhs: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; + // BigNumRef::checked_div( + // &mut *bbox, + // my_raw, + // rhs_ptr, + // &mut BigNumContext::new().unwrap(), + // ) + // .unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_div( + // self_ptr: *const u64, + // rhs_ptr: *const u64, + // return_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_div( + // &self.0 as *const _ as *const u64, + // &rhs.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Square BigNumbers - pub fn sqr(&self) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - BigNumRef::sqr(&mut *bbox, my_raw, &mut BigNumContext::new().unwrap()).unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_sqr(self_ptr: *const u64, modulus_ptr: *const u64) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_sqr( - &self.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Square BigNumbers + // pub fn sqr(&self) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // BigNumRef::sqr(&mut *bbox, my_raw, &mut BigNumContext::new().unwrap()).unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_sqr(self_ptr: *const u64, modulus_ptr: *const u64) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_sqr( + // &self.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Square BigNumbers - pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let my_mod: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - BigNumRef::mod_sqr( - &mut *bbox, - my_raw, - my_mod, - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_mod_sqr( - self_ptr: *const u64, - modulus_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_mod_sqr( - &self.0 as *const _ as *const u64, - &modulus.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Square BigNumbers + // pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let my_mod: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // BigNumRef::mod_sqr( + // &mut *bbox, + // my_raw, + // my_mod, + // &mut BigNumContext::new().unwrap(), + // ) + // .unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_mod_sqr( + // self_ptr: *const u64, + // modulus_ptr: *const u64, + // bignum_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_mod_sqr( + // &self.0 as *const _ as *const u64, + // &modulus.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Square BigNumbers - pub fn exp(&self, exponent: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; - let mut bbox = Box::new(BigNum::new().unwrap()); - BigNumRef::exp( - &mut *bbox, - my_raw, - exponent_ptr, - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(bbox); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_exp( - self_ptr: *const u64, - exponent_ptr: *const u64, - bignum_ptr: *mut u64, - ) -> u64; - } - let mut bignum_ptr = 0u64; - unsafe { - sol_bignum_exp( - &self.0 as *const _ as *const u64, - &exponent.0 as *const _ as *const u64, - &mut bignum_ptr as *mut _ as *mut u64, - ); - } - Self(bignum_ptr) - } - } + // /// Square BigNumbers + // pub fn exp(&self, exponent: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; + // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; + // let mut bbox = Box::new(BigNum::new().unwrap()); + // BigNumRef::exp( + // &mut *bbox, + // my_raw, + // exponent_ptr, + // &mut BigNumContext::new().unwrap(), + // ) + // .unwrap(); + // let rwptr = Box::into_raw(bbox); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_exp( + // self_ptr: *const u64, + // exponent_ptr: *const u64, + // bignum_ptr: *mut u64, + // ) -> u64; + // } + // let mut bignum_ptr = 0u64; + // unsafe { + // sol_bignum_exp( + // &self.0 as *const _ as *const u64, + // &exponent.0 as *const _ as *const u64, + // &mut bignum_ptr as *mut _ as *mut u64, + // ); + // } + // Self(bignum_ptr) + // } + // } - /// Compute modular exponentiation (self ^ rhs mod order) and return the result - pub fn mod_exp(&self, exponent: &BigNumber, modulus: &BigNumber) -> Self { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::{BigNum, BigNumContext}; - let mut new_self = Box::new(BigNum::new().unwrap()); - let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; - let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - new_self - .mod_exp( - myself_ptr, - exponent_ptr, - modulus_ptr, - &mut BigNumContext::new().unwrap(), - ) - .unwrap(); - let rwptr = Box::into_raw(new_self); - Self(rwptr as u64) - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_mod_exp( - bignum_ptr: *mut u64, - self_ptr: *const u64, - exponent_ptr: *const u64, - modulus_ptr: *const u64, - ) -> u64; - } - let bignum_ptr = &mut 0u64; - unsafe { - sol_bignum_mod_exp( - &mut *bignum_ptr as *mut _ as *mut u64, - &self.0 as *const _ as *const u64, - &exponent.0 as *const _ as *const u64, - &modulus.0 as *const _ as *const u64, - ); - } - Self(*bignum_ptr) - } - } + // /// Compute modular exponentiation (self ^ rhs mod order) and return the result + // pub fn mod_exp(&self, exponent: &BigNumber, modulus: &BigNumber) -> Self { + // #[cfg(not(target_arch = "bpf"))] + // { + // use openssl::bn::{BigNum, BigNumContext}; + // let mut new_self = Box::new(BigNum::new().unwrap()); + // let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; + // let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; + // let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; + // new_self + // .mod_exp( + // myself_ptr, + // exponent_ptr, + // modulus_ptr, + // &mut BigNumContext::new().unwrap(), + // ) + // .unwrap(); + // let rwptr = Box::into_raw(new_self); + // Self(rwptr as u64) + // } + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_bignum_mod_exp( + // bignum_ptr: *mut u64, + // self_ptr: *const u64, + // exponent_ptr: *const u64, + // modulus_ptr: *const u64, + // ) -> u64; + // } + // let bignum_ptr = &mut 0u64; + // unsafe { + // sol_bignum_mod_exp( + // &mut *bignum_ptr as *mut _ as *mut u64, + // &self.0 as *const _ as *const u64, + // &exponent.0 as *const _ as *const u64, + // &modulus.0 as *const _ as *const u64, + // ); + // } + // Self(*bignum_ptr) + // } + // } - /// Log a `BigNum` from a program - pub fn log(&self) { - #[cfg(not(target_arch = "bpf"))] - crate::program_stubs::sol_log(&self.to_string()); - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_log_bignum(bignum_addr: *const u64) -> u64; - } - unsafe { sol_log_bignum(&self.0 as *const _ as *const u64) }; - } - } + // /// Log a `BigNum` from a program + // pub fn log(&self) { + // #[cfg(not(target_arch = "bpf"))] + // crate::program_stubs::sol_log(&self.to_string()); + // #[cfg(target_arch = "bpf")] + // { + // extern "C" { + // fn sol_log_bignum(bignum_addr: *const u64) -> u64; + // } + // unsafe { sol_log_bignum(&self.0 as *const _ as *const u64) }; + // } + // } } +impl Default for BigNumber { + fn default() -> Self { + let mut value = Vec::::new(); + value.push(0); + Self { value } + } +} impl fmt::Debug for BigNumber { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[cfg(not(target_arch = "bpf"))] { use openssl::bn::BigNum; - let braw: &BigNum = unsafe { &*(self.0 as *mut BigNum) }; + let braw = BigNum::from_slice(&self.value) + .unwrap() + .to_dec_str() + .unwrap(); + // let braw: &BigNum = unsafe { &*(self.0 as *mut BigNum) }; write!(f, "{}", braw) } #[cfg(target_arch = "bpf")] @@ -558,7 +558,11 @@ impl fmt::Display for BigNumber { #[cfg(not(target_arch = "bpf"))] { use openssl::bn::BigNum; - let braw: &BigNum = unsafe { &*(self.0 as *mut BigNum) }; + let braw = BigNum::from_slice(&self.value) + .unwrap() + .to_dec_str() + .unwrap(); + // let braw: &BigNum = unsafe { &*(self.0 as *mut BigNum) }; write!(f, "{}", braw) } #[cfg(target_arch = "bpf")] @@ -568,43 +572,43 @@ impl fmt::Display for BigNumber { } } -impl AsRef for BigNumber { - fn as_ref(&self) -> &u64 { - &self.0 - } -} +// impl AsRef for BigNumber { +// fn as_ref(&self) -> &u64 { +// &self.0 +// } +// } -impl From for BigNumber { - fn from(ptr: u64) -> Self { - Self(ptr) - } -} +// impl From for BigNumber { +// fn from(ptr: u64) -> Self { +// Self(ptr) +// } +// } /// Drop - removes the underlying BigNum -impl Drop for BigNumber { - fn drop(&mut self) { - #[cfg(not(target_arch = "bpf"))] - { - use openssl::bn::BigNum; - drop(unsafe { Box::from_raw(self.0 as *mut BigNum) }); - } - #[cfg(target_arch = "bpf")] - { - extern "C" { - fn sol_bignum_drop(bignum_ptr: *mut u64) -> u64; - } - unsafe { - sol_bignum_drop(&mut self.0 as *mut _ as *mut u64); - } - } - } -} +// impl Drop for BigNumber { +// fn drop(&mut self) { +// #[cfg(not(target_arch = "bpf"))] +// { +// use openssl::bn::BigNum; +// drop(unsafe { Box::from_raw(self.0 as *mut BigNum) }); +// } +// #[cfg(target_arch = "bpf")] +// { +// extern "C" { +// fn sol_bignum_drop(bignum_ptr: *mut u64) -> u64; +// } +// unsafe { +// sol_bignum_drop(&mut self.0 as *mut _ as *mut u64); +// } +// } +// } +// } /// Clone - creates a new BigNumber replicating itself -impl Clone for BigNumber { - fn clone(&self) -> Self { - BigNumber::from_bytes(self.to_bytes().as_slice()) - } -} +// impl Clone for BigNumber { +// fn clone(&self) -> Self { +// BigNumber::from_bytes(self.to_bytes().as_slice()) +// } +// } #[cfg(test)] mod tests { diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index c7ff58f5a5bba7..cc22bd635a3cb6 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -166,17 +166,17 @@ pub struct BpfComputeBudget { /// Base number of compute units consumed to get a sysvar pub sysvar_base_cost: u64, /// Base number of compute units consumed to call BIGNUM NEW - pub bignum_new_base_cost: u64, + // pub bignum_new_base_cost: u64, /// Base number of compute units consumed to call BigNum size in bytes query - pub bignum_size_base_cost: u64, + // pub bignum_size_base_cost: u64, /// Base number of compute units consumed to call BigNum new from u32 value pub bignum_from_u32_base_cost: u64, /// Base number of compute units consumed to call BigNum new from big endian byte array pub bignum_from_bytes_base_cost: u64, /// Base number of compute units consumed to extract big endian byte array from BigNumb - pub bignum_to_bytes_base_cost: u64, + // pub bignum_to_bytes_base_cost: u64, /// Base number of compute units consumed to drop/dealloc BigNum - pub bignum_drop_base_cost: u64, + // pub bignum_drop_base_cost: u64, /// Incremental number of units consumed to drop/dealloc BigNum (based on bytes) pub bignum_mod_exp_base_cost: u64, /// Number of compute units consumed by logging a `BigNum` @@ -222,12 +222,12 @@ impl BpfComputeBudget { max_cpi_instruction_size: 1280, // IPv6 Min MTU size cpi_bytes_per_unit: 250, // ~50MB at 200,000 units sysvar_base_cost: 100, - bignum_new_base_cost: 100, - bignum_size_base_cost: 100, - bignum_drop_base_cost: 100, + // bignum_new_base_cost: 100, + // bignum_size_base_cost: 100, + // bignum_drop_base_cost: 100, bignum_from_u32_base_cost: 100, bignum_from_bytes_base_cost: 100, - bignum_to_bytes_base_cost: 100, + // bignum_to_bytes_base_cost: 100, bignum_mod_exp_base_cost: 100, log_bignum_cost: 100, bignum_add_cost: 15, From f5eafc779534077f723f50a9055ce298bff621ba Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Sat, 15 May 2021 17:39:47 -0400 Subject: [PATCH 16/45] BigNumber::from_dec_str using vectors instead of Box --- programs/bpf/rust/bignum/src/lib.rs | 13 +- programs/bpf_loader/src/syscalls.rs | 199 ++++++++++++++++++++-------- sdk/bpf/c/inc/solana_sdk.h | 64 +++------ sdk/program/src/bignum.rs | 92 +++++++------ sdk/src/process_instruction.rs | 6 +- 5 files changed, 227 insertions(+), 147 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index ce151095d0e9f9..98e436f75ad630 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -3,7 +3,7 @@ extern crate solana_program; use solana_program::{bignum::BigNumber, custom_panic_default, msg}; -const _LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ +const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ 300236370809933808677983409391545753391897467230180786617074456716\ 591448871466263060696957107957862111484694673874424855359234132302\ @@ -26,15 +26,18 @@ fn test_constructors() { msg!("base_bn_0 {}", base_bn_0); let default_0 = BigNumber::default(); msg!("default_0 {}", default_0); + let new_bn_0 = BigNumber::from_u32(0); + msg!("new_bn_0 {}", new_bn_0); + let max_bn_u32 = BigNumber::from_u32(u32::MAX); + msg!("max_bn_u32 {:?}", max_bn_u32.to_bytes()); + let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); + assert_eq!(bn_from_dec.is_negative(), false); + msg!("dec str bytes {:?}", bn_from_dec.to_bytes()); // base_bn_0.log(); // let empty_bn = BigNumber::from_bytes(&[0u8]); // msg!("empty_bn {}", empty_bn); // empty_bn.log(); - let new_bn_0 = BigNumber::from_u32(0); - msg!("new_bn_0 {}", new_bn_0); // new_bn_0.log(); - let max_bn_u32 = BigNumber::from_u32(u32::MAX); - msg!("max_bn_u32 {:?}", max_bn_u32.to_bytes()); // max_bn_u32.log(); // msg!("Big string len = {}", LONG_DEC_STRING.len()); // let big_string_as_bytes = LONG_DEC_STRING.as_bytes(); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d210b559aa5cf1..b8689d3e71adc9 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -182,7 +182,7 @@ pub fn register_syscalls( syscall_registry .register_syscall_by_name(b"sol_bignum_from_u32", SyscallBigNumFromU32::call)?; syscall_registry - .register_syscall_by_name(b"sol_bignum_from_bytes", SyscallBigNumFromBytes::call)?; + .register_syscall_by_name(b"sol_bignum_from_dec_str", SyscallBigNumFromDecStr::call)?; // syscall_registry // .register_syscall_by_name(b"sol_bignum_to_bytes", SyscallBigNumToBytes::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mod_exp", SyscallBigNumModExp::call)?; @@ -330,8 +330,8 @@ pub fn bind_syscall_context_objects<'a>( None, )?; vm.bind_syscall_context_object( - Box::new(SyscallBigNumFromBytes { - cost: bpf_compute_budget.bignum_from_bytes_base_cost, + Box::new(SyscallBigNumFromDecStr { + cost: bpf_compute_budget.bignum_from_dec_str_base_cost, compute_meter: invoke_context.get_compute_meter(), loader_id, }), @@ -1171,54 +1171,103 @@ impl<'a> SyscallObject for SyscallBigNumFromU32<'a> { result ); let byte_slice = question_mark!( - translate_slice_mut::(memory_mapping, bn_out_addr, u64_out_len, self.loader_id, true), + translate_slice_mut::( + memory_mapping, + bn_out_addr, + u64_out_len, + self.loader_id, + true + ), result ); let bn_bytes = BigNum::from_u32(u32_val as u32).unwrap().to_vec(); if bn_bytes.len() as u64 > u64_out_len { *result = Err(SyscallError::BigNumberToBytesError.into()) - } - else { + } else { (*byte_slice).copy_from_slice(&bn_bytes); *result = Ok(0) } } } -struct SyscallBigNumFromBytes<'a> { +/// Converts a decimal string to a bignum and returns +/// the vector bytes and if negative or not +struct SyscallBigNumFromDecStr<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallBigNumFromBytes<'a> { +impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { fn call( &mut self, - bn_addr: u64, - bytes_addr: u64, - bytes_len: u64, - _arg4: u64, - _arg5: u64, + in_dec_str_addr: u64, + in_size: u64, + out_array_addr: u64, + out_size_addr: u64, + out_negative_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let big_number = question_mark!( - translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(in_size as f64)), result ); + + // Get the string and convert to BigNum + let in_dec_raw = question_mark!( + translate_slice::(memory_mapping, in_dec_str_addr, in_size, self.loader_id, true), + result + ); + let i = match in_dec_raw.iter().position(|byte| *byte == 0) { + Some(i) => i, + None => in_size as usize, + }; + let big_number = BigNum::from_dec_str(from_utf8(&in_dec_raw[..i]).unwrap()).unwrap(); + let big_number_bytes = big_number.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + + // Get result let byte_slice = question_mark!( - translate_slice::(memory_mapping, bytes_addr, bytes_len, self.loader_id, true), + translate_slice_mut::( + memory_mapping, + out_array_addr, + *out_size, + self.loader_id, + true + ), result ); - let bytes: f64 = byte_slice.len() as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), + + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::(memory_mapping, out_negative_addr, self.loader_id, true), result ); - let bbox = Box::new(BigNum::from_slice(byte_slice).unwrap()); - let rwptr = Box::into_raw(bbox); - let bignum_ptr = rwptr as u64; - *big_number = bignum_ptr; - *result = Ok(0) + + // Exceeds size + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*byte_slice).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*byte_slice)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = big_number.is_negative() as u64; + *result = Ok(0) + } } } @@ -3077,7 +3126,7 @@ mod tests { enable_instruction_meter: true, enable_instruction_tracing: false, }; - const _LONG_DEC_STRING: &str = + const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ 300236370809933808677983409391545753391897467230180786617074456716\ @@ -3089,6 +3138,18 @@ mod tests { 996538599452325797319977413534714912781503130883692806087195354368\ 8304190675878204079994222"; + const NEG_LONG_DEC_STRING: &str = + "-1470463693494555670176851280755142329532258274256991544781479988\ + 712408107190720087233560906792937436573943189716784305633216335039\ + 300236370809933808677983409391545753391897467230180786617074456716\ + 591448871466263060696957107957862111484694673874424855359234132302\ + 162208163361387727626078022804936564470716886986414133429438273232\ + 416190048073715996321578752244853524209178212395809614878549824744\ + 227969245726015222693764433413133633359171080169137831743765672068\ + 374040331773668233371864426354886263106537340208256187214278963052\ + 996538599452325797319977413534714912781503130883692806087195354368\ + 8304190675878204079994222"; + macro_rules! assert_access_violation { ($result:expr, $va:expr, $len:expr) => { match $result { @@ -4052,15 +4113,13 @@ mod tests { }; let mut my_buffer = Vec::::with_capacity(bignum_size); let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: my_buffer.as_mut_ptr() as *mut _ as u64, - vm_addr: 1024, - len: bignum_size as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], + vec![MemoryRegion { + host_addr: my_buffer.as_mut_ptr() as *mut _ as u64, + vm_addr: 1024, + len: bignum_size as u64, + vm_gap_shift: 63, + is_writable: true, + }], &DEFAULT_CONFIG, ) .unwrap(); @@ -4073,31 +4132,58 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(1024, bignum_size as u64, val as u64, 0, 0, &memory_mapping, &mut result); + syscall.call( + 1024, + bignum_size as u64, + val as u64, + 0, + 0, + &memory_mapping, + &mut result, + ); result.unwrap(); - unsafe{my_buffer.set_len(bignum_size)}; + unsafe { my_buffer.set_len(bignum_size) }; my_buffer } // creates new bignum with bytes array - fn new_bytes_bignum(val_array: &[u8]) -> u64 { - let mut bn = 0u64; - let bn_addr = &mut bn as *mut _ as u64; - let val_len = val_array.len(); + fn new_dec_str_bignum(string: &str) -> (bool, Vec) { + let dec_str_addr = string.as_ptr() as *const _ as u64; + let dec_str_len = string.len(); + let bytes_buf = vec![0u8; dec_str_len]; + let mut bytes_len = bytes_buf.len(); + let bytes_len_addr = &mut bytes_len as *mut _ as u64; + let mut neg_flag = 0u64; + let neg_flag_addr = &mut neg_flag as *mut _ as u64; + let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_addr, + host_addr: dec_str_addr, + vm_addr: 2048, + len: dec_str_len as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bytes_buf.as_ptr() as *const _ as u64, + vm_addr: 8196, + len: bytes_len as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: bytes_len_addr, vm_addr: 96, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, }, MemoryRegion { - host_addr: val_array.as_ptr() as *const _ as u64, - vm_addr: 1024, - len: val_len as u64, + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }, ], &DEFAULT_CONFIG, @@ -4106,15 +4192,15 @@ mod tests { let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); - let mut syscall = SyscallBigNumFromBytes { + let mut syscall = SyscallBigNumFromDecStr { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, 1024, val_len as u64, 0, 0, &memory_mapping, &mut result); + syscall.call(2048, dec_str_len as u64, 8196, 96, 8, &memory_mapping, &mut result); result.unwrap(); - bn + (neg_flag != 0, bytes_buf[0..bytes_len].to_vec()) } #[test] @@ -4128,10 +4214,17 @@ mod tests { assert_eq!(bn_20, bn); } #[test] - fn test_syscall_bignum_from_bytes() { - let val = [0u8, 0u8, 1u8, 0u8]; - let bn = new_bytes_bignum(&val); - let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + fn test_syscall_bignum_from_dec_str() { + let (is_neg, result_vec) = new_dec_str_bignum(LONG_DEC_STRING); + assert!(is_neg == false); + let bns = BigNum::from_dec_str(LONG_DEC_STRING).unwrap(); + let bns_vec = bns.as_ref().to_vec(); + assert_eq!(result_vec, bns_vec); + let (is_neg, result_vec) = new_dec_str_bignum(NEG_LONG_DEC_STRING); + assert!(is_neg); + let bns = BigNum::from_dec_str(NEG_LONG_DEC_STRING).unwrap(); + let bns_vec = bns.as_ref().to_vec(); + assert_eq!(result_vec, bns_vec); } // #[test] // fn test_syscall_bignum_to_bytes() { diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 0aaea1216010a9..8b8f97d1aec6b9 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -457,63 +457,33 @@ uint64_t sol_keccak256( const uint8_t *result ); -/** - * BigNum sol_bignum_size_in_bytes - * - * @param self_ptr address of the BigNum ptr - * @parm byte_len address of where to return size - */ -static uint64_t sol_bignum_size_in_bytes( - const uint64_t *self_ptr, - const uint64_t *byte_len -); - /** * BigNum sol_bignum_from_u32 * - * @param ptr location where new object address dropped + * @param out_ptr address of vector array (r/w) + * @param ptr_size size of bytes in ptr * @param val_u32 unsigned 32 bit value to assign to the new object */ static uint64_t sol_bignum_from_u32( - const uint64_t *ptr, - const uint64_t ptr_size, + const uint64_t *out_ptr, + const uint64_t out_size, const uint64_t val_u32 ); /** - * BigNum sol_bignum_from_bytes - * - * @param ptr location where new object address dropped - * @param bytes pointer to unsigned byte array - * @param byte_len size of bytes array - */ -static uint64_t sol_bignum_from_bytes( - const uint64_t *ptr, - const SolBytes *bytes, - const uint64_t byte_len -); -/** - * BigNum sol_bignum_to_bytes + * BigNum sol_bignum_from_dec_str * - * @param ptr object address created with sol_bignum_new (read/write) - * @param bytes pointer to unsigned byte array - * @param byte_len maximum size of bytes array - */ -/** - * Size of Public key in bytes - */ -#define SIZE_BIGNUMBYTES 256 - -/** - * Public key - */ -typedef struct { - uint8_t x[SIZE_BIGNUMBYTES]; -} SolBigNumBuf; - -static uint64_t sol_bignum_to_bytes( - const uint64_t *ptr, - const SolBigNumBuf *bytes, - const uint64_t *byte_len + * @param in_dec_str_ptr address of decimal string (r/o) + * @param in_size size of bytes array (r/o) + * @param out_ptr address of vector array (r/w) + * @param out_size_ptr size of bytes in ptr (r/o) + * @param out_is_neg_flag_ptr if string was negative + */ +static uint64_t sol_bignum_from_dec_str( + const uint64_t *in_dec_str_ptr, + const uint64_t in_size, + const uint64_t *out_ptr, + const uint64_t *out_size_ptr, + const uint64_t *out_is_neg_flag_ptr ); /** diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 2216bda59b84bc..55b8bcc8fc3a84 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -3,7 +3,7 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use std::fmt; -#[repr(transparent)] +#[repr(C)] #[derive( BorshSerialize, BorshDeserialize, @@ -16,9 +16,9 @@ use std::fmt; Hash, AbiExample, )] - pub struct BigNumber { value: Vec, + negative: bool, } // pub struct BigNumber(u64); @@ -28,7 +28,7 @@ impl BigNumber { pub fn new() -> Self { let mut value = Vec::::new(); value.push(0u8); - Self { value } + Self { negative: false, value } } /// Returns the size, in bytes, of BigNum. Typically used in @@ -42,13 +42,13 @@ impl BigNumber { if val == 0 { let mut value = Vec::::new(); value.push(0); - Self { value } + Self { negative: false, value } } else { #[cfg(not(target_arch = "bpf"))] { use openssl::bn::BigNum; let value = BigNum::from_u32(val).unwrap().to_vec(); - Self { value } + Self { negative: false, value } } #[cfg(target_arch = "bpf")] { @@ -72,43 +72,57 @@ impl BigNumber { ); value.set_len(vec_size); } - Self { value } + Self { negative: false, value } } } } + /// Returns a BigNumber from a decimal string + pub fn from_dec_str(string: &str) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let bn = BigNum::from_dec_str(string).unwrap(); + let value = bn.to_vec(); + Self { negative: bn.is_negative(), value} + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_from_dec_str( + in_dec_str_ptr: *const u64, + in_size: u64, + out_ptr: *mut u8, + out_size_ptr: *mut u64, + out_is_neg_flag_ptr: *mut u64, + ) -> u64; + } + let mut value = Vec::::with_capacity(string.len()); + let mut value_len = string.len() as u64; - /// Returns a BigNumber with value set to big endian array of bytes - // pub fn from_bytes(val: &[u8]) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::BigNum; - // let value = BigNum::from_slice(val).unwrap().to_vec(); - // // let bbox = Box::new(BigNum::from_slice(val).unwrap()); - // // let rwptr = Box::into_raw(bbox); - // // let bignum_ptr = rwptr as u64; - // // Self(bignum_ptr) - // Self {value} - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_from_bytes( - // bignum_ptr: *mut u64, - // bytes_ptr: *const u64, - // bytes_len: u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_from_bytes( - // &mut bignum_ptr as *mut _ as *mut u64, - // val.as_ptr() as *const _ as *const u64, - // val.len() as u64, - // ); - // } - // BigNumber::from(bignum_ptr) - // } - // } + let mut is_negative = 0u64; + + + unsafe { + sol_bignum_from_dec_str( + string.as_ptr() as *const _ as *const u64, + string.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut value_len as *mut _ as *mut u64, + &mut is_negative as *mut _ as *mut u64 + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value + } + } + } + + /// Flag indicating if negative or not + pub fn is_negative(&self) -> bool { + self.negative + } /// Returns an array of bytes of self pub fn to_bytes(&self) -> Vec { @@ -531,7 +545,7 @@ impl Default for BigNumber { fn default() -> Self { let mut value = Vec::::new(); value.push(0); - Self { value } + Self { negative: false, value } } } impl fmt::Debug for BigNumber { diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index cc22bd635a3cb6..45d817f1dae38e 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -171,8 +171,8 @@ pub struct BpfComputeBudget { // pub bignum_size_base_cost: u64, /// Base number of compute units consumed to call BigNum new from u32 value pub bignum_from_u32_base_cost: u64, - /// Base number of compute units consumed to call BigNum new from big endian byte array - pub bignum_from_bytes_base_cost: u64, + /// Base number of compute units consumed to call BigNum new from a decimal string + pub bignum_from_dec_str_base_cost: u64, /// Base number of compute units consumed to extract big endian byte array from BigNumb // pub bignum_to_bytes_base_cost: u64, /// Base number of compute units consumed to drop/dealloc BigNum @@ -226,7 +226,7 @@ impl BpfComputeBudget { // bignum_size_base_cost: 100, // bignum_drop_base_cost: 100, bignum_from_u32_base_cost: 100, - bignum_from_bytes_base_cost: 100, + bignum_from_dec_str_base_cost: 100, // bignum_to_bytes_base_cost: 100, bignum_mod_exp_base_cost: 100, log_bignum_cost: 100, From fba26494517f63bfcbb7fd70374fa064d5e563b5 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Sun, 16 May 2021 09:36:57 -0400 Subject: [PATCH 17/45] BigNumber::add implemented with vectors --- programs/bpf/rust/bignum/src/lib.rs | 52 +++-- programs/bpf_loader/src/syscalls.rs | 330 ++++++++++++++-------------- sdk/program/src/bignum.rs | 123 +++++------ 3 files changed, 253 insertions(+), 252 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 98e436f75ad630..48442d98bd89af 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -13,6 +13,17 @@ const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256 374040331773668233371864426354886263106537340208256187214278963052\ 996538599452325797319977413534714912781503130883692806087195354368\ 8304190675878204079994222"; +const NEG_LONG_DEC_STRING: &str = + "-1470463693494555670176851280755142329532258274256991544781479988\ + 712408107190720087233560906792937436573943189716784305633216335039\ + 300236370809933808677983409391545753391897467230180786617074456716\ + 591448871466263060696957107957862111484694673874424855359234132302\ + 162208163361387727626078022804936564470716886986414133429438273232\ + 416190048073715996321578752244853524209178212395809614878549824744\ + 227969245726015222693764433413133633359171080169137831743765672068\ + 374040331773668233371864426354886263106537340208256187214278963052\ + 996538599452325797319977413534714912781503130883692806087195354368\ + 8304190675878204079994222"; /// Compares the array of numbers return from BigNumbers // fn compare_bignum_equal(lhs: &BigNumber, rhs: &BigNumber) -> bool { @@ -32,27 +43,20 @@ fn test_constructors() { msg!("max_bn_u32 {:?}", max_bn_u32.to_bytes()); let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); assert_eq!(bn_from_dec.is_negative(), false); - msg!("dec str bytes {:?}", bn_from_dec.to_bytes()); - // base_bn_0.log(); - // let empty_bn = BigNumber::from_bytes(&[0u8]); - // msg!("empty_bn {}", empty_bn); - // empty_bn.log(); - // new_bn_0.log(); - // max_bn_u32.log(); - // msg!("Big string len = {}", LONG_DEC_STRING.len()); - // let big_string_as_bytes = LONG_DEC_STRING.as_bytes(); - // let new_bn_from_long_str = BigNumber::from_bytes(big_string_as_bytes); - // let new_bn_size = new_bn_from_long_str.size_in_bytes(); - // msg!("Big string size in bytes = {}", new_bn_size); - // new_bn_from_long_str.log(); - // assert_eq!(new_bn_size, big_string_as_bytes.len()); - // let new_long_str_from_bn = new_bn_from_long_str.to_bytes(); - // assert_eq!(new_long_str_from_bn, big_string_as_bytes); + msg!("Positive from_dec_str {}", bn_from_dec.is_negative() != true); + let bn_from_dec = BigNumber::from_dec_str(NEG_LONG_DEC_STRING); + assert!(bn_from_dec.is_negative()); + msg!("Negative from_dec_str {}", bn_from_dec.is_negative()); } /// BigNumber simple number and simple maths -// fn test_basic_maths() { -// msg!("BigNumber Basic Maths"); +fn test_basic_maths() { + msg!("BigNumber Basic Maths"); + let bn_5 = BigNumber::from_u32(5); + let bn_258 = BigNumber::from_u32(258); + let added = bn_5.add(&bn_258); + msg!("added vec {:?}", added.to_bytes()); + assert_eq!(added.to_bytes(), [1, 7]) // let lhs = BigNumber::from_u32(3); // let rhs = BigNumber::from_u32(4); // let add_res = lhs.add(&rhs); @@ -65,7 +69,7 @@ fn test_constructors() { // assert!(compare_bignum_equal(&div_res, &BigNumber::from_u32(2))); // let mul_res = rhs.mul(&lhs); // assert!(compare_bignum_equal(&mul_res, &BigNumber::from_u32(200))); -// } +} // /// BigNumber bigger numbers and complex maths // fn test_complex_maths() { @@ -88,7 +92,7 @@ fn test_constructors() { pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { msg!("bignum"); test_constructors(); - // test_basic_maths(); + test_basic_maths(); // test_complex_maths(); 0u64 } @@ -103,10 +107,10 @@ mod test { fn test_basic_constructors_pass() { test_constructors(); } - // #[test] - // fn test_simple_maths_pass() { - // test_basic_maths(); - // } + #[test] + fn test_simple_maths_pass() { + test_basic_maths(); + } // #[test] // fn test_complex_maths_pass() { // test_complex_maths(); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index b8689d3e71adc9..80121b1441e239 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -79,6 +79,8 @@ pub enum SyscallError { BigNumberModExpError, #[error("BigNumber: Bytes would exceed buffer provided")] BigNumberToBytesError, + #[error("BigNumber: {0} expected {1} args but provided {2}")] + BigNumberArgError(String, u64, u64), #[error("BigNumber: add error")] BigNumberAddError, #[error("BigNumber: sub error")] @@ -1241,14 +1243,13 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { ), result ); - // Get negative flag pointer let is_negative = question_mark!( translate_type_mut::(memory_mapping, out_negative_addr, self.loader_id, true), result ); - - // Exceeds size + // Get return bytes + // Exceeds allocated size if big_number_len > *out_size { *result = Err(SyscallError::BigNumberToBytesError.into()) } else { @@ -1271,63 +1272,6 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { } } -// struct SyscallBigNumToBytes<'a> { -// cost: u64, -// compute_meter: Rc>, -// loader_id: &'a Pubkey, -// } -// impl<'a> SyscallObject for SyscallBigNumToBytes<'a> { -// fn call( -// &mut self, -// bn_self: u64, -// bytes_addr: u64, -// bytes_len_addr: u64, -// _arg4: u64, -// _arg5: u64, -// memory_mapping: &MemoryMapping, -// result: &mut Result>, -// ) { -// let self_bignum_address = question_mark!( -// translate_type::(memory_mapping, bn_self, self.loader_id, true), -// result -// ); -// let bytes_buffer = question_mark!( -// translate_slice_mut::( -// memory_mapping, -// bytes_addr, -// *question_mark!( -// translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), -// result -// ), -// self.loader_id, -// true -// ), -// result -// ); -// let bytes_len = question_mark!( -// translate_type_mut::(memory_mapping, bytes_len_addr, self.loader_id, true), -// result -// ); -// let in_length = *bytes_len; -// let bn_self = unsafe { &*(*self_bignum_address as *mut BigNum) }; -// let bn_bytes = bn_self.as_ref().to_vec(); -// let out_length = bn_bytes.len() as u64; -// question_mark!( -// self.compute_meter -// .consume(self.cost + calc_bignum_cost!(out_length as f64)), -// result -// ); -// if in_length != out_length { -// *bytes_len = 0u64; -// *result = Err(SyscallError::BigNumberToBytesError.into()) -// } else { -// (*bytes_buffer).copy_from_slice(&bn_bytes); -// *bytes_len = out_length; -// *result = Ok(0) -// } -// } -// } - // Keccak256 pub struct SyscallKeccak256<'a> { base_cost: u64, @@ -1452,46 +1396,105 @@ struct SyscallBigNumAdd<'a> { impl<'a> SyscallObject for SyscallBigNumAdd<'a> { fn call( &mut self, - self_addr: u64, - rhs_addr: u64, - sum_addr: u64, - _arg4: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let rhs_ptr = question_mark!( - translate_type::(memory_mapping, rhs_addr, self.loader_id, true), - result - ); - let sum_address = question_mark!( - translate_type_mut::(memory_mapping, sum_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - let mut sum_bn = Box::new(BigNum::new().unwrap()); - // let mut sum_ref = *sum_bn; - match BigNumRef::checked_add(&mut *sum_bn, self_bn, rhs_bn) { - Ok(_) => { - let rwptr = Box::into_raw(sum_bn); - let sum_ptr = rwptr as u64; - *sum_address = sum_ptr; - *result = Ok(0) + let my_func = String::from("sol_bignum_add"); + match arguments_count == 3 { + false => { + *result = Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) } - _ => *result = Err(SyscallError::BigNumberAddError.into()), - }; + true => { + let args = question_mark!( + translate_slice::<&[u8]>( + memory_mapping, + arguments_addr, + arguments_count, + self.loader_id, + true, + ), + result + ); + // Get arguments + let mut arg_iter = args.iter(); + let arg_meta = arg_iter.next().unwrap(); + let mut byte_count = arg_meta.len(); + let mut arg1 = BigNum::from_slice(question_mark!( + translate_slice::(memory_mapping, arg_meta.as_ptr() as u64, arg_meta.len() as u64, self.loader_id, true), + result + )).unwrap(); + let arg_meta = arg_iter.next().unwrap(); + byte_count += arg_meta.len(); + let mut arg2 = BigNum::from_slice(question_mark!( + translate_slice::(memory_mapping, arg_meta.as_ptr() as u64, arg_meta.len() as u64, self.loader_id, true), + result + )).unwrap(); + // Get the negative flags + let arg_meta = arg_iter.next().unwrap(); + let neg_flag_array = question_mark!( + translate_slice::(memory_mapping, arg_meta.as_ptr() as u64, arg_meta.len() as u64, self.loader_id, true), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::(memory_mapping, out_result_addr, *out_size, self.loader_id, true), + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + result + ); + arg1.set_negative(neg_flag_array[0] == 1); + arg2.set_negative(neg_flag_array[1] == 1); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_add(&arg1, &arg2) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::(memory_mapping, out_negative_addr, self.loader_id, true), + result + ); + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + }, + Err(_) => { + *result = Err(SyscallError::BigNumberAddError.into()) + } + } + } + } } } @@ -4226,57 +4229,6 @@ mod tests { let bns_vec = bns.as_ref().to_vec(); assert_eq!(result_vec, bns_vec); } - // #[test] - // fn test_syscall_bignum_to_bytes() { - // let val = LONG_DEC_STRING.as_bytes(); - // let mut bn = new_bytes_bignum(val); - // let bn_addr = &mut bn as *mut _ as u64; - // let big_num: &BigNum = unsafe { &*(bn as *mut BigNum) }; - // let existing_size = big_num.num_bytes() as usize; - // let bytes_buf = vec![0u8; existing_size]; - // let mut bytes_len = bytes_buf.len(); - // let bytes_len_addr = &mut bytes_len as *mut _ as u64; - // let memory_mapping = MemoryMapping::new::( - // vec![ - // MemoryRegion { - // host_addr: bn_addr, - // vm_addr: 8, - // len: std::mem::size_of::() as u64, - // vm_gap_shift: 63, - // is_writable: false, - // }, - // MemoryRegion { - // host_addr: bytes_buf.as_ptr() as *const _ as u64, - // vm_addr: 1024, - // len: bytes_len as u64, - // vm_gap_shift: 63, - // is_writable: true, - // }, - // MemoryRegion { - // host_addr: bytes_len_addr, - // vm_addr: 96, - // len: std::mem::size_of::() as u64, - // vm_gap_shift: 63, - // is_writable: true, - // }, - // ], - // &DEFAULT_CONFIG, - // ) - // .unwrap(); - - // let compute_meter: Rc> = - // Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); - // let mut syscall = SyscallBigNumToBytes { - // cost: 100, - // compute_meter, - // loader_id: &bpf_loader::id(), - // }; - // let mut result: Result> = Ok(0); - // syscall.call(8, 1024, 96, 0, 0, &memory_mapping, &mut result); - // result.unwrap(); - // assert_eq!(bytes_len, val.len()); - // assert_eq!(big_num.as_ref().to_vec(), bytes_buf.to_vec()); - // } #[test] fn test_syscall_bignum_mod_exp() { @@ -4343,31 +4295,82 @@ mod tests { #[test] fn test_syscall_bignum_add() { - let mut sum = 0u64; - let sum_addr = &mut sum as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(2); - let bn_3_ptr = new_u32_bignum(3); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_addr = &bn_3_ptr as *const _ as u64; + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(5).unwrap(); + let bn_arg2 = BigNum::from_u32(258).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + let neg_flag = 0u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: sum_addr, + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -4376,6 +4379,7 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, @@ -4386,10 +4390,10 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(sum as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(5).unwrap()); + unsafe{result_vec.set_len(out_size as usize)}; + assert_eq!(result_vec, vec![1, 7]); } #[test] fn test_syscall_bignum_sub() { diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 55b8bcc8fc3a84..a26b88a8857646 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -98,10 +98,7 @@ impl BigNumber { } let mut value = Vec::::with_capacity(string.len()); let mut value_len = string.len() as u64; - let mut is_negative = 0u64; - - unsafe { sol_bignum_from_dec_str( string.as_ptr() as *const _ as *const u64, @@ -125,70 +122,66 @@ impl BigNumber { } /// Returns an array of bytes of self - pub fn to_bytes(&self) -> Vec { - self.value.clone() - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::BigNum; - // let braw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // braw.as_ref().to_vec() - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_to_bytes( - // bignum_ptr: *const u64, - // bytes_ptr: *mut u8, - // bytes_len: *mut u64, - // ) -> u64; - // } - // // Get the BigNum size, allocate result vector - // let mut bignum_size = self.size_in_bytes() as u64; - // let mut my_buffer = Vec::::with_capacity(bignum_size as usize); - // unsafe { - // sol_bignum_to_bytes( - // &self.0 as *const _ as *const u64, - // my_buffer.as_mut_ptr() as *mut _ as *mut u8, - // &mut bignum_size as *mut _ as *mut u64, - // ); - // my_buffer.set_len(bignum_size as usize); - // } - // my_buffer.clone() - // } + pub fn to_bytes(&self) -> &[u8] { + &self.value } - // /// Add BigNumbers - // pub fn add(&self, rhs: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - // BigNumRef::checked_add(&mut bbox, my_raw, rhs_ptr).unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_add( - // self_ptr: *const u64, - // rhs_ptr: *const u64, - // return_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_add( - // &self.0 as *const _ as *const u64, - // &rhs.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } + /// Add BigNumbers + pub fn add(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&rhs.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res.checked_add(&my_num, &rhs_num).unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_add( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, rhs.negative as u8]; + let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; + // let mut arg_array = Vec::<&[u8]>::new(); + // arg_array.push(self.to_bytes()); + // arg_array.push(rhs.to_bytes()); + // arg_array.push(&neg_values); + + + let mut value_len = std::cmp::max(self.value.len(),rhs.value.len()) +1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + + unsafe { + sol_bignum_add( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value + } + } + } // /// Subtract BigNumbers // pub fn sub(&self, rhs: &BigNumber) -> Self { From cbd738bbd8da43d6f01ed37777fe5f7aa7347429 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Sun, 16 May 2021 09:43:02 -0400 Subject: [PATCH 18/45] Formatting --- programs/bpf/rust/bignum/src/lib.rs | 6 +- programs/bpf_loader/src/syscalls.rs | 307 ++++++++++++++++------------ sdk/program/src/bignum.rs | 49 +++-- 3 files changed, 207 insertions(+), 155 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 48442d98bd89af..e85dab8d420a02 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -56,11 +56,7 @@ fn test_basic_maths() { let bn_258 = BigNumber::from_u32(258); let added = bn_5.add(&bn_258); msg!("added vec {:?}", added.to_bytes()); - assert_eq!(added.to_bytes(), [1, 7]) -// let lhs = BigNumber::from_u32(3); -// let rhs = BigNumber::from_u32(4); -// let add_res = lhs.add(&rhs); -// assert!(compare_bignum_equal(&add_res, &BigNumber::from_u32(7))); + assert_eq!(added.to_bytes(), [1, 7]); // let sub_res = rhs.sub(&lhs); // assert!(compare_bignum_equal(&sub_res, &BigNumber::from_u32(1))); // let lhs = BigNumber::from_u32(20); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 80121b1441e239..4c13f19252914b 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1139,6 +1139,64 @@ impl<'a> SyscallObject for SyscallSha256<'a> { *result = Ok(0); } } +// Keccak256 +pub struct SyscallKeccak256<'a> { + base_cost: u64, + byte_cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallKeccak256<'a> { + fn call( + &mut self, + vals_addr: u64, + vals_len: u64, + result_addr: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.base_cost), result); + let hash_result = question_mark!( + translate_slice_mut::( + memory_mapping, + result_addr, + keccak::HASH_BYTES as u64, + self.loader_id, + true, + ), + result + ); + let mut hasher = keccak::Hasher::default(); + if vals_len > 0 { + let vals = question_mark!( + translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id, true), + result + ); + for val in vals.iter() { + let bytes = question_mark!( + translate_slice::( + memory_mapping, + val.as_ptr() as u64, + val.len() as u64, + self.loader_id, + true, + ), + result + ); + question_mark!( + self.compute_meter + .consume(self.byte_cost * (val.len() as u64 / 2)), + result + ); + hasher.hash(bytes); + } + } + hash_result.copy_from_slice(&hasher.result().to_bytes()); + *result = Ok(0); + } +} /// BIGNUM data cost const BIGNUM_WORDCOST: f64 = 6.0; @@ -1217,7 +1275,13 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { // Get the string and convert to BigNum let in_dec_raw = question_mark!( - translate_slice::(memory_mapping, in_dec_str_addr, in_size, self.loader_id, true), + translate_slice::( + memory_mapping, + in_dec_str_addr, + in_size, + self.loader_id, + true + ), result ); let i = match in_dec_raw.iter().position(|byte| *byte == 0) { @@ -1250,7 +1314,7 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { ); // Get return bytes // Exceeds allocated size - if big_number_len > *out_size { + if big_number_len > *out_size { *result = Err(SyscallError::BigNumberToBytesError.into()) } else { // Equal (memcpy) @@ -1272,121 +1336,6 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { } } -// Keccak256 -pub struct SyscallKeccak256<'a> { - base_cost: u64, - byte_cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallKeccak256<'a> { - fn call( - &mut self, - vals_addr: u64, - vals_len: u64, - result_addr: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - question_mark!(self.compute_meter.consume(self.base_cost), result); - let hash_result = question_mark!( - translate_slice_mut::( - memory_mapping, - result_addr, - keccak::HASH_BYTES as u64, - self.loader_id, - true, - ), - result - ); - let mut hasher = keccak::Hasher::default(); - if vals_len > 0 { - let vals = question_mark!( - translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id, true), - result - ); - for val in vals.iter() { - let bytes = question_mark!( - translate_slice::( - memory_mapping, - val.as_ptr() as u64, - val.len() as u64, - self.loader_id, - true, - ), - result - ); - question_mark!( - self.compute_meter - .consume(self.byte_cost * (val.len() as u64 / 2)), - result - ); - hasher.hash(bytes); - } - } - hash_result.copy_from_slice(&hasher.result().to_bytes()); - *result = Ok(0); - } -} - -/// BIGNUM sol_bignum_mod_exp -struct SyscallBigNumModExp<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumModExp<'a> { - fn call( - &mut self, - mod_exp_addr: u64, - self_bn_addr: u64, - exponent_bn_addr: u64, - modulus_bn_addr: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - let mod_bignum_address = question_mark!( - translate_type_mut::(memory_mapping, mod_exp_addr, self.loader_id, true), - result - ); - let self_bignum_address = question_mark!( - translate_type::(memory_mapping, self_bn_addr, self.loader_id, true), - result - ); - let exponent_bignum_address = question_mark!( - translate_type::(memory_mapping, exponent_bn_addr, self.loader_id, true), - result - ); - let modulus_bignum_address = question_mark!( - translate_type::(memory_mapping, modulus_bn_addr, self.loader_id, true), - result - ); - - let mut mod_exp_bn = Box::new(BigNum::new().unwrap()); - let bn_self = unsafe { &*(*self_bignum_address as *const BigNum) }; - let bn_exponent = unsafe { &*(*exponent_bignum_address as *const BigNum) }.as_ref(); - let bn_modulus = (unsafe { &*(*modulus_bignum_address as *const BigNum) }).as_ref(); - let bytes = (bn_self.num_bytes() + bn_exponent.num_bytes() + bn_modulus.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - let ctx = &mut BigNumContext::new().unwrap(); - match mod_exp_bn.mod_exp(bn_self, bn_exponent, bn_modulus, ctx) { - Ok(()) => { - let rwptr = Box::into_raw(mod_exp_bn); - let mod_exp_ptr = rwptr as u64; - *mod_bignum_address = mod_exp_ptr; - *result = Ok(0) - } - Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), - } - } -} /// Add BigNums struct SyscallBigNumAdd<'a> { cost: u64, @@ -1407,7 +1356,8 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { let my_func = String::from("sol_bignum_add"); match arguments_count == 3 { false => { - *result = Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) + *result = + Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) } true => { let args = question_mark!( @@ -1425,19 +1375,39 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { let arg_meta = arg_iter.next().unwrap(); let mut byte_count = arg_meta.len(); let mut arg1 = BigNum::from_slice(question_mark!( - translate_slice::(memory_mapping, arg_meta.as_ptr() as u64, arg_meta.len() as u64, self.loader_id, true), + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), result - )).unwrap(); + )) + .unwrap(); let arg_meta = arg_iter.next().unwrap(); byte_count += arg_meta.len(); let mut arg2 = BigNum::from_slice(question_mark!( - translate_slice::(memory_mapping, arg_meta.as_ptr() as u64, arg_meta.len() as u64, self.loader_id, true), + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), result - )).unwrap(); + )) + .unwrap(); // Get the negative flags let arg_meta = arg_iter.next().unwrap(); let neg_flag_array = question_mark!( - translate_slice::(memory_mapping, arg_meta.as_ptr() as u64, arg_meta.len() as u64, self.loader_id, true), + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), result ); // Get out size and out vector @@ -1446,7 +1416,13 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { result ); let bignum_result = question_mark!( - translate_slice_mut::(memory_mapping, out_result_addr, *out_size, self.loader_id, true), + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), result ); // Compute costs @@ -1464,12 +1440,17 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { // Get out_size pointer and negative flag pointer // Get negative flag pointer let is_negative = question_mark!( - translate_type_mut::(memory_mapping, out_negative_addr, self.loader_id, true), + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), result ); let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; - if big_number_len > *out_size { + if big_number_len > *out_size { *result = Err(SyscallError::BigNumberToBytesError.into()) } else { // Equal (memcpy) @@ -1488,10 +1469,8 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { *is_negative = bn_result.is_negative() as u64; *result = Ok(0) } - }, - Err(_) => { - *result = Err(SyscallError::BigNumberAddError.into()) } + Err(_) => *result = Err(SyscallError::BigNumberAddError.into()), } } } @@ -1759,6 +1738,64 @@ impl<'a> SyscallObject for SyscallBigNumSqr<'a> { }; } } + +/// BIGNUM sol_bignum_mod_exp +struct SyscallBigNumModExp<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumModExp<'a> { + fn call( + &mut self, + mod_exp_addr: u64, + self_bn_addr: u64, + exponent_bn_addr: u64, + modulus_bn_addr: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let mod_bignum_address = question_mark!( + translate_type_mut::(memory_mapping, mod_exp_addr, self.loader_id, true), + result + ); + let self_bignum_address = question_mark!( + translate_type::(memory_mapping, self_bn_addr, self.loader_id, true), + result + ); + let exponent_bignum_address = question_mark!( + translate_type::(memory_mapping, exponent_bn_addr, self.loader_id, true), + result + ); + let modulus_bignum_address = question_mark!( + translate_type::(memory_mapping, modulus_bn_addr, self.loader_id, true), + result + ); + + let mut mod_exp_bn = Box::new(BigNum::new().unwrap()); + let bn_self = unsafe { &*(*self_bignum_address as *const BigNum) }; + let bn_exponent = unsafe { &*(*exponent_bignum_address as *const BigNum) }.as_ref(); + let bn_modulus = (unsafe { &*(*modulus_bignum_address as *const BigNum) }).as_ref(); + let bytes = (bn_self.num_bytes() + bn_exponent.num_bytes() + bn_modulus.num_bytes()) as f64; + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes)), + result + ); + let ctx = &mut BigNumContext::new().unwrap(); + match mod_exp_bn.mod_exp(bn_self, bn_exponent, bn_modulus, ctx) { + Ok(()) => { + let rwptr = Box::into_raw(mod_exp_bn); + let mod_exp_ptr = rwptr as u64; + *mod_bignum_address = mod_exp_ptr; + *result = Ok(0) + } + Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), + } + } +} + struct SyscallBigNumModSqr<'a> { cost: u64, compute_meter: Rc>, @@ -4201,7 +4238,15 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(2048, dec_str_len as u64, 8196, 96, 8, &memory_mapping, &mut result); + syscall.call( + 2048, + dec_str_len as u64, + 8196, + 96, + 8, + &memory_mapping, + &mut result, + ); result.unwrap(); (neg_flag != 0, bytes_buf[0..bytes_len].to_vec()) } @@ -4392,7 +4437,7 @@ mod tests { let mut result: Result> = Ok(0); syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - unsafe{result_vec.set_len(out_size as usize)}; + unsafe { result_vec.set_len(out_size as usize) }; assert_eq!(result_vec, vec![1, 7]); } #[test] diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index a26b88a8857646..d6e4b1ccb5700d 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -28,7 +28,10 @@ impl BigNumber { pub fn new() -> Self { let mut value = Vec::::new(); value.push(0u8); - Self { negative: false, value } + Self { + negative: false, + value, + } } /// Returns the size, in bytes, of BigNum. Typically used in @@ -42,13 +45,19 @@ impl BigNumber { if val == 0 { let mut value = Vec::::new(); value.push(0); - Self { negative: false, value } + Self { + negative: false, + value, + } } else { #[cfg(not(target_arch = "bpf"))] { use openssl::bn::BigNum; let value = BigNum::from_u32(val).unwrap().to_vec(); - Self { negative: false, value } + Self { + negative: false, + value, + } } #[cfg(target_arch = "bpf")] { @@ -72,7 +81,10 @@ impl BigNumber { ); value.set_len(vec_size); } - Self { negative: false, value } + Self { + negative: false, + value, + } } } } @@ -83,7 +95,10 @@ impl BigNumber { use openssl::bn::BigNum; let bn = BigNum::from_dec_str(string).unwrap(); let value = bn.to_vec(); - Self { negative: bn.is_negative(), value} + Self { + negative: bn.is_negative(), + value, + } } #[cfg(target_arch = "bpf")] { @@ -105,13 +120,13 @@ impl BigNumber { string.len() as u64, value.as_mut_ptr() as *mut _ as *mut u8, &mut value_len as *mut _ as *mut u64, - &mut is_negative as *mut _ as *mut u64 + &mut is_negative as *mut _ as *mut u64, ); value.set_len(value_len as usize); } Self { negative: is_negative != 0, - value + value, } } } @@ -138,7 +153,7 @@ impl BigNumber { let value = bn_res.as_ref().to_vec(); Self { negative: bn_res.is_negative(), - value + value, } } #[cfg(target_arch = "bpf")] @@ -155,16 +170,10 @@ impl BigNumber { // Setup the argument array (3) let neg_values = vec![self.negative as u8, rhs.negative as u8]; let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; - // let mut arg_array = Vec::<&[u8]>::new(); - // arg_array.push(self.to_bytes()); - // arg_array.push(rhs.to_bytes()); - // arg_array.push(&neg_values); - - - let mut value_len = std::cmp::max(self.value.len(),rhs.value.len()) +1; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), rhs.value.len()) + 1; let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; - unsafe { sol_bignum_add( arg_array.as_ptr() as *const _ as *const u64, @@ -172,13 +181,12 @@ impl BigNumber { value.as_mut_ptr() as *mut _ as *mut u8, &mut is_negative as *mut _ as *mut u64, &mut value_len as *mut _ as *mut u64, - ); value.set_len(value_len as usize); } Self { negative: is_negative != 0, - value + value, } } } @@ -538,7 +546,10 @@ impl Default for BigNumber { fn default() -> Self { let mut value = Vec::::new(); value.push(0); - Self { negative: false, value } + Self { + negative: false, + value, + } } } impl fmt::Debug for BigNumber { From 22107d0f5e6260f0a1e40c6acbdac518a4b705f8 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Sun, 16 May 2021 11:46:10 -0400 Subject: [PATCH 19/45] BigNumber simple maths using vectors instead of Box --- programs/bpf/rust/bignum/src/lib.rs | 26 +- programs/bpf_loader/src/syscalls.rs | 747 +++++++++++++++++++++------- sdk/program/src/bignum.rs | 256 ++++++---- 3 files changed, 739 insertions(+), 290 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index e85dab8d420a02..659281269c3e2b 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -25,11 +25,6 @@ const NEG_LONG_DEC_STRING: &str = 996538599452325797319977413534714912781503130883692806087195354368\ 8304190675878204079994222"; -/// Compares the array of numbers return from BigNumbers -// fn compare_bignum_equal(lhs: &BigNumber, rhs: &BigNumber) -> bool { -// lhs.to_bytes() == rhs.to_bytes() -// } - /// BigNumber construction fn test_constructors() { msg!("BigNumber constructors"); @@ -55,16 +50,19 @@ fn test_basic_maths() { let bn_5 = BigNumber::from_u32(5); let bn_258 = BigNumber::from_u32(258); let added = bn_5.add(&bn_258); - msg!("added vec {:?}", added.to_bytes()); + msg!("add bn vec {:?}", added.to_bytes()); assert_eq!(added.to_bytes(), [1, 7]); -// let sub_res = rhs.sub(&lhs); -// assert!(compare_bignum_equal(&sub_res, &BigNumber::from_u32(1))); -// let lhs = BigNumber::from_u32(20); -// let rhs = BigNumber::from_u32(10); -// let div_res = lhs.div(&rhs); -// assert!(compare_bignum_equal(&div_res, &BigNumber::from_u32(2))); -// let mul_res = rhs.mul(&lhs); -// assert!(compare_bignum_equal(&mul_res, &BigNumber::from_u32(200))); + let subed = bn_5.sub(&bn_258); + msg!("sub bn vec {:?}", subed.to_bytes()); + assert_eq!(subed.to_bytes(), vec![253]); + let muled = bn_5.mul(&bn_5); + msg!("mul bn vec {:?}", muled.to_bytes()); + assert_eq!(muled.to_bytes(), vec![25]); + let bn_300 = BigNumber::from_u32(300); + let bn_10 = BigNumber::from_u32(10); + let dived = bn_300.div(&bn_10); + msg!("div bn vec {:?}", dived.to_bytes()); + assert_eq!(dived.to_bytes(), vec![30]); } // /// BigNumber bigger numbers and complex maths diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 4c13f19252914b..d0c9bc459fbda1 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1486,45 +1486,135 @@ struct SyscallBigNumSub<'a> { impl<'a> SyscallObject for SyscallBigNumSub<'a> { fn call( &mut self, - self_addr: u64, - rhs_addr: u64, - diff_addr: u64, - _arg4: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let rhs_ptr = question_mark!( - translate_type::(memory_mapping, rhs_addr, self.loader_id, true), - result - ); - let diff_address = question_mark!( - translate_type_mut::(memory_mapping, diff_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - let mut diff_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::checked_sub(&mut *diff_bn, self_bn, rhs_bn) { - Ok(_) => { - let rwptr = Box::into_raw(diff_bn); - let diff_ptr = rwptr as u64; - *diff_address = diff_ptr; - *result = Ok(0) + let my_func = String::from("sol_bignum_sub"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) } - _ => *result = Err(SyscallError::BigNumberSubError.into()), - }; + true => { + let args = question_mark!( + translate_slice::<&[u8]>( + memory_mapping, + arguments_addr, + arguments_count, + self.loader_id, + true, + ), + result + ); + // Get arguments + let mut arg_iter = args.iter(); + let arg_meta = arg_iter.next().unwrap(); + let mut byte_count = arg_meta.len(); + let mut arg1 = BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + )) + .unwrap(); + let arg_meta = arg_iter.next().unwrap(); + byte_count += arg_meta.len(); + let mut arg2 = BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + )) + .unwrap(); + // Get the negative flags + let arg_meta = arg_iter.next().unwrap(); + let neg_flag_array = question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + result + ); + arg1.set_negative(neg_flag_array[0] == 1); + arg2.set_negative(neg_flag_array[1] == 1); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_sub(&arg1, &arg2) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberSubError.into()), + } + } + } } } /// Subtract BigNums @@ -1536,51 +1626,135 @@ struct SyscallBigNumMul<'a> { impl<'a> SyscallObject for SyscallBigNumMul<'a> { fn call( &mut self, - self_addr: u64, - rhs_addr: u64, - prod_addr: u64, - _arg4: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let rhs_ptr = question_mark!( - translate_type::(memory_mapping, rhs_addr, self.loader_id, true), - result - ); - let prod_address = question_mark!( - translate_type_mut::(memory_mapping, prod_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - - let mut prod_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::checked_mul( - &mut *prod_bn, - self_bn, - rhs_bn, - &mut BigNumContext::new().unwrap(), - ) { - Ok(_) => { - let rwptr = Box::into_raw(prod_bn); - let prod_ptr = rwptr as u64; - *prod_address = prod_ptr; - *result = Ok(0) + let my_func = String::from("sol_bignum_mul"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) } - _ => *result = Err(SyscallError::BigNumberMulError.into()), - }; + true => { + let args = question_mark!( + translate_slice::<&[u8]>( + memory_mapping, + arguments_addr, + arguments_count, + self.loader_id, + true, + ), + result + ); + // Get arguments + let mut arg_iter = args.iter(); + let arg_meta = arg_iter.next().unwrap(); + let mut byte_count = arg_meta.len(); + let mut arg1 = BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + )) + .unwrap(); + let arg_meta = arg_iter.next().unwrap(); + byte_count += arg_meta.len(); + let mut arg2 = BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + )) + .unwrap(); + // Get the negative flags + let arg_meta = arg_iter.next().unwrap(); + let neg_flag_array = question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + result + ); + arg1.set_negative(neg_flag_array[0] == 1); + arg2.set_negative(neg_flag_array[1] == 1); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_mul(&arg1, &arg2, &mut BigNumContext::new().unwrap()) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberMulError.into()), + } + } + } } } struct SyscallBigNumDiv<'a> { @@ -1591,51 +1765,135 @@ struct SyscallBigNumDiv<'a> { impl<'a> SyscallObject for SyscallBigNumDiv<'a> { fn call( &mut self, - self_addr: u64, - rhs_addr: u64, - quotient_addr: u64, - _arg4: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let rhs_ptr = question_mark!( - translate_type::(memory_mapping, rhs_addr, self.loader_id, true), - result - ); - let quotient_address = question_mark!( - translate_type_mut::(memory_mapping, quotient_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let rhs_bn = unsafe { &*(*rhs_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + rhs_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - - let mut quot_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::checked_div( - &mut *quot_bn, - self_bn, - rhs_bn, - &mut BigNumContext::new().unwrap(), - ) { - Ok(_) => { - let rwptr = Box::into_raw(quot_bn); - let prod_ptr = rwptr as u64; - *quotient_address = prod_ptr; - *result = Ok(0) + let my_func = String::from("sol_bignum_div"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) + } + true => { + let args = question_mark!( + translate_slice::<&[u8]>( + memory_mapping, + arguments_addr, + arguments_count, + self.loader_id, + true, + ), + result + ); + // Get arguments + let mut arg_iter = args.iter(); + let arg_meta = arg_iter.next().unwrap(); + let mut byte_count = arg_meta.len(); + let mut arg1 = BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + )) + .unwrap(); + let arg_meta = arg_iter.next().unwrap(); + byte_count += arg_meta.len(); + let mut arg2 = BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + )) + .unwrap(); + // Get the negative flags + let arg_meta = arg_iter.next().unwrap(); + let neg_flag_array = question_mark!( + translate_slice::( + memory_mapping, + arg_meta.as_ptr() as u64, + arg_meta.len() as u64, + self.loader_id, + true + ), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + result + ); + arg1.set_negative(neg_flag_array[0] == 1); + arg2.set_negative(neg_flag_array[1] == 1); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_div(&arg1, &arg2, &mut BigNumContext::new().unwrap()) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberDivError.into()), + } } - _ => *result = Err(SyscallError::BigNumberDivError.into()), - }; + } } } struct SyscallBigNumExp<'a> { @@ -3158,7 +3416,7 @@ mod tests { hash::hashv, process_instruction::{MockComputeMeter, MockInvokeContext, MockLogger}, }; - use std::str::FromStr; + use std::{str::FromStr, vec}; const DEFAULT_CONFIG: Config = Config { max_call_depth: 20, @@ -4354,7 +4612,6 @@ mod tests { let out_size_addr = &mut out_size as *mut _ as u64; let mut neg_result = 0u64; let neg_flag_addr = &mut neg_result as *mut _ as u64; - let neg_flag = 0u64; let mock_arg1 = ArgSlice { addr: 1024, @@ -4442,31 +4699,81 @@ mod tests { } #[test] fn test_syscall_bignum_sub() { - let mut diff = 0u64; - let diff_addr = &mut diff as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(2); - let bn_3_ptr = new_u32_bignum(3); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_addr = &bn_3_ptr as *const _ as u64; + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(5).unwrap(); + let bn_arg2 = BigNum::from_u32(258).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: diff_addr, + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -4475,6 +4782,7 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, @@ -4485,38 +4793,89 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(diff as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_dec_str("-1").unwrap()); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![253]); } + #[test] fn test_syscall_bignum_mul() { - let mut prod = 0u64; - let prod_addr = &mut prod as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(2); - let bn_3_ptr = new_u32_bignum(3); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_addr = &bn_3_ptr as *const _ as u64; + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(5).unwrap(); + let bn_arg2 = BigNum::from_u32(5).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: prod_addr, + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -4525,6 +4884,7 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, @@ -4535,38 +4895,89 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(prod as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(6).unwrap()); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![25]); } + #[test] fn test_syscall_bignum_div() { - let mut quot = 0u64; - let quot_addr = &mut quot as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(4); - let bn_3_ptr = new_u32_bignum(2); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_addr = &bn_3_ptr as *const _ as u64; + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(300).unwrap(); + let bn_arg2 = BigNum::from_u32(10).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: quot_addr, + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -4575,6 +4986,7 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, @@ -4585,11 +4997,12 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(quot as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(2).unwrap()); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![30]); } + #[test] fn test_syscall_bignum_exp() { let mut exp = 0u64; diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index d6e4b1ccb5700d..d0a2e28d639d7a 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -190,78 +190,154 @@ impl BigNumber { } } } + /// Subtract BigNumbers + pub fn sub(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::BigNum; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&rhs.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res.checked_sub(&my_num, &rhs_num).unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_sub( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, rhs.negative as u8]; + let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), rhs.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + unsafe { + sol_bignum_sub( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } - // /// Subtract BigNumbers - // pub fn sub(&self, rhs: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - // BigNumRef::checked_sub(&mut *bbox, my_raw, rhs_ptr).unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_sub( - // self_ptr: *const u64, - // rhs_ptr: *const u64, - // return_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_sub( - // &self.0 as *const _ as *const u64, - // &rhs.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } - - // /// Multiple BigNumbers - // pub fn mul(&self, rhs: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - // BigNumRef::checked_mul( - // &mut *bbox, - // my_raw, - // rhs_ptr, - // &mut BigNumContext::new().unwrap(), - // ) - // .unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_mul( - // self_ptr: *const u64, - // rhs_ptr: *const u64, - // return_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_mul( - // &self.0 as *const _ as *const u64, - // &rhs.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } + /// Multiple BigNumbers + pub fn mul(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&rhs.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res.checked_mul(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()).unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_mul( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, rhs.negative as u8]; + let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), rhs.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + unsafe { + sol_bignum_mul( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } + /// Divide BigNumbers + pub fn div(&self, rhs: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&rhs.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res.checked_div(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()).unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_div( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, rhs.negative as u8]; + let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), rhs.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + unsafe { + sol_bignum_div( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } // /// Mod multiplier (self * multiplier) % modulus // pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { @@ -341,44 +417,6 @@ impl BigNumber { // } // } - // /// Divide BigNumbers - // pub fn div(&self, rhs: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // let rhs_ptr: &BigNum = unsafe { &*(rhs.0 as *const BigNum) }; - // BigNumRef::checked_div( - // &mut *bbox, - // my_raw, - // rhs_ptr, - // &mut BigNumContext::new().unwrap(), - // ) - // .unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_div( - // self_ptr: *const u64, - // rhs_ptr: *const u64, - // return_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_div( - // &self.0 as *const _ as *const u64, - // &rhs.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } // /// Square BigNumbers // pub fn sqr(&self) -> Self { From 47c57b18592fb5c26237570e717fb82ae53c46f4 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 06:06:02 -0400 Subject: [PATCH 20/45] BigNumber complex maths-part1 using vector instead of Box --- programs/bpf/rust/bignum/src/lib.rs | 35 +- programs/bpf_loader/src/syscalls.rs | 708 +++++++++++++++++----------- sdk/bpf/c/inc/solana_sdk.h | 165 ++++--- sdk/program/src/bignum.rs | 209 ++++---- sdk/src/process_instruction.rs | 16 +- 5 files changed, 635 insertions(+), 498 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 659281269c3e2b..62e7ad178bda0d 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -65,29 +65,22 @@ fn test_basic_maths() { assert_eq!(dived.to_bytes(), vec![30]); } -// /// BigNumber bigger numbers and complex maths -// fn test_complex_maths() { -// msg!("BigNumber Complex Maths"); -// let base_3 = BigNumber::from_u32(3); -// let exp_base_3 = base_3.clone(); -// let modulus_7 = BigNumber::from_u32(7); -// assert!(compare_bignum_equal( -// &base_3.mod_mul(&exp_base_3, &modulus_7), -// &BigNumber::from_u32(2) -// )); -// let base_15 = BigNumber::from_u32(15); -// assert!(compare_bignum_equal( -// &base_15.mod_sqr(&modulus_7), -// &BigNumber::from_u32(1) -// )); -// } +/// BigNumber bigger numbers and complex maths +fn test_complex_maths() { + msg!("BigNumber Complex Maths"); + let bn_arg1 = BigNumber::from_u32(8); + let bn_arg2 = BigNumber::from_u32(2); + let exp_res = bn_arg1.exp(&bn_arg2); + msg!("exp vec {:?}", exp_res.to_bytes()); + assert_eq!(exp_res.to_bytes(), vec![64]); +} #[no_mangle] pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { msg!("bignum"); test_constructors(); test_basic_maths(); - // test_complex_maths(); + test_complex_maths(); 0u64 } @@ -105,8 +98,8 @@ mod test { fn test_simple_maths_pass() { test_basic_maths(); } - // #[test] - // fn test_complex_maths_pass() { - // test_complex_maths(); - // } + #[test] + fn test_complex_maths_pass() { + test_complex_maths(); + } } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d0c9bc459fbda1..d46e13e77d6013 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -189,7 +189,7 @@ pub fn register_syscalls( // .register_syscall_by_name(b"sol_bignum_to_bytes", SyscallBigNumToBytes::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mod_exp", SyscallBigNumModExp::call)?; // syscall_registry.register_syscall_by_name(b"sol_bignum_drop", SyscallBigNumDrop::call)?; - syscall_registry.register_syscall_by_name(b"sol_log_bignum", SyscallLogBigNum::call)?; + syscall_registry.register_syscall_by_name(b"sol_bignum_log", SyscallBigNumLog::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_add", SyscallBigNumAdd::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_sub", SyscallBigNumSub::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mul", SyscallBigNumMul::call)?; @@ -366,8 +366,8 @@ pub fn bind_syscall_context_objects<'a>( // )?; vm.bind_syscall_context_object( - Box::new(SyscallLogBigNum { - cost: bpf_compute_budget.log_bignum_cost, + Box::new(SyscallBigNumLog { + cost: bpf_compute_budget.bignum_log_cost, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), loader_id, @@ -1336,6 +1336,51 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { } } +/// Converts the arguments array into BigNum and set negative flag +/// Argument array is BigNum slices for 0..n-1, n is negative flag array +fn translate_bignum_args( + arg_addr: u64, + arg_count: u64, + loader_id: &Pubkey, + buffers: &mut Vec, + bytes: &mut u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, +) { + let args = question_mark!( + translate_slice::<&[u8]>(memory_mapping, arg_addr, arg_count, loader_id, true,), + result + ); + *bytes = 0; + // BigNums are all but ast + for arg in args[0..args.len() - 1 ].iter() { + buffers.push( + BigNum::from_slice(question_mark!( + translate_slice::( + memory_mapping, + arg.as_ptr() as u64, + arg.len() as u64, + loader_id, + true + ), + result + )).unwrap() + ) + } + // Negative flags are last + let last = args.last().unwrap(); + let neg_flags = question_mark!( + translate_slice::(memory_mapping, last.as_ptr() as u64, last.len() as u64, loader_id, true), + result + ); + // Get byte count and set negative flag + *bytes += neg_flags.len() as u64; + for x in 0..neg_flags.len() { + *bytes += buffers[x].num_bytes() as u64; + buffers[x].set_negative(neg_flags[x] == 1) + } +} + /// Add BigNums struct SyscallBigNumAdd<'a> { cost: u64, @@ -1357,57 +1402,24 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { match arguments_count == 3 { false => { *result = - Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) } true => { - let args = question_mark!( - translate_slice::<&[u8]>( - memory_mapping, - arguments_addr, - arguments_count, - self.loader_id, - true, - ), + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, result ); - // Get arguments - let mut arg_iter = args.iter(); - let arg_meta = arg_iter.next().unwrap(); - let mut byte_count = arg_meta.len(); - let mut arg1 = BigNum::from_slice(question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), - result - )) - .unwrap(); - let arg_meta = arg_iter.next().unwrap(); - byte_count += arg_meta.len(); - let mut arg2 = BigNum::from_slice(question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), - result - )) - .unwrap(); - // Get the negative flags - let arg_meta = arg_iter.next().unwrap(); - let neg_flag_array = question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), result ); // Get out size and out vector @@ -1425,29 +1437,20 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { ), result ); - // Compute costs - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), result ); - arg1.set_negative(neg_flag_array[0] == 1); - arg2.set_negative(neg_flag_array[1] == 1); // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.checked_add(&arg1, &arg2) { + match bn_result.checked_add(&buffer[0], &buffer[1]) { Ok(_) => { - // Get out_size pointer and negative flag pointer - // Get negative flag pointer - let is_negative = question_mark!( - translate_type_mut::( - memory_mapping, - out_negative_addr, - self.loader_id, - true - ), - result - ); let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; if big_number_len > *out_size { @@ -1498,59 +1501,221 @@ impl<'a> SyscallObject for SyscallBigNumSub<'a> { match arguments_count == 3 { false => { *result = - Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) } true => { - let args = question_mark!( - translate_slice::<&[u8]>( + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( memory_mapping, - arguments_addr, - arguments_count, + out_result_addr, + *out_size, self.loader_id, - true, + true ), result ); - // Get arguments - let mut arg_iter = args.iter(); - let arg_meta = arg_iter.next().unwrap(); - let mut byte_count = arg_meta.len(); - let mut arg1 = BigNum::from_slice(question_mark!( - translate_slice::( + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, + out_negative_addr, self.loader_id, true ), result - )) - .unwrap(); - let arg_meta = arg_iter.next().unwrap(); - byte_count += arg_meta.len(); - let mut arg2 = BigNum::from_slice(question_mark!( - translate_slice::( + ); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_sub(&buffer[0], &buffer[1]) { + Ok(_) => { + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberAddError.into()), + } + } + } + } +} +/// Subtract BigNums +struct SyscallBigNumMul<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumMul<'a> { + fn call( + &mut self, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let my_func = String::from("sol_bignum_mul"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) + } + true => { + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, + out_result_addr, + *out_size, self.loader_id, true ), result - )) - .unwrap(); - // Get the negative flags - let arg_meta = arg_iter.next().unwrap(); - let neg_flag_array = question_mark!( - translate_slice::( + ); + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, + out_negative_addr, self.loader_id, true ), result ); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_mul(&buffer[0], &buffer[1], &mut BigNumContext::new().unwrap()) { + Ok(_) => { + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberAddError.into()), + } + } + } + } +} +struct SyscallBigNumDiv<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumDiv<'a> { + fn call( + &mut self, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let my_func = String::from("sol_bignum_div"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) + } + true => { + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); // Get out size and out vector let out_size = question_mark!( translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), @@ -1566,29 +1731,20 @@ impl<'a> SyscallObject for SyscallBigNumSub<'a> { ), result ); - // Compute costs - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(byte_count as f64)), - result - ); - arg1.set_negative(neg_flag_array[0] == 1); - arg2.set_negative(neg_flag_array[1] == 1); - // Execute function - let mut bn_result = BigNum::new().unwrap(); - match bn_result.checked_sub(&arg1, &arg2) { - Ok(_) => { - // Get out_size pointer and negative flag pointer - // Get negative flag pointer - let is_negative = question_mark!( - translate_type_mut::( - memory_mapping, - out_negative_addr, - self.loader_id, - true - ), - result - ); + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.checked_div(&buffer[0], &buffer[1], &mut BigNumContext::new().unwrap()) { + Ok(_) => { let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; if big_number_len > *out_size { @@ -1611,19 +1767,18 @@ impl<'a> SyscallObject for SyscallBigNumSub<'a> { *result = Ok(0) } } - Err(_) => *result = Err(SyscallError::BigNumberSubError.into()), + Err(_) => *result = Err(SyscallError::BigNumberAddError.into()), } } } } } -/// Subtract BigNums -struct SyscallBigNumMul<'a> { +struct SyscallBigNumSqr<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallBigNumMul<'a> { +impl<'a> SyscallObject for SyscallBigNumSqr<'a> { fn call( &mut self, arguments_addr: u64, @@ -1634,11 +1789,11 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let my_func = String::from("sol_bignum_mul"); - match arguments_count == 3 { + let my_func = String::from("sol_bignum_sqr"); + match arguments_count == 2 { false => { *result = - Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) + Err(SyscallError::BigNumberArgError(my_func, 1u64, arguments_count - 1).into()) } true => { let args = question_mark!( @@ -1654,7 +1809,7 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { // Get arguments let mut arg_iter = args.iter(); let arg_meta = arg_iter.next().unwrap(); - let mut byte_count = arg_meta.len(); + let byte_count = arg_meta.len(); let mut arg1 = BigNum::from_slice(question_mark!( translate_slice::( memory_mapping, @@ -1666,19 +1821,6 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { result )) .unwrap(); - let arg_meta = arg_iter.next().unwrap(); - byte_count += arg_meta.len(); - let mut arg2 = BigNum::from_slice(question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), - result - )) - .unwrap(); // Get the negative flags let arg_meta = arg_iter.next().unwrap(); let neg_flag_array = question_mark!( @@ -1713,10 +1855,9 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { result ); arg1.set_negative(neg_flag_array[0] == 1); - arg2.set_negative(neg_flag_array[1] == 1); // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.checked_mul(&arg1, &arg2, &mut BigNumContext::new().unwrap()) { + match bn_result.sqr(&arg1, &mut BigNumContext::new().unwrap()) { Ok(_) => { // Get out_size pointer and negative flag pointer // Get negative flag pointer @@ -1751,18 +1892,18 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { *result = Ok(0) } } - Err(_) => *result = Err(SyscallError::BigNumberMulError.into()), + Err(_) => *result = Err(SyscallError::BigNumberSqrError.into()), } } } } } -struct SyscallBigNumDiv<'a> { +struct SyscallBigNumExp<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallBigNumDiv<'a> { +impl<'a> SyscallObject for SyscallBigNumExp<'a> { fn call( &mut self, arguments_addr: u64, @@ -1773,7 +1914,7 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let my_func = String::from("sol_bignum_div"); + let my_func = String::from("sol_bignum_exp"); match arguments_count == 3 { false => { *result = @@ -1855,7 +1996,7 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { arg2.set_negative(neg_flag_array[1] == 1); // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.checked_div(&arg1, &arg2, &mut BigNumContext::new().unwrap()) { + match bn_result.exp(&arg1, &arg2, &mut BigNumContext::new().unwrap()) { Ok(_) => { // Get out_size pointer and negative flag pointer // Get negative flag pointer @@ -1890,112 +2031,12 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { *result = Ok(0) } } - Err(_) => *result = Err(SyscallError::BigNumberDivError.into()), + Err(_) => *result = Err(SyscallError::BigNumberExpError.into()), } } } } } -struct SyscallBigNumExp<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumExp<'a> { - fn call( - &mut self, - self_addr: u64, - exponent_addr: u64, - result_exp_addr: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let exp_ptr = question_mark!( - translate_type::(memory_mapping, exponent_addr, self.loader_id, true), - result - ); - let result_exp_address = question_mark!( - translate_type_mut::(memory_mapping, result_exp_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let exp_bn = unsafe { &*(*exp_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + exp_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - - let mut result_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::exp( - &mut *result_bn, - self_bn, - exp_bn, - &mut BigNumContext::new().unwrap(), - ) { - Ok(_) => { - let rwptr = Box::into_raw(result_bn); - let exp_ptr = rwptr as u64; - *result_exp_address = exp_ptr; - *result = Ok(0) - } - _ => *result = Err(SyscallError::BigNumberExpError.into()), - }; - } -} -struct SyscallBigNumSqr<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumSqr<'a> { - fn call( - &mut self, - self_addr: u64, - result_sqr_addr: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let result_sqr_address = question_mark!( - translate_type_mut::(memory_mapping, result_sqr_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let bytes = self_bn.num_bytes() as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - - let mut result_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::sqr(&mut *result_bn, self_bn, &mut BigNumContext::new().unwrap()) { - Ok(_) => { - let rwptr = Box::into_raw(result_bn); - let exp_ptr = rwptr as u64; - *result_sqr_address = exp_ptr; - *result = Ok(0) - } - _ => *result = Err(SyscallError::BigNumberSqrError.into()), - }; - } -} /// BIGNUM sol_bignum_mod_exp struct SyscallBigNumModExp<'a> { @@ -2254,13 +2295,13 @@ impl<'a> SyscallObject for SyscallBigNumModInv<'a> { // } /// Log BigNum values -struct SyscallLogBigNum<'a> { +struct SyscallBigNumLog<'a> { cost: u64, compute_meter: Rc>, logger: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallLogBigNum<'a> { +impl<'a> SyscallObject for SyscallBigNumLog<'a> { fn call( &mut self, bn_addr: u64, @@ -5002,34 +5043,71 @@ mod tests { unsafe { result_vec.set_len(out_size as usize) }; assert_eq!(result_vec, vec![30]); } - #[test] - fn test_syscall_bignum_exp() { - let mut exp = 0u64; - let exp_addr = &mut exp as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(4); - let bn_3_ptr = new_u32_bignum(2); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_addr = &bn_3_ptr as *const _ as u64; + fn test_syscall_bignum_sqr() { + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + + let bn_arg1 = BigNum::from_u32(300).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() * 2); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 2048, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: exp_addr, + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -5038,39 +5116,99 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumExp { + let mut syscall = SyscallBigNumSqr { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 2, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(exp as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(16).unwrap()); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![1, 95, 144]); } #[test] - fn test_syscall_bignum_sqr() { - let mut sqr = 0u64; - let sqr_addr = &mut sqr as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(4); - let bn_2_addr = &bn_2_ptr as *const _ as u64; + fn test_syscall_bignum_exp() { + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(8).unwrap(); + let bn_arg2 = BigNum::from_u32(2).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: sqr_addr, + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -5079,21 +5217,23 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumSqr { + let mut syscall = SyscallBigNumExp { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 96, 0, 0, 0, &memory_mapping, &mut result); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let braw: &BigNum = unsafe { &*(sqr as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(16).unwrap()); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![64]); } + #[test] fn test_syscall_bignum_mod_sqr() { let mut mod_sqr = 0u64; diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 8b8f97d1aec6b9..7dc5e5cfe62df3 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -489,129 +489,150 @@ static uint64_t sol_bignum_from_dec_str( /** * BigNum sol_bignum_add * Performs add and returns bignum for sum - * @param self_ptr self bignum address - * @param rhs_ptr bignum address to add with self - * @param sum_ptr object address of resulting sum - + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_add( - const uint64_t *self_ptr, - const uint64_t *rhs_ptr, - const uint64_t *sum_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_sub * Performs subtraction and returns bignum for difference - * @param self_ptr self bignum address - * @param rhs_ptr bignum address number to sub from self - * @param diff_ptr object address of resulting difference - + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_sub( - const uint64_t *self_ptr, - const uint64_t *rhs_ptr, - const uint64_t *diff_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_mul * Performs multiplication and returns bignum for product - * @param self_ptr self bignum address - * @param rhs_ptr bignum address number to multiple self by - * @param product_ptr object address of resulting product - + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_mul( - const uint64_t *self_ptr, - const uint64_t *rhs_ptr, - const uint64_t *product_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_div * Performs division and returns bignum for product - * @param self_ptr self bignum address - * @param rhs_ptr bignum address number to divide self by - * @param quotient_ptr object address of resulting quotient + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_div( - const uint64_t *self_ptr, - const uint64_t *rhs_ptr, - const uint64_t *quotient_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_exp - * @param self_ptr self bignum address - * @param exponent_ptr exponent bignum address - * @param exp_res_ptr object address of resulting self^exp + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_exp( - const uint64_t *self_ptr, - const uint64_t *self_exponent_ptr, - const uint64_t *exp_res_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_sqr - * @param self_ptr self bignum address - * @param uint64_t *sqr_res_ptr + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ + static uint64_t sol_bignum_sqr( - const uint64_t *self_ptr, - const uint64_t *sqr_res_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_mod_mul * Performs (base * multiplier) % modulus and updates self_ptr BigNum - * @param self_ptr base bignum address (i.e. self -- read) - * @param multiplier_ptr - The number that self_ptr is multiplied by - * @param modulus_ptr the modulus applied to the product of self*multiplier - * @param mod_exp_ptr object address of resulting BigNum + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_mod_mul( - const uint64_t *self_ptr, - const uint64_t *multiplier_ptr, - const uint64_t *modulus_ptr, - const uint64_t *mod_mul_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** * BigNum sol_bignum_mod_inverse - * Performs (base * multiplier) % modulus and updates self_ptr BigNum - * @param self_ptr base bignum address (i.e. self -- read) - * @param modulus_ptr the modulus applied to the product of self*multiplier - * @param mod_exp_ptr object address of resulting BigNum + * Performs (base * multiplier) % modulus + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_mod_inverse( - const uint64_t *self_ptr, - const uint64_t *modulus_ptr, - const uint64_t *mod_mul_ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); - /** * BigNum sol_bignum_mod_exp - * Performs base^exponent % modulus and updates self_ptr BigNum - * @param mod_exp_ptr object address of resulting BigNum - * @param self_ptr base bignum address (i.e. self -- read) - * @param exponent_ptr exponent bignum address (read) - * @param modulus_ptr modulus bignum address (read) + * Performs base^exponent % modulus + * @param args_ptr pointer to array of arguments + * @param arg_count count of arrays in args_ptr + * @param result_ptr address of buffer for result, + * @param negative_ptr address to store if result is negative (true) + * @param outsize_ptr on in, contains size of result_ptr, on out it num bytes copied */ static uint64_t sol_bignum_mod_exp( - const uint64_t *mod_exp_ptr, - const uint64_t *self_ptr, - const uint64_t *base_ptr, - const uint64_t *exponent_ptr, - const uint64_t *modulus_ptr -); - -/** - * BigNum drop - * - * @param ptr object address created with sol_bignum_new - */ -static uint64_t sol_bignum_drop( - const uint64_t *ptr + const uint64_t *args_ptr, + const uint64_t arg_count, + const uint64_t *result_ptr, + const uint64_t *negative_ptr, + const uint64_t *outsize_ptr ); /** diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index d0a2e28d639d7a..892a9a6b123860 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -339,6 +339,106 @@ impl BigNumber { } } + /// Square BigNumbers + pub fn sqr(&self) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res.sqr(&my_num, &mut BigNumContext::new().unwrap()).unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_sqr( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8]; + let arg_array = vec![self.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = self.value.len()*2; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + + unsafe { + sol_bignum_sqr( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } + + /// Raise BigNumber to exponent + pub fn exp(&self, exponent: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&exponent.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res.exp(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()).unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_exp( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, exponent.negative as u8]; + let arg_array = vec![self.to_bytes(), exponent.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), exponent.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + unsafe { + sol_bignum_exp( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } + // /// Mod multiplier (self * multiplier) % modulus // pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { // #[cfg(not(target_arch = "bpf"))] @@ -417,34 +517,6 @@ impl BigNumber { // } // } - - // /// Square BigNumbers - // pub fn sqr(&self) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // BigNumRef::sqr(&mut *bbox, my_raw, &mut BigNumContext::new().unwrap()).unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_sqr(self_ptr: *const u64, modulus_ptr: *const u64) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_sqr( - // &self.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } - // /// Square BigNumbers // pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { // #[cfg(not(target_arch = "bpf"))] @@ -484,45 +556,6 @@ impl BigNumber { // } // } - // /// Square BigNumbers - // pub fn exp(&self, exponent: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // BigNumRef::exp( - // &mut *bbox, - // my_raw, - // exponent_ptr, - // &mut BigNumContext::new().unwrap(), - // ) - // .unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_exp( - // self_ptr: *const u64, - // exponent_ptr: *const u64, - // bignum_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_exp( - // &self.0 as *const _ as *const u64, - // &exponent.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } - // /// Compute modular exponentiation (self ^ rhs mod order) and return the result // pub fn mod_exp(&self, exponent: &BigNumber, modulus: &BigNumber) -> Self { // #[cfg(not(target_arch = "bpf"))] @@ -573,9 +606,9 @@ impl BigNumber { // #[cfg(target_arch = "bpf")] // { // extern "C" { - // fn sol_log_bignum(bignum_addr: *const u64) -> u64; + // fn sol_bignum_log(bignum_addr: *const u64) -> u64; // } - // unsafe { sol_log_bignum(&self.0 as *const _ as *const u64) }; + // unsafe { sol_bignum_log(&self.0 as *const _ as *const u64) }; // } // } } @@ -628,44 +661,6 @@ impl fmt::Display for BigNumber { } } -// impl AsRef for BigNumber { -// fn as_ref(&self) -> &u64 { -// &self.0 -// } -// } - -// impl From for BigNumber { -// fn from(ptr: u64) -> Self { -// Self(ptr) -// } -// } - -/// Drop - removes the underlying BigNum -// impl Drop for BigNumber { -// fn drop(&mut self) { -// #[cfg(not(target_arch = "bpf"))] -// { -// use openssl::bn::BigNum; -// drop(unsafe { Box::from_raw(self.0 as *mut BigNum) }); -// } -// #[cfg(target_arch = "bpf")] -// { -// extern "C" { -// fn sol_bignum_drop(bignum_ptr: *mut u64) -> u64; -// } -// unsafe { -// sol_bignum_drop(&mut self.0 as *mut _ as *mut u64); -// } -// } -// } -// } -/// Clone - creates a new BigNumber replicating itself -// impl Clone for BigNumber { -// fn clone(&self) -> Self { -// BigNumber::from_bytes(self.to_bytes().as_slice()) -// } -// } - #[cfg(test)] mod tests { use super::*; diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index 45d817f1dae38e..e720c0e1f1645f 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -165,22 +165,14 @@ pub struct BpfComputeBudget { pub cpi_bytes_per_unit: u64, /// Base number of compute units consumed to get a sysvar pub sysvar_base_cost: u64, - /// Base number of compute units consumed to call BIGNUM NEW - // pub bignum_new_base_cost: u64, - /// Base number of compute units consumed to call BigNum size in bytes query - // pub bignum_size_base_cost: u64, /// Base number of compute units consumed to call BigNum new from u32 value pub bignum_from_u32_base_cost: u64, /// Base number of compute units consumed to call BigNum new from a decimal string pub bignum_from_dec_str_base_cost: u64, - /// Base number of compute units consumed to extract big endian byte array from BigNumb - // pub bignum_to_bytes_base_cost: u64, - /// Base number of compute units consumed to drop/dealloc BigNum - // pub bignum_drop_base_cost: u64, /// Incremental number of units consumed to drop/dealloc BigNum (based on bytes) pub bignum_mod_exp_base_cost: u64, /// Number of compute units consumed by logging a `BigNum` - pub log_bignum_cost: u64, + pub bignum_log_cost: u64, /// Number of compute units consumed by BigNum add pub bignum_add_cost: u64, /// Number of compute units consumed by BigNum subtract @@ -222,14 +214,10 @@ impl BpfComputeBudget { max_cpi_instruction_size: 1280, // IPv6 Min MTU size cpi_bytes_per_unit: 250, // ~50MB at 200,000 units sysvar_base_cost: 100, - // bignum_new_base_cost: 100, - // bignum_size_base_cost: 100, - // bignum_drop_base_cost: 100, bignum_from_u32_base_cost: 100, bignum_from_dec_str_base_cost: 100, - // bignum_to_bytes_base_cost: 100, bignum_mod_exp_base_cost: 100, - log_bignum_cost: 100, + bignum_log_cost: 100, bignum_add_cost: 15, bignum_sub_cost: 15, bignum_mul_cost: 30, From 5e2d3978c53e338f797e8a7628f979ca58400bf4 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:06:19 -0400 Subject: [PATCH 21/45] BigNumber complete conversion to vector from Box --- programs/bpf/rust/bignum/src/lib.rs | 38 +- programs/bpf_loader/src/syscalls.rs | 1571 ++++++++++++++++----------- sdk/program/src/bignum.rs | 438 +++++--- 3 files changed, 1244 insertions(+), 803 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 62e7ad178bda0d..bf0974218cf9ca 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -1,7 +1,7 @@ //! @brief BigNumber Syscall test extern crate solana_program; -use solana_program::{bignum::BigNumber, custom_panic_default, msg}; +use solana_program::{bignum::BigNumber, custom_panic_default, log::sol_log_compute_units, msg}; const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ @@ -29,19 +29,13 @@ const NEG_LONG_DEC_STRING: &str = fn test_constructors() { msg!("BigNumber constructors"); let base_bn_0 = BigNumber::new(); - msg!("base_bn_0 {}", base_bn_0); let default_0 = BigNumber::default(); - msg!("default_0 {}", default_0); let new_bn_0 = BigNumber::from_u32(0); - msg!("new_bn_0 {}", new_bn_0); let max_bn_u32 = BigNumber::from_u32(u32::MAX); - msg!("max_bn_u32 {:?}", max_bn_u32.to_bytes()); let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); assert_eq!(bn_from_dec.is_negative(), false); - msg!("Positive from_dec_str {}", bn_from_dec.is_negative() != true); let bn_from_dec = BigNumber::from_dec_str(NEG_LONG_DEC_STRING); assert!(bn_from_dec.is_negative()); - msg!("Negative from_dec_str {}", bn_from_dec.is_negative()); } /// BigNumber simple number and simple maths @@ -50,29 +44,43 @@ fn test_basic_maths() { let bn_5 = BigNumber::from_u32(5); let bn_258 = BigNumber::from_u32(258); let added = bn_5.add(&bn_258); - msg!("add bn vec {:?}", added.to_bytes()); assert_eq!(added.to_bytes(), [1, 7]); let subed = bn_5.sub(&bn_258); - msg!("sub bn vec {:?}", subed.to_bytes()); assert_eq!(subed.to_bytes(), vec![253]); let muled = bn_5.mul(&bn_5); - msg!("mul bn vec {:?}", muled.to_bytes()); assert_eq!(muled.to_bytes(), vec![25]); let bn_300 = BigNumber::from_u32(300); let bn_10 = BigNumber::from_u32(10); let dived = bn_300.div(&bn_10); - msg!("div bn vec {:?}", dived.to_bytes()); assert_eq!(dived.to_bytes(), vec![30]); } /// BigNumber bigger numbers and complex maths fn test_complex_maths() { msg!("BigNumber Complex Maths"); - let bn_arg1 = BigNumber::from_u32(8); - let bn_arg2 = BigNumber::from_u32(2); - let exp_res = bn_arg1.exp(&bn_arg2); - msg!("exp vec {:?}", exp_res.to_bytes()); + let bn_arg1 = BigNumber::from_u32(300); + let sqr_res = bn_arg1.sqr(); + assert_eq!(sqr_res.to_bytes(), vec![1, 95, 144]); + let bn_arg2 = BigNumber::from_u32(8); + let bn_arg3 = BigNumber::from_u32(2); + let exp_res = bn_arg2.exp(&bn_arg3); assert_eq!(exp_res.to_bytes(), vec![64]); + let bn_arg1 = BigNumber::from_u32(300); + let bn_arg2 = BigNumber::from_u32(11); + let mod_sqr = bn_arg1.mod_sqr(&bn_arg2); + assert_eq!(mod_sqr.to_bytes(), vec![9]); + let bn_arg1 = BigNumber::from_u32(300); + let bn_arg2 = BigNumber::from_u32(11); + let bn_arg3 = BigNumber::from_u32(7); + let mod_exp = bn_arg1.mod_exp(&bn_arg2, &bn_arg3); + assert_eq!(mod_exp.to_bytes(), vec![6]); + let mod_mul = bn_arg1.mod_mul(&bn_arg2, &bn_arg3); + assert_eq!(mod_mul.to_bytes(), vec![3]); + let bn_arg1 = BigNumber::from_u32(415); + let bn_arg2 = BigNumber::from_u32(7); + let mod_inv = bn_arg1.mod_inv(&bn_arg2); + assert_eq!(mod_inv.to_bytes(), vec![4]); + mod_inv.log(); } #[no_mangle] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d46e13e77d6013..d73f0b645b9e98 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -356,14 +356,6 @@ pub fn bind_syscall_context_objects<'a>( }), None, )?; - // vm.bind_syscall_context_object( - // Box::new(SyscallBigNumDrop { - // cost: bpf_compute_budget.bignum_drop_base_cost, - // compute_meter: invoke_context.get_compute_meter(), - // loader_id, - // }), - // None, - // )?; vm.bind_syscall_context_object( Box::new(SyscallBigNumLog { @@ -1353,7 +1345,7 @@ fn translate_bignum_args( ); *bytes = 0; // BigNums are all but ast - for arg in args[0..args.len() - 1 ].iter() { + for arg in args[0..args.len() - 1].iter() { buffers.push( BigNum::from_slice(question_mark!( translate_slice::( @@ -1364,13 +1356,20 @@ fn translate_bignum_args( true ), result - )).unwrap() + )) + .unwrap(), ) } // Negative flags are last let last = args.last().unwrap(); let neg_flags = question_mark!( - translate_slice::(memory_mapping, last.as_ptr() as u64, last.len() as u64, loader_id, true), + translate_slice::( + memory_mapping, + last.as_ptr() as u64, + last.len() as u64, + loader_id, + true + ), result ); // Get byte count and set negative flag @@ -1414,7 +1413,7 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { &mut buffer, &mut bytes, &memory_mapping, - result + result, ); // Compute costs question_mark!( @@ -1513,7 +1512,7 @@ impl<'a> SyscallObject for SyscallBigNumSub<'a> { &mut buffer, &mut bytes, &memory_mapping, - result + result, ); // Compute costs question_mark!( @@ -1611,7 +1610,7 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { &mut buffer, &mut bytes, &memory_mapping, - result + result, ); // Compute costs question_mark!( @@ -1646,7 +1645,11 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { ); // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.checked_mul(&buffer[0], &buffer[1], &mut BigNumContext::new().unwrap()) { + match bn_result.checked_mul( + &buffer[0], + &buffer[1], + &mut BigNumContext::new().unwrap(), + ) { Ok(_) => { let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; @@ -1708,7 +1711,7 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { &mut buffer, &mut bytes, &memory_mapping, - result + result, ); // Compute costs question_mark!( @@ -1743,7 +1746,11 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { ); // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.checked_div(&buffer[0], &buffer[1], &mut BigNumContext::new().unwrap()) { + match bn_result.checked_div( + &buffer[0], + &buffer[1], + &mut BigNumContext::new().unwrap(), + ) { Ok(_) => { let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; @@ -1796,43 +1803,24 @@ impl<'a> SyscallObject for SyscallBigNumSqr<'a> { Err(SyscallError::BigNumberArgError(my_func, 1u64, arguments_count - 1).into()) } true => { - let args = question_mark!( - translate_slice::<&[u8]>( - memory_mapping, - arguments_addr, - arguments_count, - self.loader_id, - true, - ), - result + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result, ); - // Get arguments - let mut arg_iter = args.iter(); - let arg_meta = arg_iter.next().unwrap(); - let byte_count = arg_meta.len(); - let mut arg1 = BigNum::from_slice(question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), - result - )) - .unwrap(); - // Get the negative flags - let arg_meta = arg_iter.next().unwrap(); - let neg_flag_array = question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), result ); + // Get out size and out vector let out_size = question_mark!( translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), @@ -1848,28 +1836,20 @@ impl<'a> SyscallObject for SyscallBigNumSqr<'a> { ), result ); - // Compute costs - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + // Get negative flag pointer + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), result ); - arg1.set_negative(neg_flag_array[0] == 1); // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.sqr(&arg1, &mut BigNumContext::new().unwrap()) { + match bn_result.sqr(&buffer[0], &mut BigNumContext::new().unwrap()) { Ok(_) => { - // Get out_size pointer and negative flag pointer - // Get negative flag pointer - let is_negative = question_mark!( - translate_type_mut::( - memory_mapping, - out_negative_addr, - self.loader_id, - true - ), - result - ); let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; if big_number_len > *out_size { @@ -1918,59 +1898,27 @@ impl<'a> SyscallObject for SyscallBigNumExp<'a> { match arguments_count == 3 { false => { *result = - Err(SyscallError::BigNumberArgError(my_func, 2u64, arguments_count - 1).into()) + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) } true => { - let args = question_mark!( - translate_slice::<&[u8]>( - memory_mapping, - arguments_addr, - arguments_count, - self.loader_id, - true, - ), - result + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result, ); - // Get arguments - let mut arg_iter = args.iter(); - let arg_meta = arg_iter.next().unwrap(); - let mut byte_count = arg_meta.len(); - let mut arg1 = BigNum::from_slice(question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), - result - )) - .unwrap(); - let arg_meta = arg_iter.next().unwrap(); - byte_count += arg_meta.len(); - let mut arg2 = BigNum::from_slice(question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), - result - )) - .unwrap(); - // Get the negative flags - let arg_meta = arg_iter.next().unwrap(); - let neg_flag_array = question_mark!( - translate_slice::( - memory_mapping, - arg_meta.as_ptr() as u64, - arg_meta.len() as u64, - self.loader_id, - true - ), + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), result ); + // Get out size and out vector let out_size = question_mark!( translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), @@ -1986,29 +1934,22 @@ impl<'a> SyscallObject for SyscallBigNumExp<'a> { ), result ); - // Compute costs - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(byte_count as f64)), + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), result ); - arg1.set_negative(neg_flag_array[0] == 1); - arg2.set_negative(neg_flag_array[1] == 1); + // Execute function let mut bn_result = BigNum::new().unwrap(); - match bn_result.exp(&arg1, &arg2, &mut BigNumContext::new().unwrap()) { + match bn_result.exp(&buffer[0], &buffer[1], &mut BigNumContext::new().unwrap()) { Ok(_) => { // Get out_size pointer and negative flag pointer // Get negative flag pointer - let is_negative = question_mark!( - translate_type_mut::( - memory_mapping, - out_negative_addr, - self.loader_id, - true - ), - result - ); let big_number_bytes = bn_result.as_ref().to_vec(); let big_number_len = big_number_bytes.len() as u64; if big_number_len > *out_size { @@ -2038,63 +1979,6 @@ impl<'a> SyscallObject for SyscallBigNumExp<'a> { } } -/// BIGNUM sol_bignum_mod_exp -struct SyscallBigNumModExp<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, -} -impl<'a> SyscallObject for SyscallBigNumModExp<'a> { - fn call( - &mut self, - mod_exp_addr: u64, - self_bn_addr: u64, - exponent_bn_addr: u64, - modulus_bn_addr: u64, - _arg5: u64, - memory_mapping: &MemoryMapping, - result: &mut Result>, - ) { - let mod_bignum_address = question_mark!( - translate_type_mut::(memory_mapping, mod_exp_addr, self.loader_id, true), - result - ); - let self_bignum_address = question_mark!( - translate_type::(memory_mapping, self_bn_addr, self.loader_id, true), - result - ); - let exponent_bignum_address = question_mark!( - translate_type::(memory_mapping, exponent_bn_addr, self.loader_id, true), - result - ); - let modulus_bignum_address = question_mark!( - translate_type::(memory_mapping, modulus_bn_addr, self.loader_id, true), - result - ); - - let mut mod_exp_bn = Box::new(BigNum::new().unwrap()); - let bn_self = unsafe { &*(*self_bignum_address as *const BigNum) }; - let bn_exponent = unsafe { &*(*exponent_bignum_address as *const BigNum) }.as_ref(); - let bn_modulus = (unsafe { &*(*modulus_bignum_address as *const BigNum) }).as_ref(); - let bytes = (bn_self.num_bytes() + bn_exponent.num_bytes() + bn_modulus.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); - let ctx = &mut BigNumContext::new().unwrap(); - match mod_exp_bn.mod_exp(bn_self, bn_exponent, bn_modulus, ctx) { - Ok(()) => { - let rwptr = Box::into_raw(mod_exp_bn); - let mod_exp_ptr = rwptr as u64; - *mod_bignum_address = mod_exp_ptr; - *result = Ok(0) - } - Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), - } - } -} - struct SyscallBigNumModSqr<'a> { cost: u64, compute_meter: Rc>, @@ -2103,197 +1987,417 @@ struct SyscallBigNumModSqr<'a> { impl<'a> SyscallObject for SyscallBigNumModSqr<'a> { fn call( &mut self, - self_addr: u64, - mod_addr: u64, - result_mod_sqr_addr: u64, - _arg4: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let mod_ptr = question_mark!( - translate_type::(memory_mapping, mod_addr, self.loader_id, true), - result - ); - let result_mod_sqr_address = question_mark!( - translate_type_mut::(memory_mapping, result_mod_sqr_addr, self.loader_id, true), - result - ); + let my_func = String::from("sol_bignum_mod_sqr"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) + } + true => { + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result, + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let mod_bn = unsafe { &*(*mod_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + mod_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); - let mut result_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::mod_sqr( - &mut *result_bn, - self_bn, - mod_bn, - &mut BigNumContext::new().unwrap(), - ) { - Ok(_) => { - let rwptr = Box::into_raw(result_bn); - let mod_sqr_ptr = rwptr as u64; - *result_mod_sqr_address = mod_sqr_ptr; - *result = Ok(0) + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.mod_sqr(&buffer[0], &buffer[1], &mut BigNumContext::new().unwrap()) + { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberModSqrError.into()), + } } - _ => *result = Err(SyscallError::BigNumberModSqrError.into()), - }; + } } } -struct SyscallBigNumModMul<'a> { +/// BIGNUM sol_bignum_mod_exp +struct SyscallBigNumModExp<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallBigNumModMul<'a> { +impl<'a> SyscallObject for SyscallBigNumModExp<'a> { fn call( &mut self, - self_addr: u64, - mul_addr: u64, - mod_addr: u64, - result_mod_mul_addr: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let mul_ptr = question_mark!( - translate_type::(memory_mapping, mul_addr, self.loader_id, true), - result - ); - let mod_ptr = question_mark!( - translate_type::(memory_mapping, mod_addr, self.loader_id, true), - result - ); - let result_mod_mul_address = question_mark!( - translate_type_mut::(memory_mapping, result_mod_mul_addr, self.loader_id, true), - result - ); - - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let mul_bn = unsafe { &*(*mul_ptr as *mut BigNum) }; - let mod_bn = unsafe { &*(*mod_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + mul_bn.num_bytes() + mod_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); + let my_func = String::from("sol_bignum_mod_exp"); + match arguments_count == 4 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) + } + true => { + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result, + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); - let mut result_bn = Box::new(BigNum::new().unwrap()); - match BigNumRef::mod_mul( - &mut *result_bn, - self_bn, - mul_bn, - mod_bn, - &mut BigNumContext::new().unwrap(), - ) { - Ok(_) => { - let rwptr = Box::into_raw(result_bn); - let mod_sqr_ptr = rwptr as u64; - *result_mod_mul_address = mod_sqr_ptr; - *result = Ok(0) + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); + + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.mod_exp( + &buffer[0], + &buffer[1], + &buffer[2], + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), + } } - _ => *result = Err(SyscallError::BigNumberModSqrError.into()), - }; + } } } -struct SyscallBigNumModInv<'a> { +struct SyscallBigNumModMul<'a> { cost: u64, compute_meter: Rc>, loader_id: &'a Pubkey, } -impl<'a> SyscallObject for SyscallBigNumModInv<'a> { +impl<'a> SyscallObject for SyscallBigNumModMul<'a> { fn call( &mut self, - self_addr: u64, - mod_addr: u64, - result_mod_sqr_addr: u64, - _arg4: u64, - _arg5: u64, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, memory_mapping: &MemoryMapping, result: &mut Result>, ) { - let self_ptr = question_mark!( - translate_type::(memory_mapping, self_addr, self.loader_id, true), - result - ); - let mod_ptr = question_mark!( - translate_type::(memory_mapping, mod_addr, self.loader_id, true), - result - ); - let result_mod_sqr_address = question_mark!( - translate_type_mut::(memory_mapping, result_mod_sqr_addr, self.loader_id, true), - result - ); + let my_func = String::from("sol_bignum_mod_mul"); + match arguments_count == 4 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) + } + true => { + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result, + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); - let self_bn = unsafe { &*(*self_ptr as *mut BigNum) }; - let mod_bn = unsafe { &*(*mod_ptr as *mut BigNum) }; - let bytes = (self_bn.num_bytes() + mod_bn.num_bytes()) as f64; - question_mark!( - self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), - result - ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); - // let mut result_bn = Box::new(BigNum::new().unwrap()); - let mut result_bn = BigNum::new().unwrap(); - match result_bn.mod_inverse(&*self_bn, &*mod_bn, &mut BigNumContext::new().unwrap()) { - // match BigNumRef::mod_inverse(&mut result_bn, self_bn, mod_bn, &mut BigNumContext::new().unwrap()) { - Ok(_) => { - let rwptr = Box::into_raw(Box::new(result_bn)); - let mod_sqr_ptr = rwptr as u64; - *result_mod_sqr_address = mod_sqr_ptr; - *result = Ok(0) + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.mod_mul( + &buffer[0], + &buffer[1], + &buffer[2], + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), + } } - Err(_e) => *result = Err(SyscallError::BigNumberModInvError.into()), - }; + } } } -/// BIGNUM sol_bignum_drop -// struct SyscallBigNumDrop<'a> { -// cost: u64, -// compute_meter: Rc>, -// loader_id: &'a Pubkey, -// } -// impl<'a> SyscallObject for SyscallBigNumDrop<'a> { -// fn call( -// &mut self, -// bn_addr: u64, -// _arg2: u64, -// _arg3: u64, -// _arg4: u64, -// _arg5: u64, -// memory_mapping: &MemoryMapping, -// result: &mut Result>, -// ) { -// question_mark!(self.compute_meter.consume(self.cost), result); -// let big_number = question_mark!( -// translate_type_mut::(memory_mapping, bn_addr, self.loader_id, true), -// result -// ); -// drop(unsafe { Box::from_raw(*big_number as *mut BigNum) }); -// *big_number = 0u64; -// *result = Ok(0) -// } -// } +struct SyscallBigNumModInv<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallBigNumModInv<'a> { + fn call( + &mut self, + arguments_addr: u64, + arguments_count: u64, + out_result_addr: u64, + out_negative_addr: u64, + out_size_addr: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let my_func = String::from("sol_bignum_mod_mul"); + match arguments_count == 3 { + false => { + *result = + Err(SyscallError::BigNumberArgError(my_func, 3u64, arguments_count).into()) + } + true => { + let mut buffer = Vec::::new(); + let mut bytes = 0u64; + translate_bignum_args( + arguments_addr, + arguments_count, + self.loader_id, + &mut buffer, + &mut bytes, + &memory_mapping, + result, + ); + // Compute costs + question_mark!( + self.compute_meter + .consume(self.cost + calc_bignum_cost!(bytes as f64)), + result + ); + // Get out size and out vector + let out_size = question_mark!( + translate_type_mut::(memory_mapping, out_size_addr, self.loader_id, true), + result + ); + let bignum_result = question_mark!( + translate_slice_mut::( + memory_mapping, + out_result_addr, + *out_size, + self.loader_id, + true + ), + result + ); + let is_negative = question_mark!( + translate_type_mut::( + memory_mapping, + out_negative_addr, + self.loader_id, + true + ), + result + ); + + // Execute function + let mut bn_result = BigNum::new().unwrap(); + match bn_result.mod_inverse( + &buffer[0], + &buffer[1], + &mut BigNumContext::new().unwrap(), + ) { + Ok(_) => { + // Get out_size pointer and negative flag pointer + // Get negative flag pointer + let big_number_bytes = bn_result.as_ref().to_vec(); + let big_number_len = big_number_bytes.len() as u64; + if big_number_len > *out_size { + *result = Err(SyscallError::BigNumberToBytesError.into()) + } else { + // Equal (memcpy) + if big_number_len == *out_size { + (*bignum_result).copy_from_slice(&big_number_bytes); + } + // Smaller than our buffer + else { + let mut index = 0; + for byte in big_number_bytes.iter() { + (*bignum_result)[index] = *byte; + index = index + 1; + } + *out_size = index as u64; + } + *is_negative = bn_result.is_negative() as u64; + *result = Ok(0) + } + } + Err(_) => *result = Err(SyscallError::BigNumberModExpError.into()), + } + } + } + } +} /// Log BigNum values struct SyscallBigNumLog<'a> { cost: u64, @@ -2305,7 +2409,7 @@ impl<'a> SyscallObject for SyscallBigNumLog<'a> { fn call( &mut self, bn_addr: u64, - _arg2: u64, + bn_size: u64, _arg3: u64, _arg4: u64, _arg5: u64, @@ -2313,17 +2417,15 @@ impl<'a> SyscallObject for SyscallBigNumLog<'a> { result: &mut Result>, ) { let bignum_ptr = question_mark!( - translate_type::(memory_mapping, bn_addr, self.loader_id, true), + translate_slice::(memory_mapping, bn_addr, bn_size, self.loader_id, true), result ); - let bignum = unsafe { &*(*bignum_ptr as *mut BigNum) }; - let bytes = bignum.num_bytes() as f64; question_mark!( self.compute_meter - .consume(self.cost + calc_bignum_cost!(bytes)), + .consume(self.cost + calc_bignum_cost!(bn_size as f64)), result ); - + let bignum = BigNum::from_slice(bignum_ptr).unwrap(); stable_log::program_log(&self.logger, &bignum.to_string()); *result = Ok(0); } @@ -4464,58 +4566,283 @@ mod tests { .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); - let mut syscall = SyscallBigNumFromU32 { - cost: 100, + Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); + let mut syscall = SyscallBigNumFromU32 { + cost: 100, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call( + 1024, + bignum_size as u64, + val as u64, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); + unsafe { my_buffer.set_len(bignum_size) }; + my_buffer + } + // creates new bignum with bytes array + fn new_dec_str_bignum(string: &str) -> (bool, Vec) { + let dec_str_addr = string.as_ptr() as *const _ as u64; + let dec_str_len = string.len(); + let bytes_buf = vec![0u8; dec_str_len]; + let mut bytes_len = bytes_buf.len(); + let bytes_len_addr = &mut bytes_len as *mut _ as u64; + let mut neg_flag = 0u64; + let neg_flag_addr = &mut neg_flag as *mut _ as u64; + + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: dec_str_addr, + vm_addr: 2048, + len: dec_str_len as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: bytes_buf.as_ptr() as *const _ as u64, + vm_addr: 8196, + len: bytes_len as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: bytes_len_addr, + vm_addr: 96, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); + let mut syscall = SyscallBigNumFromDecStr { + cost: 1, + compute_meter, + loader_id: &bpf_loader::id(), + }; + let mut result: Result> = Ok(0); + syscall.call( + 2048, + dec_str_len as u64, + 8196, + 96, + 8, + &memory_mapping, + &mut result, + ); + result.unwrap(); + (neg_flag != 0, bytes_buf[0..bytes_len].to_vec()) + } + + #[test] + fn test_syscall_bignum_from_u32() { + let bn_new = BigNum::new().unwrap(); + let bn_0 = BigNum::from_u32(0).unwrap(); + println!("bn_new_vec {:?}", bn_new.to_vec()); + println!("bn_0 {:?}", bn_0.to_vec()); + let bn_20 = new_u32_bignum(20u32); + let bn = BigNum::from_u32(20u32).unwrap().to_vec(); + assert_eq!(bn_20, bn); + } + #[test] + fn test_syscall_bignum_from_dec_str() { + let (is_neg, result_vec) = new_dec_str_bignum(LONG_DEC_STRING); + assert!(is_neg == false); + let bns = BigNum::from_dec_str(LONG_DEC_STRING).unwrap(); + let bns_vec = bns.as_ref().to_vec(); + assert_eq!(result_vec, bns_vec); + let (is_neg, result_vec) = new_dec_str_bignum(NEG_LONG_DEC_STRING); + assert!(is_neg); + let bns = BigNum::from_dec_str(NEG_LONG_DEC_STRING).unwrap(); + let bns_vec = bns.as_ref().to_vec(); + assert_eq!(result_vec, bns_vec); + } + + #[test] + fn test_syscall_bignum_add() { + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(5).unwrap(); + let bn_arg2 = BigNum::from_u32(258).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; + let memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion { + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: adds_array.as_ptr() as *const _ as u64, + vm_addr: 96, + len: 48, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flag_addr, + vm_addr: 8, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &DEFAULT_CONFIG, + ) + .unwrap(); + + let compute_meter: Rc> = + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumAdd { + cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call( - 1024, - bignum_size as u64, - val as u64, - 0, - 0, - &memory_mapping, - &mut result, - ); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - unsafe { my_buffer.set_len(bignum_size) }; - my_buffer + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![1, 7]); } - // creates new bignum with bytes array - fn new_dec_str_bignum(string: &str) -> (bool, Vec) { - let dec_str_addr = string.as_ptr() as *const _ as u64; - let dec_str_len = string.len(); - let bytes_buf = vec![0u8; dec_str_len]; - let mut bytes_len = bytes_buf.len(); - let bytes_len_addr = &mut bytes_len as *mut _ as u64; - let mut neg_flag = 0u64; - let neg_flag_addr = &mut neg_flag as *mut _ as u64; + #[test] + fn test_syscall_bignum_sub() { + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(5).unwrap(); + let bn_arg2 = BigNum::from_u32(258).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: dec_str_addr, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: arg2.as_ptr() as *const _ as u64, vm_addr: 2048, - len: dec_str_len as u64, + len: arg2.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bytes_buf.as_ptr() as *const _ as u64, - vm_addr: 8196, - len: bytes_len as u64, + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, vm_gap_shift: 63, is_writable: true, }, MemoryRegion { - host_addr: bytes_len_addr, + host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, - len: std::mem::size_of::() as u64, + len: 48, vm_gap_shift: 63, - is_writable: true, + is_writable: false, }, MemoryRegion { host_addr: neg_flag_addr, @@ -4524,98 +4851,114 @@ mod tests { vm_gap_shift: 63, is_writable: true, }, + MemoryRegion { + host_addr: out_size_addr, + vm_addr: 16, + len: std::mem::size_of::() as u64, + vm_gap_shift: 63, + is_writable: true, + }, ], &DEFAULT_CONFIG, ) .unwrap(); let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { remaining: 400 })); - let mut syscall = SyscallBigNumFromDecStr { + Rc::new(RefCell::new(MockComputeMeter { + remaining: (20 + 20) as u64, + })); + let mut syscall = SyscallBigNumSub { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call( - 2048, - dec_str_len as u64, - 8196, - 96, - 8, - &memory_mapping, - &mut result, - ); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - (neg_flag != 0, bytes_buf[0..bytes_len].to_vec()) - } - - #[test] - fn test_syscall_bignum_from_u32() { - let bn_new = BigNum::new().unwrap(); - let bn_0 = BigNum::from_u32(0).unwrap(); - println!("bn_new_vec {:?}", bn_new.to_vec()); - println!("bn_0 {:?}", bn_0.to_vec()); - let bn_20 = new_u32_bignum(20u32); - let bn = BigNum::from_u32(20u32).unwrap().to_vec(); - assert_eq!(bn_20, bn); - } - #[test] - fn test_syscall_bignum_from_dec_str() { - let (is_neg, result_vec) = new_dec_str_bignum(LONG_DEC_STRING); - assert!(is_neg == false); - let bns = BigNum::from_dec_str(LONG_DEC_STRING).unwrap(); - let bns_vec = bns.as_ref().to_vec(); - assert_eq!(result_vec, bns_vec); - let (is_neg, result_vec) = new_dec_str_bignum(NEG_LONG_DEC_STRING); - assert!(is_neg); - let bns = BigNum::from_dec_str(NEG_LONG_DEC_STRING).unwrap(); - let bns_vec = bns.as_ref().to_vec(); - assert_eq!(result_vec, bns_vec); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![253]); } #[test] - fn test_syscall_bignum_mod_exp() { - let mut bn = 0u64; - let bn_addr = &mut bn as *mut _ as u64; - - let bn_self_ptr = new_u32_bignum(2); - let bn_exponent_ptr = new_u32_bignum(3); - let bn_modulus_ptr = new_u32_bignum(7); - - let bn_self_addr = &bn_self_ptr as *const _ as u64; - let bn_exponent_addr = &bn_exponent_ptr as *const _ as u64; - let bn_modulus_addr = &bn_modulus_ptr as *const _ as u64; + fn test_syscall_bignum_mul() { + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(5).unwrap(); + let bn_arg2 = BigNum::from_u32(5).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), + }; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, vm_gap_shift: 63, is_writable: true, }, MemoryRegion { - host_addr: bn_self_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: adds_array.as_ptr() as *const _ as u64, + vm_addr: 96, + len: 48, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_exponent_addr, - vm_addr: 16, + host_addr: neg_flag_addr, + vm_addr: 8, len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }, MemoryRegion { - host_addr: bn_modulus_addr, - vm_addr: 24, + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }, ], &DEFAULT_CONFIG, @@ -4626,25 +4969,26 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumModExp { + let mut syscall = SyscallBigNumMul { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, 8, 16, 24, 0, &memory_mapping, &mut result); + syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); - let _braw: &BigNum = unsafe { &*(bn as *mut BigNum) }; + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![25]); } #[test] - fn test_syscall_bignum_add() { + fn test_syscall_bignum_div() { struct ArgSlice { pub addr: u64, pub len: usize, - } - let bn_arg1 = BigNum::from_u32(5).unwrap(); - let bn_arg2 = BigNum::from_u32(258).unwrap(); + } + let bn_arg1 = BigNum::from_u32(300).unwrap(); + let bn_arg2 = BigNum::from_u32(10).unwrap(); let arg1 = bn_arg1.as_ref().to_vec(); let arg2 = bn_arg2.as_ref().to_vec(); let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; @@ -4727,7 +5071,7 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumAdd { + let mut syscall = SyscallBigNumDiv { cost: 1, compute_meter, loader_id: &bpf_loader::id(), @@ -4736,20 +5080,19 @@ mod tests { syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); unsafe { result_vec.set_len(out_size as usize) }; - assert_eq!(result_vec, vec![1, 7]); + assert_eq!(result_vec, vec![30]); } #[test] - fn test_syscall_bignum_sub() { + fn test_syscall_bignum_sqr() { struct ArgSlice { pub addr: u64, pub len: usize, } - let bn_arg1 = BigNum::from_u32(5).unwrap(); - let bn_arg2 = BigNum::from_u32(258).unwrap(); + + let bn_arg1 = BigNum::from_u32(300).unwrap(); let arg1 = bn_arg1.as_ref().to_vec(); - let arg2 = bn_arg2.as_ref().to_vec(); - let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; - let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let neg_flags = vec![bn_arg1.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() * 2); let mut out_size = result_vec.capacity() as u64; let out_size_addr = &mut out_size as *mut _ as u64; let mut neg_result = 0u64; @@ -4759,15 +5102,11 @@ mod tests { addr: 1024, len: arg1.len(), }; - let mock_arg2 = ArgSlice { - addr: 2048, - len: arg2.len(), - }; let mock_neg_flags = ArgSlice { - addr: 4096, + addr: 2048, len: neg_flags.len(), }; - let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; + let adds_array = [mock_arg1, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { @@ -4777,16 +5116,9 @@ mod tests { vm_gap_shift: 63, is_writable: false, }, - MemoryRegion { - host_addr: arg2.as_ptr() as *const _ as u64, - vm_addr: 2048, - len: arg2.len() as u64, - vm_gap_shift: 63, - is_writable: false, - }, MemoryRegion { host_addr: neg_flags.as_ptr() as *const _ as u64, - vm_addr: 4096, + vm_addr: 2048, len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, @@ -4828,26 +5160,25 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumSub { + let mut syscall = SyscallBigNumSqr { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); + syscall.call(96, 2, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); unsafe { result_vec.set_len(out_size as usize) }; - assert_eq!(result_vec, vec![253]); + assert_eq!(result_vec, vec![1, 95, 144]); } - #[test] - fn test_syscall_bignum_mul() { + fn test_syscall_bignum_exp() { struct ArgSlice { pub addr: u64, pub len: usize, } - let bn_arg1 = BigNum::from_u32(5).unwrap(); - let bn_arg2 = BigNum::from_u32(5).unwrap(); + let bn_arg1 = BigNum::from_u32(8).unwrap(); + let bn_arg2 = BigNum::from_u32(2).unwrap(); let arg1 = bn_arg1.as_ref().to_vec(); let arg2 = bn_arg2.as_ref().to_vec(); let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; @@ -4930,7 +5261,7 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumMul { + let mut syscall = SyscallBigNumExp { cost: 1, compute_meter, loader_id: &bpf_loader::id(), @@ -4939,17 +5270,17 @@ mod tests { syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); unsafe { result_vec.set_len(out_size as usize) }; - assert_eq!(result_vec, vec![25]); + assert_eq!(result_vec, vec![64]); } #[test] - fn test_syscall_bignum_div() { + fn test_syscall_bignum_mod_sqr() { struct ArgSlice { pub addr: u64, pub len: usize, } - let bn_arg1 = BigNum::from_u32(300).unwrap(); - let bn_arg2 = BigNum::from_u32(10).unwrap(); + let bn_arg1 = BigNum::from_u32(11).unwrap(); + let bn_arg2 = BigNum::from_u32(7).unwrap(); let arg1 = bn_arg1.as_ref().to_vec(); let arg2 = bn_arg2.as_ref().to_vec(); let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; @@ -5032,7 +5363,7 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumDiv { + let mut syscall = SyscallBigNumModSqr { cost: 1, compute_meter, loader_id: &bpf_loader::id(), @@ -5041,19 +5372,26 @@ mod tests { syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); result.unwrap(); unsafe { result_vec.set_len(out_size as usize) }; - assert_eq!(result_vec, vec![30]); + assert_eq!(result_vec, vec![2]); } #[test] - fn test_syscall_bignum_sqr() { + fn test_syscall_bignum_mod_exp() { struct ArgSlice { pub addr: u64, pub len: usize, } - let bn_arg1 = BigNum::from_u32(300).unwrap(); + let bn_arg2 = BigNum::from_u32(11).unwrap(); + let bn_arg3 = BigNum::from_u32(7).unwrap(); let arg1 = bn_arg1.as_ref().to_vec(); - let neg_flags = vec![bn_arg1.is_negative() as u8]; - let mut result_vec = Vec::::with_capacity(arg1.len() * 2); + let arg2 = bn_arg2.as_ref().to_vec(); + let arg3 = bn_arg3.as_ref().to_vec(); + let neg_flags = vec![ + bn_arg1.is_negative() as u8, + bn_arg2.is_negative() as u8, + bn_arg3.is_negative() as u8, + ]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); let mut out_size = result_vec.capacity() as u64; let out_size_addr = &mut out_size as *mut _ as u64; let mut neg_result = 0u64; @@ -5063,11 +5401,19 @@ mod tests { addr: 1024, len: arg1.len(), }; - let mock_neg_flags = ArgSlice { + let mock_arg2 = ArgSlice { addr: 2048, + len: arg2.len(), + }; + let mock_arg3 = ArgSlice { + addr: 4096, + len: arg3.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 8192, len: neg_flags.len(), }; - let adds_array = [mock_arg1, mock_neg_flags]; + let adds_array = [mock_arg1, mock_arg2, mock_arg3, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { @@ -5078,15 +5424,29 @@ mod tests { is_writable: false, }, MemoryRegion { - host_addr: neg_flags.as_ptr() as *const _ as u64, + host_addr: arg2.as_ptr() as *const _ as u64, vm_addr: 2048, + len: arg2.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: arg3.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: arg3.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 8192, len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { host_addr: result_vec.as_mut_ptr() as u64, - vm_addr: 8192, + vm_addr: 16_384, len: result_vec.capacity() as u64, vm_gap_shift: 63, is_writable: true, @@ -5094,7 +5454,7 @@ mod tests { MemoryRegion { host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, - len: 48, + len: adds_array.len() as u64 * 16, vm_gap_shift: 63, is_writable: false, }, @@ -5121,28 +5481,42 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumSqr { + let mut syscall = SyscallBigNumModExp { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, 2, 8192, 8, 16, &memory_mapping, &mut result); + syscall.call( + 96, + adds_array.len() as u64, + 16_384, + 8, + 16, + &memory_mapping, + &mut result, + ); result.unwrap(); unsafe { result_vec.set_len(out_size as usize) }; - assert_eq!(result_vec, vec![1, 95, 144]); + assert_eq!(result_vec, vec![6]); } #[test] - fn test_syscall_bignum_exp() { + fn test_syscall_bignum_mod_mul() { struct ArgSlice { pub addr: u64, pub len: usize, } - let bn_arg1 = BigNum::from_u32(8).unwrap(); - let bn_arg2 = BigNum::from_u32(2).unwrap(); + let bn_arg1 = BigNum::from_u32(300).unwrap(); + let bn_arg2 = BigNum::from_u32(11).unwrap(); + let bn_arg3 = BigNum::from_u32(7).unwrap(); let arg1 = bn_arg1.as_ref().to_vec(); let arg2 = bn_arg2.as_ref().to_vec(); - let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let arg3 = bn_arg3.as_ref().to_vec(); + let neg_flags = vec![ + bn_arg1.is_negative() as u8, + bn_arg2.is_negative() as u8, + bn_arg3.is_negative() as u8, + ]; let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); let mut out_size = result_vec.capacity() as u64; let out_size_addr = &mut out_size as *mut _ as u64; @@ -5157,11 +5531,15 @@ mod tests { addr: 2048, len: arg2.len(), }; - let mock_neg_flags = ArgSlice { + let mock_arg3 = ArgSlice { addr: 4096, + len: arg3.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 8192, len: neg_flags.len(), }; - let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; + let adds_array = [mock_arg1, mock_arg2, mock_arg3, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { @@ -5179,15 +5557,22 @@ mod tests { is_writable: false, }, MemoryRegion { - host_addr: neg_flags.as_ptr() as *const _ as u64, + host_addr: arg3.as_ptr() as *const _ as u64, vm_addr: 4096, + len: arg3.len() as u64, + vm_gap_shift: 63, + is_writable: false, + }, + MemoryRegion { + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 8192, len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { host_addr: result_vec.as_mut_ptr() as u64, - vm_addr: 8192, + vm_addr: 16_384, len: result_vec.capacity() as u64, vm_gap_shift: 63, is_writable: true, @@ -5195,7 +5580,7 @@ mod tests { MemoryRegion { host_addr: adds_array.as_ptr() as *const _ as u64, vm_addr: 96, - len: 48, + len: adds_array.len() as u64 * 16, vm_gap_shift: 63, is_writable: false, }, @@ -5222,157 +5607,102 @@ mod tests { Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, })); - let mut syscall = SyscallBigNumExp { + let mut syscall = SyscallBigNumModMul { cost: 1, compute_meter, loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(96, 3, 8192, 8, 16, &memory_mapping, &mut result); + syscall.call( + 96, + adds_array.len() as u64, + 16_384, + 8, + 16, + &memory_mapping, + &mut result, + ); result.unwrap(); unsafe { result_vec.set_len(out_size as usize) }; - assert_eq!(result_vec, vec![64]); + assert_eq!(result_vec, vec![3]); } - #[test] - fn test_syscall_bignum_mod_sqr() { - let mut mod_sqr = 0u64; - let mod_sqr_addr = &mut mod_sqr as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(15); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_ptr = new_u32_bignum(7); - let bn_3_addr = &bn_3_ptr as *const _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![ - MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: false, - }, - MemoryRegion { - host_addr: mod_sqr_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, - vm_gap_shift: 63, - is_writable: true, - }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); + fn test_syscall_bignum_mod_inv() { + struct ArgSlice { + pub addr: u64, + pub len: usize, + } + let bn_arg1 = BigNum::from_u32(415).unwrap(); + let bn_arg2 = BigNum::from_u32(7).unwrap(); + let arg1 = bn_arg1.as_ref().to_vec(); + let arg2 = bn_arg2.as_ref().to_vec(); + let neg_flags = vec![bn_arg1.is_negative() as u8, bn_arg2.is_negative() as u8]; + let mut result_vec = Vec::::with_capacity(arg1.len() + arg2.len()); + let mut out_size = result_vec.capacity() as u64; + let out_size_addr = &mut out_size as *mut _ as u64; + let mut neg_result = 0u64; + let neg_flag_addr = &mut neg_result as *mut _ as u64; - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); - let mut syscall = SyscallBigNumModSqr { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), + let mock_arg1 = ArgSlice { + addr: 1024, + len: arg1.len(), }; - let mut result: Result> = Ok(0); - syscall.call(8, 16, 96, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - let braw: &BigNum = unsafe { &*(mod_sqr as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(1).unwrap()); - } - - #[test] - fn test_syscall_bignum_mod_mul() { - let mut mod_mul = 0u64; - let mod_mul_addr = &mut mod_mul as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(3); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_ptr = new_u32_bignum(3); - let bn_3_addr = &bn_3_ptr as *const _ as u64; - let bn_4_ptr = new_u32_bignum(7); - let bn_4_addr = &bn_4_ptr as *const _ as u64; + let mock_arg2 = ArgSlice { + addr: 2048, + len: arg2.len(), + }; + let mock_neg_flags = ArgSlice { + addr: 4096, + len: neg_flags.len(), + }; + let adds_array = [mock_arg1, mock_arg2, mock_neg_flags]; let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: arg1.as_ptr() as *const _ as u64, + vm_addr: 1024, + len: arg1.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 16, - len: std::mem::size_of::() as u64, + host_addr: arg2.as_ptr() as *const _ as u64, + vm_addr: 2048, + len: arg2.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_4_addr, - vm_addr: 24, - len: std::mem::size_of::() as u64, + host_addr: neg_flags.as_ptr() as *const _ as u64, + vm_addr: 4096, + len: neg_flags.len() as u64, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: mod_mul_addr, - vm_addr: 96, - len: std::mem::size_of::() as u64, + host_addr: result_vec.as_mut_ptr() as u64, + vm_addr: 8192, + len: result_vec.capacity() as u64, vm_gap_shift: 63, is_writable: true, }, - ], - &DEFAULT_CONFIG, - ) - .unwrap(); - let compute_meter: Rc> = - Rc::new(RefCell::new(MockComputeMeter { - remaining: (20 + 20) as u64, - })); - let mut syscall = SyscallBigNumModMul { - cost: 1, - compute_meter, - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall.call(8, 16, 24, 96, 0, &memory_mapping, &mut result); - result.unwrap(); - let braw: &BigNum = unsafe { &*(mod_mul as *mut BigNum) }; - assert_eq!(*braw, BigNum::from_u32(2).unwrap()); - } - #[test] - #[should_panic(expected = "UserError(SyscallError(BigNumberModInvError))")] - fn test_syscall_bignum_mod_inv() { - let mut mod_inv = 0u64; - let mod_inv_addr = &mut mod_inv as *mut _ as u64; - let bn_2_ptr = new_u32_bignum(3); - let bn_2_addr = &bn_2_ptr as *const _ as u64; - let bn_3_ptr = new_u32_bignum(3); - let bn_3_addr = &bn_3_ptr as *const _ as u64; - let memory_mapping = MemoryMapping::new::( - vec![ MemoryRegion { - host_addr: bn_2_addr, - vm_addr: 8, - len: std::mem::size_of::() as u64, + host_addr: adds_array.as_ptr() as *const _ as u64, + vm_addr: 96, + len: adds_array.len() as u64 * 16, vm_gap_shift: 63, is_writable: false, }, MemoryRegion { - host_addr: bn_3_addr, - vm_addr: 32, + host_addr: neg_flag_addr, + vm_addr: 8, len: std::mem::size_of::() as u64, vm_gap_shift: 63, - is_writable: false, + is_writable: true, }, MemoryRegion { - host_addr: mod_inv_addr, - vm_addr: 96, + host_addr: out_size_addr, + vm_addr: 16, len: std::mem::size_of::() as u64, vm_gap_shift: 63, is_writable: true, @@ -5381,6 +5711,7 @@ mod tests { &DEFAULT_CONFIG, ) .unwrap(); + let compute_meter: Rc> = Rc::new(RefCell::new(MockComputeMeter { remaining: (20 + 20) as u64, @@ -5391,7 +5722,17 @@ mod tests { loader_id: &bpf_loader::id(), }; let mut result: Result> = Ok(0); - syscall.call(8, 32, 96, 0, 0, &memory_mapping, &mut result); + syscall.call( + 96, + adds_array.len() as u64, + 8192, + 8, + 16, + &memory_mapping, + &mut result, + ); result.unwrap(); + unsafe { result_vec.set_len(out_size as usize) }; + assert_eq!(result_vec, vec![4]); } } diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 892a9a6b123860..087453efa26b0a 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -248,7 +248,9 @@ impl BigNumber { let my_num = BigNum::from_slice(&self.value).unwrap(); let rhs_num = BigNum::from_slice(&rhs.value).unwrap(); let mut bn_res = BigNum::new().unwrap(); - bn_res.checked_mul(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()).unwrap(); + bn_res + .checked_mul(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()) + .unwrap(); let value = bn_res.as_ref().to_vec(); Self { negative: bn_res.is_negative(), @@ -297,7 +299,9 @@ impl BigNumber { let my_num = BigNum::from_slice(&self.value).unwrap(); let rhs_num = BigNum::from_slice(&rhs.value).unwrap(); let mut bn_res = BigNum::new().unwrap(); - bn_res.checked_div(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()).unwrap(); + bn_res + .checked_div(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()) + .unwrap(); let value = bn_res.as_ref().to_vec(); Self { negative: bn_res.is_negative(), @@ -346,7 +350,9 @@ impl BigNumber { use openssl::bn::{BigNum, BigNumContext}; let my_num = BigNum::from_slice(&self.value).unwrap(); let mut bn_res = BigNum::new().unwrap(); - bn_res.sqr(&my_num, &mut BigNumContext::new().unwrap()).unwrap(); + bn_res + .sqr(&my_num, &mut BigNumContext::new().unwrap()) + .unwrap(); let value = bn_res.as_ref().to_vec(); Self { negative: bn_res.is_negative(), @@ -368,7 +374,7 @@ impl BigNumber { let neg_values = vec![self.negative as u8]; let arg_array = vec![self.to_bytes(), &neg_values]; // Setup the result information - let mut value_len = self.value.len()*2; + let mut value_len = self.value.len() * 2; let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; @@ -397,7 +403,9 @@ impl BigNumber { let my_num = BigNum::from_slice(&self.value).unwrap(); let rhs_num = BigNum::from_slice(&exponent.value).unwrap(); let mut bn_res = BigNum::new().unwrap(); - bn_res.exp(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()).unwrap(); + bn_res + .exp(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()) + .unwrap(); let value = bn_res.as_ref().to_vec(); Self { negative: bn_res.is_negative(), @@ -438,179 +446,263 @@ impl BigNumber { } } } + /// BigNumbers modulus square + pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&modulus.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res + .mod_sqr(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()) + .unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_mod_sqr( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, modulus.negative as u8]; + let arg_array = vec![self.to_bytes(), modulus.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), modulus.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + unsafe { + sol_bignum_mod_sqr( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } + + /// Compute modular exponentiation (self ^ rhs mod order) and return the result + pub fn mod_exp(&self, exponent: &BigNumber, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let exp_num = BigNum::from_slice(&exponent.value).unwrap(); + let mod_num = BigNum::from_slice(&modulus.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res + .mod_exp( + &my_num, + &exp_num, + &mod_num, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_mod_exp( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (4) + let neg_values = vec![ + self.negative as u8, + exponent.negative as u8, + modulus.negative as u8, + ]; + let arg_array = vec![ + self.to_bytes(), + exponent.to_bytes(), + modulus.to_bytes(), + &neg_values, + ]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), exponent.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; - // /// Mod multiplier (self * multiplier) % modulus - // pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext}; - // let mut new_self = Box::new(BigNum::new().unwrap()); - // let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let multiplier_ptr: &BigNum = unsafe { &*(multiplier.0 as *const BigNum) }; - // let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - // new_self - // .mod_mul( - // myself_ptr, - // multiplier_ptr, - // modulus_ptr, - // &mut BigNumContext::new().unwrap(), - // ) - // .unwrap(); - // let rwptr = Box::into_raw(new_self); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_mod_mul( - // self_ptr: *const u64, - // multiplier_ptr: *const u64, - // modulus_ptr: *const u64, - // bignum_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_mod_mul( - // &self.0 as *const _ as *const u64, - // &multiplier.0 as *const _ as *const u64, - // &modulus.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } + unsafe { + sol_bignum_mod_exp( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } - // /// Finds the inverse of modulus on self - // pub fn mod_inv(&self, modulus: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext}; - // let mut new_self = Box::new(BigNum::new().unwrap()); - // let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - // new_self - // .mod_inverse(myself_ptr, modulus_ptr, &mut BigNumContext::new().unwrap()) - // .unwrap(); - // let rwptr = Box::into_raw(new_self); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_mod_inv( - // self_ptr: *const u64, - // modulus_ptr: *const u64, - // bignum_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_mod_inv( - // &self.0 as *const _ as *const u64, - // &modulus.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } + /// Mod multiplier (self * multiplier) % modulus + pub fn mod_mul(&self, multiplier: &BigNumber, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let mul_num = BigNum::from_slice(&multiplier.value).unwrap(); + let mod_num = BigNum::from_slice(&modulus.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res + .mod_mul( + &my_num, + &mul_num, + &mod_num, + &mut BigNumContext::new().unwrap(), + ) + .unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_mod_mul( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (4) + let neg_values = vec![ + self.negative as u8, + multiplier.negative as u8, + modulus.negative as u8, + ]; + let arg_array = vec![ + self.to_bytes(), + multiplier.to_bytes(), + modulus.to_bytes(), + &neg_values, + ]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), multiplier.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; - // /// Square BigNumbers - // pub fn mod_sqr(&self, modulus: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext, BigNumRef}; - // let my_raw: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let my_mod: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - // let mut bbox = Box::new(BigNum::new().unwrap()); - // BigNumRef::mod_sqr( - // &mut *bbox, - // my_raw, - // my_mod, - // &mut BigNumContext::new().unwrap(), - // ) - // .unwrap(); - // let rwptr = Box::into_raw(bbox); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_mod_sqr( - // self_ptr: *const u64, - // modulus_ptr: *const u64, - // bignum_ptr: *mut u64, - // ) -> u64; - // } - // let mut bignum_ptr = 0u64; - // unsafe { - // sol_bignum_mod_sqr( - // &self.0 as *const _ as *const u64, - // &modulus.0 as *const _ as *const u64, - // &mut bignum_ptr as *mut _ as *mut u64, - // ); - // } - // Self(bignum_ptr) - // } - // } + unsafe { + sol_bignum_mod_mul( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } - // /// Compute modular exponentiation (self ^ rhs mod order) and return the result - // pub fn mod_exp(&self, exponent: &BigNumber, modulus: &BigNumber) -> Self { - // #[cfg(not(target_arch = "bpf"))] - // { - // use openssl::bn::{BigNum, BigNumContext}; - // let mut new_self = Box::new(BigNum::new().unwrap()); - // let myself_ptr: &BigNum = unsafe { &*(self.0 as *const BigNum) }; - // let exponent_ptr: &BigNum = unsafe { &*(exponent.0 as *const BigNum) }; - // let modulus_ptr: &BigNum = unsafe { &*(modulus.0 as *const BigNum) }; - // new_self - // .mod_exp( - // myself_ptr, - // exponent_ptr, - // modulus_ptr, - // &mut BigNumContext::new().unwrap(), - // ) - // .unwrap(); - // let rwptr = Box::into_raw(new_self); - // Self(rwptr as u64) - // } - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_mod_exp( - // bignum_ptr: *mut u64, - // self_ptr: *const u64, - // exponent_ptr: *const u64, - // modulus_ptr: *const u64, - // ) -> u64; - // } - // let bignum_ptr = &mut 0u64; - // unsafe { - // sol_bignum_mod_exp( - // &mut *bignum_ptr as *mut _ as *mut u64, - // &self.0 as *const _ as *const u64, - // &exponent.0 as *const _ as *const u64, - // &modulus.0 as *const _ as *const u64, - // ); - // } - // Self(*bignum_ptr) - // } - // } + /// Finds the inverse of modulus on self + pub fn mod_inv(&self, modulus: &BigNumber) -> Self { + #[cfg(not(target_arch = "bpf"))] + { + use openssl::bn::{BigNum, BigNumContext}; + let my_num = BigNum::from_slice(&self.value).unwrap(); + let rhs_num = BigNum::from_slice(&modulus.value).unwrap(); + let mut bn_res = BigNum::new().unwrap(); + bn_res + .mod_inverse(&my_num, &rhs_num, &mut BigNumContext::new().unwrap()) + .unwrap(); + let value = bn_res.as_ref().to_vec(); + Self { + negative: bn_res.is_negative(), + value, + } + } + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_mod_inv( + arg_address: *const u64, + arg_count: u64, + out_value_address: *mut u8, + out_neg_address: *mut u64, + out_size_address: *mut u64, + ) -> u64; + } + // Setup the argument array (3) + let neg_values = vec![self.negative as u8, modulus.negative as u8]; + let arg_array = vec![self.to_bytes(), modulus.to_bytes(), &neg_values]; + // Setup the result information + let mut value_len = std::cmp::max(self.value.len(), modulus.value.len()) + 1; + let mut value = Vec::::with_capacity(value_len as usize); + let mut is_negative = 0u64; + unsafe { + sol_bignum_mod_inv( + arg_array.as_ptr() as *const _ as *const u64, + arg_array.len() as u64, + value.as_mut_ptr() as *mut _ as *mut u8, + &mut is_negative as *mut _ as *mut u64, + &mut value_len as *mut _ as *mut u64, + ); + value.set_len(value_len as usize); + } + Self { + negative: is_negative != 0, + value, + } + } + } - // /// Log a `BigNum` from a program - // pub fn log(&self) { - // #[cfg(not(target_arch = "bpf"))] - // crate::program_stubs::sol_log(&self.to_string()); - // #[cfg(target_arch = "bpf")] - // { - // extern "C" { - // fn sol_bignum_log(bignum_addr: *const u64) -> u64; - // } - // unsafe { sol_bignum_log(&self.0 as *const _ as *const u64) }; - // } - // } + /// Log a `BigNum` from a program + pub fn log(&self) { + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_log(&self.to_string()); + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_bignum_log(bignum_addr: *const u64, bignum_size: u64) -> u64; + } + unsafe { + sol_bignum_log( + self.value.as_ptr() as *const _ as *const u64, + self.value.len() as u64, + ) + }; + } + } } impl Default for BigNumber { From 069c6744239fff93464fc5b90b5036ceb05af29f Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:10:06 -0400 Subject: [PATCH 22/45] Remove println call --- programs/bpf_loader/src/syscalls.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d73f0b645b9e98..c7da933e6f603c 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4656,8 +4656,6 @@ mod tests { fn test_syscall_bignum_from_u32() { let bn_new = BigNum::new().unwrap(); let bn_0 = BigNum::from_u32(0).unwrap(); - println!("bn_new_vec {:?}", bn_new.to_vec()); - println!("bn_0 {:?}", bn_0.to_vec()); let bn_20 = new_u32_bignum(20u32); let bn = BigNum::from_u32(20u32).unwrap().to_vec(); assert_eq!(bn_20, bn); From 7e7bebb08cd448686108d77dcd8632eed4988ee9 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:12:40 -0400 Subject: [PATCH 23/45] Remove dead code --- programs/bpf_loader/src/syscalls.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index c7da933e6f603c..d6aed643dc6d5b 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4654,8 +4654,6 @@ mod tests { #[test] fn test_syscall_bignum_from_u32() { - let bn_new = BigNum::new().unwrap(); - let bn_0 = BigNum::from_u32(0).unwrap(); let bn_20 = new_u32_bignum(20u32); let bn = BigNum::from_u32(20u32).unwrap().to_vec(); assert_eq!(bn_20, bn); From ed924a5b3fbfd4c15ab7b88042115f53bbfb206c Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:21:28 -0400 Subject: [PATCH 24/45] Replace Vec with vec macro as per clippy --- sdk/program/src/bignum.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 087453efa26b0a..b736902ecdab1d 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -26,11 +26,9 @@ pub struct BigNumber { impl BigNumber { /// Returns a BigNumber with initial value of 0 pub fn new() -> Self { - let mut value = Vec::::new(); - value.push(0u8); Self { negative: false, - value, + value: vec![0u8], } } @@ -43,11 +41,9 @@ impl BigNumber { /// Returns a BigNumber with initial value set to a u32 value pub fn from_u32(val: u32) -> Self { if val == 0 { - let mut value = Vec::::new(); - value.push(0); Self { negative: false, - value, + value: vec![0u8], } } else { #[cfg(not(target_arch = "bpf"))] @@ -707,11 +703,9 @@ impl BigNumber { impl Default for BigNumber { fn default() -> Self { - let mut value = Vec::::new(); - value.push(0); Self { negative: false, - value, + value: vec![0u8], } } } From b173d5915b792fed54fde0ae12692ce8b33addf2 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:32:12 -0400 Subject: [PATCH 25/45] Modernize incrementing by 1 --- programs/bpf_loader/src/syscalls.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d6aed643dc6d5b..69a9d56598e17b 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1318,7 +1318,7 @@ impl<'a> SyscallObject for SyscallBigNumFromDecStr<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*byte_slice)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -1464,7 +1464,7 @@ impl<'a> SyscallObject for SyscallBigNumAdd<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -1563,7 +1563,7 @@ impl<'a> SyscallObject for SyscallBigNumSub<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -1665,7 +1665,7 @@ impl<'a> SyscallObject for SyscallBigNumMul<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -1766,7 +1766,7 @@ impl<'a> SyscallObject for SyscallBigNumDiv<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -1864,7 +1864,7 @@ impl<'a> SyscallObject for SyscallBigNumSqr<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -1964,7 +1964,7 @@ impl<'a> SyscallObject for SyscallBigNumExp<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -2066,7 +2066,7 @@ impl<'a> SyscallObject for SyscallBigNumModSqr<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -2173,7 +2173,7 @@ impl<'a> SyscallObject for SyscallBigNumModExp<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -2279,7 +2279,7 @@ impl<'a> SyscallObject for SyscallBigNumModMul<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } @@ -2384,7 +2384,7 @@ impl<'a> SyscallObject for SyscallBigNumModInv<'a> { let mut index = 0; for byte in big_number_bytes.iter() { (*bignum_result)[index] = *byte; - index = index + 1; + index += 1; } *out_size = index as u64; } From aaf90d808a60be938097e12408b33453b6f5c69d Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:44:14 -0400 Subject: [PATCH 26/45] Modernize boolean test --- programs/bpf_loader/src/syscalls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 69a9d56598e17b..1c651c750c902d 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4661,7 +4661,7 @@ mod tests { #[test] fn test_syscall_bignum_from_dec_str() { let (is_neg, result_vec) = new_dec_str_bignum(LONG_DEC_STRING); - assert!(is_neg == false); + assert!(!is_neg); let bns = BigNum::from_dec_str(LONG_DEC_STRING).unwrap(); let bns_vec = bns.as_ref().to_vec(); assert_eq!(result_vec, bns_vec); From 0c9258ea3bd7a31cfeab6da36e71d8fc484dc16e Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 09:54:23 -0400 Subject: [PATCH 27/45] remove unused imports --- programs/bpf/rust/bignum/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index bf0974218cf9ca..bcbc1f4dc833d9 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -1,7 +1,7 @@ //! @brief BigNumber Syscall test extern crate solana_program; -use solana_program::{bignum::BigNumber, custom_panic_default, log::sol_log_compute_units, msg}; +use solana_program::{bignum::BigNumber, custom_panic_default, msg}; const LONG_DEC_STRING: &str = "1470463693494555670176851280755142329532258274256991544781479988\ 712408107190720087233560906792937436573943189716784305633216335039\ From 0d8a51b9749aba1ba01da28645e8cf29738ff97d Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Mon, 17 May 2021 10:34:44 -0400 Subject: [PATCH 28/45] Added assertions to constructor tests --- programs/bpf/rust/bignum/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index bcbc1f4dc833d9..cbc030c7db9999 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -29,9 +29,13 @@ const NEG_LONG_DEC_STRING: &str = fn test_constructors() { msg!("BigNumber constructors"); let base_bn_0 = BigNumber::new(); + assert_eq!(base_bn_0.to_bytes(), vec![0]); let default_0 = BigNumber::default(); + assert_eq!(default_0.to_bytes(), vec![0]); let new_bn_0 = BigNumber::from_u32(0); + assert_eq!(new_bn_0.to_bytes(), vec![0]); let max_bn_u32 = BigNumber::from_u32(u32::MAX); + assert_eq!(max_bn_u32.to_bytes(), vec![255, 255, 255, 255]); let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); assert_eq!(bn_from_dec.is_negative(), false); let bn_from_dec = BigNumber::from_dec_str(NEG_LONG_DEC_STRING); From af54caee5812c0aebe774cad4a48997344db58ef Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Tue, 18 May 2021 05:24:47 -0400 Subject: [PATCH 29/45] Fix logging to include sign and refine result allocations --- programs/bpf/rust/bignum/src/lib.rs | 17 +++++++++++++++-- programs/bpf_loader/src/syscalls.rs | 5 +++-- sdk/program/src/bignum.rs | 17 +++++++++-------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index cbc030c7db9999..d2d6b83951e1e2 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -31,9 +31,9 @@ fn test_constructors() { let base_bn_0 = BigNumber::new(); assert_eq!(base_bn_0.to_bytes(), vec![0]); let default_0 = BigNumber::default(); - assert_eq!(default_0.to_bytes(), vec![0]); + assert!(base_bn_0 == default_0); let new_bn_0 = BigNumber::from_u32(0); - assert_eq!(new_bn_0.to_bytes(), vec![0]); + assert!(new_bn_0 == default_0); let max_bn_u32 = BigNumber::from_u32(u32::MAX); assert_eq!(max_bn_u32.to_bytes(), vec![255, 255, 255, 255]); let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); @@ -87,12 +87,20 @@ fn test_complex_maths() { mod_inv.log(); } +fn test_output_logging() { + let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); + bn_from_dec.log(); + let bn_from_dec = BigNumber::from_dec_str(NEG_LONG_DEC_STRING); + bn_from_dec.log(); +} + #[no_mangle] pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { msg!("bignum"); test_constructors(); test_basic_maths(); test_complex_maths(); + test_output_logging(); 0u64 } @@ -114,4 +122,9 @@ mod test { fn test_complex_maths_pass() { test_complex_maths(); } + + #[test] + fn test_logging() { + test_output_logging(); + } } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 1c651c750c902d..d3f22bf9345653 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -2410,7 +2410,7 @@ impl<'a> SyscallObject for SyscallBigNumLog<'a> { &mut self, bn_addr: u64, bn_size: u64, - _arg3: u64, + neg_flag: u64, _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, @@ -2425,7 +2425,8 @@ impl<'a> SyscallObject for SyscallBigNumLog<'a> { .consume(self.cost + calc_bignum_cost!(bn_size as f64)), result ); - let bignum = BigNum::from_slice(bignum_ptr).unwrap(); + let mut bignum = BigNum::from_slice(bignum_ptr).unwrap(); + bignum.set_negative(neg_flag == 1u64); stable_log::program_log(&self.logger, &bignum.to_string()); *result = Ok(0); } diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index b736902ecdab1d..30f19564a477e7 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -268,7 +268,7 @@ impl BigNumber { let neg_values = vec![self.negative as u8, rhs.negative as u8]; let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), rhs.value.len()) + 1; + let mut value_len = self.value.len() + rhs.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; unsafe { @@ -319,7 +319,7 @@ impl BigNumber { let neg_values = vec![self.negative as u8, rhs.negative as u8]; let arg_array = vec![self.to_bytes(), rhs.to_bytes(), &neg_values]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), rhs.value.len()) + 1; + let mut value_len = self.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; unsafe { @@ -423,7 +423,7 @@ impl BigNumber { let neg_values = vec![self.negative as u8, exponent.negative as u8]; let arg_array = vec![self.to_bytes(), exponent.to_bytes(), &neg_values]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), exponent.value.len()) + 1; + let mut value_len = self.value.len() * exponent.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; unsafe { @@ -474,7 +474,7 @@ impl BigNumber { let neg_values = vec![self.negative as u8, modulus.negative as u8]; let arg_array = vec![self.to_bytes(), modulus.to_bytes(), &neg_values]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), modulus.value.len()) + 1; + let mut value_len = modulus.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; unsafe { @@ -541,7 +541,7 @@ impl BigNumber { &neg_values, ]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), exponent.value.len()) + 1; + let mut value_len = self.value.len() * exponent.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; @@ -609,7 +609,7 @@ impl BigNumber { &neg_values, ]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), multiplier.value.len()) + 1; + let mut value_len = modulus.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; @@ -662,7 +662,7 @@ impl BigNumber { let neg_values = vec![self.negative as u8, modulus.negative as u8]; let arg_array = vec![self.to_bytes(), modulus.to_bytes(), &neg_values]; // Setup the result information - let mut value_len = std::cmp::max(self.value.len(), modulus.value.len()) + 1; + let mut value_len = modulus.value.len(); let mut value = Vec::::with_capacity(value_len as usize); let mut is_negative = 0u64; unsafe { @@ -689,12 +689,13 @@ impl BigNumber { #[cfg(target_arch = "bpf")] { extern "C" { - fn sol_bignum_log(bignum_addr: *const u64, bignum_size: u64) -> u64; + fn sol_bignum_log(bignum_addr: *const u64, bignum_size: u64, negative_set: u64) -> u64; } unsafe { sol_bignum_log( self.value.as_ptr() as *const _ as *const u64, self.value.len() as u64, + self.negative as u64, ) }; } From 35d5c6266f684b9607275a2f8d281d0901d6a1fb Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Tue, 18 May 2021 05:38:53 -0400 Subject: [PATCH 30/45] Cleanup tests --- programs/bpf/rust/bignum/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index d2d6b83951e1e2..81f0461d617c7d 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -84,7 +84,6 @@ fn test_complex_maths() { let bn_arg2 = BigNumber::from_u32(7); let mod_inv = bn_arg1.mod_inv(&bn_arg2); assert_eq!(mod_inv.to_bytes(), vec![4]); - mod_inv.log(); } fn test_output_logging() { From 4b7925c33e69f01a3aae47df95bb61e82fbde270 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Tue, 18 May 2021 05:47:19 -0400 Subject: [PATCH 31/45] Updated logging for non-bpf execution --- sdk/program/src/bignum.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sdk/program/src/bignum.rs b/sdk/program/src/bignum.rs index 30f19564a477e7..402daf29eda7ff 100644 --- a/sdk/program/src/bignum.rs +++ b/sdk/program/src/bignum.rs @@ -685,11 +685,20 @@ impl BigNumber { /// Log a `BigNum` from a program pub fn log(&self) { #[cfg(not(target_arch = "bpf"))] - crate::program_stubs::sol_log(&self.to_string()); + { + use openssl::bn::BigNum; + let mut my_num = BigNum::from_slice(&self.value).unwrap(); + my_num.set_negative(self.negative); + crate::program_stubs::sol_log(&my_num.to_dec_str().unwrap()); + } #[cfg(target_arch = "bpf")] { extern "C" { - fn sol_bignum_log(bignum_addr: *const u64, bignum_size: u64, negative_set: u64) -> u64; + fn sol_bignum_log( + bignum_addr: *const u64, + bignum_size: u64, + negative_set: u64, + ) -> u64; } unsafe { sol_bignum_log( From bc7eb30376ac7400bf0dc3ca21cccfa34e3dbb04 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Wed, 19 May 2021 05:29:28 -0400 Subject: [PATCH 32/45] Doubled BigNumber syscall execution base units --- sdk/src/process_instruction.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index e720c0e1f1645f..b396d48b8e699d 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -218,15 +218,15 @@ impl BpfComputeBudget { bignum_from_dec_str_base_cost: 100, bignum_mod_exp_base_cost: 100, bignum_log_cost: 100, - bignum_add_cost: 15, - bignum_sub_cost: 15, - bignum_mul_cost: 30, - bignum_div_cost: 30, - bignum_exp_cost: 30, - bignum_sqr_cost: 15, - bignum_mod_sqr_cost: 30, - bignum_mod_mul_cost: 45, - bignum_mod_inv_cost: 45, + bignum_add_cost: 30, + bignum_sub_cost: 30, + bignum_mul_cost: 60, + bignum_div_cost: 60, + bignum_exp_cost: 60, + bignum_sqr_cost: 30, + bignum_mod_sqr_cost: 60, + bignum_mod_mul_cost: 90, + bignum_mod_inv_cost: 90, } } } From 1f422ab007d0955adf5de847c4341bb3fa6de66b Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Wed, 19 May 2021 11:17:15 -0400 Subject: [PATCH 33/45] Fix deadcode errors --- programs/bpf_loader/src/syscalls.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 05e799242a9b67..b1c8185a975359 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -4255,7 +4255,7 @@ mod tests { fn test_syscall_sha256() { let bytes1 = "Gaggablaghblagh!"; let bytes2 = "flurbos"; - + #[allow(dead_code)] struct MockSlice { pub addr: u64, pub len: usize, @@ -4675,6 +4675,7 @@ mod tests { #[test] fn test_syscall_bignum_add() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -4776,6 +4777,7 @@ mod tests { } #[test] fn test_syscall_bignum_sub() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -4878,6 +4880,7 @@ mod tests { #[test] fn test_syscall_bignum_mul() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -4980,6 +4983,7 @@ mod tests { #[test] fn test_syscall_bignum_div() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -5081,6 +5085,7 @@ mod tests { } #[test] fn test_syscall_bignum_sqr() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -5170,6 +5175,7 @@ mod tests { } #[test] fn test_syscall_bignum_exp() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -5272,6 +5278,7 @@ mod tests { #[test] fn test_syscall_bignum_mod_sqr() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -5373,6 +5380,7 @@ mod tests { } #[test] fn test_syscall_bignum_mod_exp() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -5499,6 +5507,7 @@ mod tests { } #[test] fn test_syscall_bignum_mod_mul() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, @@ -5626,6 +5635,7 @@ mod tests { #[test] fn test_syscall_bignum_mod_inv() { + #[allow(dead_code)] struct ArgSlice { pub addr: u64, pub len: usize, From 7a00993f57b6b06e252649dd2d5e8bd3cab43710 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Wed, 19 May 2021 11:29:28 -0400 Subject: [PATCH 34/45] Fix assertion expression --- programs/bpf/rust/bignum/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/bpf/rust/bignum/src/lib.rs b/programs/bpf/rust/bignum/src/lib.rs index 81f0461d617c7d..db7c28af835882 100644 --- a/programs/bpf/rust/bignum/src/lib.rs +++ b/programs/bpf/rust/bignum/src/lib.rs @@ -37,7 +37,7 @@ fn test_constructors() { let max_bn_u32 = BigNumber::from_u32(u32::MAX); assert_eq!(max_bn_u32.to_bytes(), vec![255, 255, 255, 255]); let bn_from_dec = BigNumber::from_dec_str(LONG_DEC_STRING); - assert_eq!(bn_from_dec.is_negative(), false); + assert!(!bn_from_dec.is_negative()); let bn_from_dec = BigNumber::from_dec_str(NEG_LONG_DEC_STRING); assert!(bn_from_dec.is_negative()); } From ed9cbd50f039afa9fbe9865a7099fefc03a778fd Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" <75863576+jeffwashington@users.noreply.github.com> Date: Wed, 19 May 2021 11:50:34 -0500 Subject: [PATCH 35/45] move Ancestors to its own module (#17316) --- accounts-bench/src/main.rs | 3 ++- runtime/benches/accounts.rs | 3 ++- runtime/src/accounts.rs | 3 ++- runtime/src/accounts_db.rs | 3 ++- runtime/src/accounts_index.rs | 4 ++-- runtime/src/ancestors.rs | 4 ++++ runtime/src/bank.rs | 8 ++++---- runtime/src/lib.rs | 1 + runtime/src/message_processor.rs | 2 +- runtime/src/serde_snapshot.rs | 3 ++- runtime/src/status_cache.rs | 2 +- runtime/tests/accounts.rs | 2 +- 12 files changed, 24 insertions(+), 14 deletions(-) create mode 100644 runtime/src/ancestors.rs diff --git a/accounts-bench/src/main.rs b/accounts-bench/src/main.rs index e23be3ce71b35c..01524b07135d0a 100644 --- a/accounts-bench/src/main.rs +++ b/accounts-bench/src/main.rs @@ -6,7 +6,8 @@ use rayon::prelude::*; use solana_measure::measure::Measure; use solana_runtime::{ accounts::{create_test_accounts, update_accounts_bench, Accounts}, - accounts_index::{AccountSecondaryIndexes, Ancestors}, + accounts_index::AccountSecondaryIndexes, + ancestors::Ancestors, }; use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey}; use std::{env, fs, path::PathBuf}; diff --git a/runtime/benches/accounts.rs b/runtime/benches/accounts.rs index 99f60c670564e1..d7a27ad5a51727 100644 --- a/runtime/benches/accounts.rs +++ b/runtime/benches/accounts.rs @@ -8,7 +8,8 @@ use rand::Rng; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use solana_runtime::{ accounts::{create_test_accounts, AccountAddressFilter, Accounts}, - accounts_index::{AccountSecondaryIndexes, Ancestors}, + accounts_index::AccountSecondaryIndexes, + ancestors::Ancestors, bank::*, }; use solana_sdk::{ diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index d6223ac722acf1..43d264e4af90e9 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -2,7 +2,8 @@ use crate::{ accounts_db::{ AccountsDb, BankHashInfo, ErrorCounters, LoadHint, LoadedAccount, ScanStorageResult, }, - accounts_index::{AccountSecondaryIndexes, Ancestors, IndexKey}, + accounts_index::{AccountSecondaryIndexes, IndexKey}, + ancestors::Ancestors, bank::{ NonceRollbackFull, NonceRollbackInfo, TransactionCheckResult, TransactionExecutionResult, }, diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index e368208fe90e1a..168b1357d5f8d1 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -23,8 +23,9 @@ use crate::{ accounts_hash::{AccountsHash, CalculateHashIntermediate, HashStats, PreviousPass}, accounts_index::{ AccountIndexGetResult, AccountSecondaryIndexes, AccountsIndex, AccountsIndexRootsStats, - Ancestors, IndexKey, IsCached, SlotList, SlotSlice, ZeroLamport, + IndexKey, IsCached, SlotList, SlotSlice, ZeroLamport, }, + ancestors::Ancestors, append_vec::{AppendVec, StoredAccountMeta, StoredMeta, StoredMetaWriteVersion}, contains::Contains, read_only_accounts_cache::ReadOnlyAccountsCache, diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index 9fe583450f899d..76761a44f1e9c1 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -1,4 +1,5 @@ use crate::{ + ancestors::Ancestors, contains::Contains, inline_spl_token_v2_0::{self, SPL_TOKEN_ACCOUNT_MINT_OFFSET, SPL_TOKEN_ACCOUNT_OWNER_OFFSET}, secondary_index::*, @@ -15,7 +16,7 @@ use solana_sdk::{ use std::{ collections::{ btree_map::{self, BTreeMap}, - HashMap, HashSet, + HashSet, }, ops::{ Bound, @@ -32,7 +33,6 @@ pub const ITER_BATCH_SIZE: usize = 1000; pub type SlotList = Vec<(Slot, T)>; pub type SlotSlice<'s, T> = &'s [(Slot, T)]; -pub type Ancestors = HashMap; pub type RefCount = u64; pub type AccountMap = BTreeMap; diff --git a/runtime/src/ancestors.rs b/runtime/src/ancestors.rs new file mode 100644 index 00000000000000..d4c167206b3523 --- /dev/null +++ b/runtime/src/ancestors.rs @@ -0,0 +1,4 @@ +use solana_sdk::clock::Slot; +use std::collections::HashMap; + +pub type Ancestors = HashMap; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 90317eedd50c47..e1ad5f433d2386 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -39,7 +39,8 @@ use crate::{ TransactionLoadResult, TransactionLoaders, }, accounts_db::{ErrorCounters, SnapshotStorages}, - accounts_index::{AccountSecondaryIndexes, Ancestors, IndexKey}, + accounts_index::{AccountSecondaryIndexes, IndexKey}, + ancestors::Ancestors, blockhash_queue::BlockhashQueue, builtins::{self, ActivationType}, epoch_stakes::{EpochStakes, NodeVoteAccounts}, @@ -5185,9 +5186,8 @@ pub(crate) mod tests { use super::*; use crate::{ accounts_db::SHRINK_RATIO, - accounts_index::{ - AccountIndex, AccountMap, AccountSecondaryIndexes, Ancestors, ITER_BATCH_SIZE, - }, + accounts_index::{AccountIndex, AccountMap, AccountSecondaryIndexes, ITER_BATCH_SIZE}, + ancestors::Ancestors, genesis_utils::{ activate_all_features, bootstrap_validator_stake_lamports, create_genesis_config_with_leader, create_genesis_config_with_vote_accounts, diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 825075b0bd8b7f..abc3f761785af7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -6,6 +6,7 @@ pub mod accounts_cache; pub mod accounts_db; pub mod accounts_hash; pub mod accounts_index; +pub mod ancestors; pub mod append_vec; pub mod bank; pub mod bank_client; diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 07dcfd1ddba218..2e5ef60034b4a5 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -1,5 +1,5 @@ use crate::{ - accounts::Accounts, accounts_index::Ancestors, instruction_recorder::InstructionRecorder, + accounts::Accounts, ancestors::Ancestors, instruction_recorder::InstructionRecorder, log_collector::LogCollector, native_loader::NativeLoader, rent_collector::RentCollector, }; use log::*; diff --git a/runtime/src/serde_snapshot.rs b/runtime/src/serde_snapshot.rs index 41044fbb84f75e..0cfc7b2b976ea5 100644 --- a/runtime/src/serde_snapshot.rs +++ b/runtime/src/serde_snapshot.rs @@ -2,7 +2,8 @@ use { crate::{ accounts::Accounts, accounts_db::{AccountStorageEntry, AccountsDb, AppendVecId, BankHashInfo}, - accounts_index::{AccountSecondaryIndexes, Ancestors}, + accounts_index::AccountSecondaryIndexes, + ancestors::Ancestors, append_vec::{AppendVec, StoredMetaWriteVersion}, bank::{Bank, BankFieldsToDeserialize, BankRc, Builtins}, blockhash_queue::BlockhashQueue, diff --git a/runtime/src/status_cache.rs b/runtime/src/status_cache.rs index 84cce738989d6e..e66537ae66e8d1 100644 --- a/runtime/src/status_cache.rs +++ b/runtime/src/status_cache.rs @@ -1,4 +1,4 @@ -use crate::accounts_index::Ancestors; +use crate::ancestors::Ancestors; use log::*; use rand::{thread_rng, Rng}; diff --git a/runtime/tests/accounts.rs b/runtime/tests/accounts.rs index c58a71445ffa7c..f04021aff05ec2 100644 --- a/runtime/tests/accounts.rs +++ b/runtime/tests/accounts.rs @@ -3,7 +3,7 @@ use rand::{thread_rng, Rng}; use rayon::prelude::*; use solana_runtime::{ accounts_db::{AccountsDb, LoadHint}, - accounts_index::Ancestors, + ancestors::Ancestors, }; use solana_sdk::genesis_config::ClusterType; use solana_sdk::{ From c20b27bc8f44f1414712867b37965996f22e71ca Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" <75863576+jeffwashington@users.noreply.github.com> Date: Wed, 19 May 2021 12:15:24 -0500 Subject: [PATCH 36/45] shink all in parallel on startup (#17308) --- runtime/src/accounts_db.rs | 142 ++++++++++++++++++++----------------- runtime/src/bank.rs | 8 +-- 2 files changed, 82 insertions(+), 68 deletions(-) diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index 168b1357d5f8d1..9e694a7a1aa3a5 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -2171,12 +2171,22 @@ impl AccountsDb { num_candidates } - pub fn shrink_all_slots(&self) { - for slot in self.all_slots_in_storage() { - if self.caching_enabled { - self.shrink_slot_forced(slot); - } else { - self.do_shrink_slot_forced_v1(slot); + pub fn shrink_all_slots(&self, is_startup: bool) { + if is_startup && self.caching_enabled { + let slots = self.all_slots_in_storage(); + let chunk_size = std::cmp::max(slots.len() / 8, 1); // approximately 400k slots in a snapshot + slots.par_chunks(chunk_size).for_each(|slots| { + for slot in slots { + self.shrink_slot_forced(*slot); + } + }); + } else { + for slot in self.all_slots_in_storage() { + if self.caching_enabled { + self.shrink_slot_forced(slot); + } else { + self.do_shrink_slot_forced_v1(slot); + } } } } @@ -8445,13 +8455,15 @@ pub mod tests { #[test] fn test_shrink_all_slots_none() { - let accounts = AccountsDb::new_single(); + for startup in &[false, true] { + let accounts = AccountsDb::new_single(); - for _ in 0..10 { - accounts.shrink_candidate_slots(); - } + for _ in 0..10 { + accounts.shrink_candidate_slots(); + } - accounts.shrink_all_slots(); + accounts.shrink_all_slots(*startup); + } } #[test] @@ -8532,68 +8544,70 @@ pub mod tests { fn test_shrink_stale_slots_processed() { solana_logger::setup(); - let accounts = AccountsDb::new_single(); + for startup in &[false, true] { + let accounts = AccountsDb::new_single(); - let pubkey_count = 100; - let pubkeys: Vec<_> = (0..pubkey_count) - .map(|_| solana_sdk::pubkey::new_rand()) - .collect(); + let pubkey_count = 100; + let pubkeys: Vec<_> = (0..pubkey_count) + .map(|_| solana_sdk::pubkey::new_rand()) + .collect(); - let some_lamport = 223; - let no_data = 0; - let owner = *AccountSharedData::default().owner(); + let some_lamport = 223; + let no_data = 0; + let owner = *AccountSharedData::default().owner(); - let account = AccountSharedData::new(some_lamport, no_data, &owner); + let account = AccountSharedData::new(some_lamport, no_data, &owner); - let mut current_slot = 0; + let mut current_slot = 0; - current_slot += 1; - for pubkey in &pubkeys { - accounts.store_uncached(current_slot, &[(&pubkey, &account)]); - } - let shrink_slot = current_slot; - accounts.get_accounts_delta_hash(current_slot); - accounts.add_root(current_slot); + current_slot += 1; + for pubkey in &pubkeys { + accounts.store_uncached(current_slot, &[(&pubkey, &account)]); + } + let shrink_slot = current_slot; + accounts.get_accounts_delta_hash(current_slot); + accounts.add_root(current_slot); - current_slot += 1; - let pubkey_count_after_shrink = 10; - let updated_pubkeys = &pubkeys[0..pubkey_count - pubkey_count_after_shrink]; + current_slot += 1; + let pubkey_count_after_shrink = 10; + let updated_pubkeys = &pubkeys[0..pubkey_count - pubkey_count_after_shrink]; - for pubkey in updated_pubkeys { - accounts.store_uncached(current_slot, &[(&pubkey, &account)]); - } - accounts.get_accounts_delta_hash(current_slot); - accounts.add_root(current_slot); + for pubkey in updated_pubkeys { + accounts.store_uncached(current_slot, &[(&pubkey, &account)]); + } + accounts.get_accounts_delta_hash(current_slot); + accounts.add_root(current_slot); - accounts.clean_accounts(None); + accounts.clean_accounts(None); - assert_eq!( - pubkey_count, - accounts.all_account_count_in_append_vec(shrink_slot) - ); - accounts.shrink_all_slots(); - assert_eq!( - pubkey_count_after_shrink, - accounts.all_account_count_in_append_vec(shrink_slot) - ); + assert_eq!( + pubkey_count, + accounts.all_account_count_in_append_vec(shrink_slot) + ); + accounts.shrink_all_slots(*startup); + assert_eq!( + pubkey_count_after_shrink, + accounts.all_account_count_in_append_vec(shrink_slot) + ); - let no_ancestors = Ancestors::default(); - accounts.update_accounts_hash(current_slot, &no_ancestors); - accounts - .verify_bank_hash_and_lamports(current_slot, &no_ancestors, 22300) - .unwrap(); + let no_ancestors = Ancestors::default(); + accounts.update_accounts_hash(current_slot, &no_ancestors); + accounts + .verify_bank_hash_and_lamports(current_slot, &no_ancestors, 22300) + .unwrap(); - let accounts = reconstruct_accounts_db_via_serialization(&accounts, current_slot); - accounts - .verify_bank_hash_and_lamports(current_slot, &no_ancestors, 22300) - .unwrap(); + let accounts = reconstruct_accounts_db_via_serialization(&accounts, current_slot); + accounts + .verify_bank_hash_and_lamports(current_slot, &no_ancestors, 22300) + .unwrap(); - // repeating should be no-op - accounts.shrink_all_slots(); - assert_eq!( - pubkey_count_after_shrink, - accounts.all_account_count_in_append_vec(shrink_slot) - ); + // repeating should be no-op + accounts.shrink_all_slots(*startup); + assert_eq!( + pubkey_count_after_shrink, + accounts.all_account_count_in_append_vec(shrink_slot) + ); + } } #[test] @@ -8648,7 +8662,7 @@ pub mod tests { ); // Now, do full-shrink. - accounts.shrink_all_slots(); + accounts.shrink_all_slots(false); assert_eq!( pubkey_count_after_shrink, accounts.all_account_count_in_append_vec(shrink_slot) @@ -8708,7 +8722,7 @@ pub mod tests { ); // Now, do full-shrink. - accounts.shrink_all_slots(); + accounts.shrink_all_slots(false); assert_eq!( pubkey_count_after_shrink, accounts.all_account_count_in_append_vec(shrink_slot) @@ -8910,7 +8924,7 @@ pub mod tests { } accounts.add_root(1); accounts.clean_accounts(None); - accounts.shrink_all_slots(); + accounts.shrink_all_slots(false); accounts.print_accounts_stats("post-shrink"); let num_stores = accounts.recycle_stores.read().unwrap().entry_count(); assert!(num_stores > 0); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index e1ad5f433d2386..709d77c7617afb 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -2122,7 +2122,7 @@ impl Bank { clean.stop(); let mut shrink = Measure::start("shrink"); - self.shrink_all_slots(); + self.shrink_all_slots(false); shrink.stop(); info!( @@ -4527,7 +4527,7 @@ impl Bank { let mut shrink_all_slots_time = Measure::start("shrink_all_slots"); if self.slot() > 0 { - self.shrink_all_slots(); + self.shrink_all_slots(true); } shrink_all_slots_time.stop(); @@ -4816,8 +4816,8 @@ impl Bank { self.rc.accounts.accounts_db.clean_accounts(max_clean_slot); } - pub fn shrink_all_slots(&self) { - self.rc.accounts.accounts_db.shrink_all_slots(); + pub fn shrink_all_slots(&self, is_startup: bool) { + self.rc.accounts.accounts_db.shrink_all_slots(is_startup); } pub fn print_accounts_stats(&self) { From f1b4a0a2e0acda1f2e066b17571ee19e2c01bab4 Mon Sep 17 00:00:00 2001 From: Ulrich Stark <8657779+ulrichstark@users.noreply.github.com> Date: Wed, 19 May 2021 19:24:08 +0200 Subject: [PATCH 37/45] Fix typo (#17326) --- docs/src/cli/conventions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/cli/conventions.md b/docs/src/cli/conventions.md index 87521d12d98a31..4c73f21808371e 100644 --- a/docs/src/cli/conventions.md +++ b/docs/src/cli/conventions.md @@ -46,7 +46,7 @@ on your wallet type. #### Paper Wallet In a paper wallet, the keypair is securely derived from the seed words and -optional passphrase you entered when the wallet was create. To use a paper +optional passphrase you entered when the wallet was created. To use a paper wallet keypair anywhere the `` text is shown in examples or help documents, enter the uri scheme `prompt://` and the program will prompt you to enter your seed words when you run the command. From b5302e76198b951e7d4f96fbf5f17e273f209dcd Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" <75863576+jeffwashington@users.noreply.github.com> Date: Wed, 19 May 2021 12:29:41 -0500 Subject: [PATCH 38/45] add calc_stored_meta_us metric (#17318) --- runtime/src/accounts_db.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index 9e694a7a1aa3a5..14a54d194741b8 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -838,6 +838,7 @@ struct AccountsStats { last_store_report: AtomicU64, store_hash_accounts: AtomicU64, + calc_stored_meta: AtomicU64, store_accounts: AtomicU64, store_update_index: AtomicU64, store_handle_reclaims: AtomicU64, @@ -3811,6 +3812,7 @@ impl AccountsDb { mut write_version_producer: P, is_cached_store: bool, ) -> Vec { + let mut calc_stored_meta_time = Measure::start("calc_stored_meta"); let accounts_and_meta_to_store: Vec<_> = accounts .iter() .map(|(pubkey, account)| { @@ -3831,6 +3833,10 @@ impl AccountsDb { (meta, account) }) .collect(); + calc_stored_meta_time.stop(); + self.stats + .calc_stored_meta + .fetch_add(calc_stored_meta_time.as_us(), Ordering::Relaxed); if self.caching_enabled && is_cached_store { self.write_accounts_to_cache(slot, hashes, &accounts_and_meta_to_store) @@ -4754,6 +4760,11 @@ impl AccountsDb { read_only_cache_misses, i64 ), + ( + "calc_stored_meta_us", + self.stats.calc_stored_meta.swap(0, Ordering::Relaxed), + i64 + ), ); let recycle_stores = self.recycle_stores.read().unwrap(); From e7073ecab1ec8db59b2f80e5b42afcdacc74e488 Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Wed, 19 May 2021 19:25:21 +0000 Subject: [PATCH 39/45] adds gossip metrics for number of staked nodes (#17330) --- core/src/cluster_info.rs | 23 ++++++++++++----------- core/src/cluster_info_metrics.rs | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/core/src/cluster_info.rs b/core/src/cluster_info.rs index 5393ef6651b004..78e15fd3adb477 100644 --- a/core/src/cluster_info.rs +++ b/core/src/cluster_info.rs @@ -2564,7 +2564,7 @@ impl ClusterInfo { thread_pool: &ThreadPool, recycler: &PacketsRecycler, response_sender: &PacketSender, - stakes: HashMap, + stakes: &HashMap, feature_set: Option<&FeatureSet>, epoch_time_ms: u64, should_check_duplicate_instance: bool, @@ -2637,13 +2637,13 @@ impl ClusterInfo { self.stats .packets_received_prune_messages_count .add_relaxed(prune_messages.len() as u64); - let require_stake_for_gossip = self.require_stake_for_gossip(feature_set, &stakes); + let require_stake_for_gossip = self.require_stake_for_gossip(feature_set, stakes); if require_stake_for_gossip { for (_, data) in &mut pull_responses { - retain_staked(data, &stakes); + retain_staked(data, stakes); } for (_, data) in &mut push_messages { - retain_staked(data, &stakes); + retain_staked(data, stakes); } pull_responses.retain(|(_, data)| !data.is_empty()); push_messages.retain(|(_, data)| !data.is_empty()); @@ -2654,18 +2654,18 @@ impl ClusterInfo { push_messages, thread_pool, recycler, - &stakes, + stakes, response_sender, require_stake_for_gossip, ); - self.handle_batch_pull_responses(pull_responses, thread_pool, &stakes, epoch_time_ms); - self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, &stakes); + self.handle_batch_pull_responses(pull_responses, thread_pool, stakes, epoch_time_ms); + self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, stakes); self.handle_batch_pong_messages(pong_messages, Instant::now()); self.handle_batch_pull_requests( pull_requests, thread_pool, recycler, - &stakes, + stakes, response_sender, require_stake_for_gossip, ); @@ -2684,6 +2684,7 @@ impl ClusterInfo { should_check_duplicate_instance: bool, ) -> Result<()> { const RECV_TIMEOUT: Duration = Duration::from_secs(1); + const SUBMIT_GOSSIP_STATS_INTERVAL: Duration = Duration::from_secs(2); let packets: Vec<_> = requests_receiver.recv_timeout(RECV_TIMEOUT)?.packets.into(); let mut packets = VecDeque::from(packets); while let Ok(packet) = requests_receiver.try_recv() { @@ -2714,13 +2715,13 @@ impl ClusterInfo { thread_pool, recycler, response_sender, - stakes, + &stakes, feature_set.as_deref(), epoch_time_ms, should_check_duplicate_instance, )?; - if last_print.elapsed().as_millis() > 2000 { - submit_gossip_stats(&self.stats, &self.gossip); + if last_print.elapsed() > SUBMIT_GOSSIP_STATS_INTERVAL { + submit_gossip_stats(&self.stats, &self.gossip, &stakes); *last_print = Instant::now(); } Ok(()) diff --git a/core/src/cluster_info_metrics.rs b/core/src/cluster_info_metrics.rs index 1250824560502c..2bdb5e00c3be1d 100644 --- a/core/src/cluster_info_metrics.rs +++ b/core/src/cluster_info_metrics.rs @@ -1,6 +1,8 @@ use crate::crds_gossip::CrdsGossip; use solana_measure::measure::Measure; +use solana_sdk::pubkey::Pubkey; use std::{ + collections::HashMap, sync::{ atomic::{AtomicU64, Ordering}, RwLock, @@ -116,15 +118,21 @@ pub(crate) struct GossipStats { pub(crate) tvu_peers: Counter, } -pub(crate) fn submit_gossip_stats(stats: &GossipStats, gossip: &RwLock) { - let (table_size, purged_values_size, failed_inserts_size) = { +pub(crate) fn submit_gossip_stats( + stats: &GossipStats, + gossip: &RwLock, + stakes: &HashMap, +) { + let (table_size, num_nodes, purged_values_size, failed_inserts_size) = { let gossip = gossip.read().unwrap(); ( gossip.crds.len(), + gossip.crds.num_nodes(), gossip.pull.purged_values.len(), gossip.pull.failed_inserts.len(), ) }; + let num_nodes_staked = stakes.values().filter(|stake| **stake > 0).count(); datapoint_info!( "cluster_info_stats", ("entrypoint", stats.entrypoint.clear(), i64), @@ -142,6 +150,8 @@ pub(crate) fn submit_gossip_stats(stats: &GossipStats, gossip: &RwLock Date: Wed, 19 May 2021 13:43:59 -0700 Subject: [PATCH 40/45] Optimize aligned memory used by the runtime (#17324) --- Cargo.lock | 4 +- cli/Cargo.toml | 2 +- programs/bpf/Cargo.lock | 4 +- programs/bpf/Cargo.toml | 2 +- programs/bpf_loader/Cargo.toml | 2 +- programs/bpf_loader/benches/serialization.rs | 141 +++++++++++++++++++ programs/bpf_loader/src/lib.rs | 2 +- programs/bpf_loader/src/serialization.rs | 2 +- programs/bpf_loader/src/syscalls.rs | 9 +- 9 files changed, 154 insertions(+), 14 deletions(-) create mode 100644 programs/bpf_loader/benches/serialization.rs diff --git a/Cargo.lock b/Cargo.lock index 2ed71fd23fe318..15f62950c56c04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5508,9 +5508,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e" +checksum = "debbc13545a1d972955a4fd3014e7c9d6d81da16c3626ee5f64bf3aa619548f8" dependencies = [ "byteorder", "combine", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cf8592507e2e8b..33fcc45144bbca 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -38,7 +38,7 @@ solana-config-program = { path = "../programs/config", version = "=1.7.0" } solana-faucet = { path = "../faucet", version = "=1.7.0" } solana-logger = { path = "../logger", version = "=1.7.0" } solana-net-utils = { path = "../net-utils", version = "=1.7.0" } -solana_rbpf = "=0.2.8" +solana_rbpf = "=0.2.9" solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" } solana-sdk = { path = "../sdk", version = "=1.7.0" } solana-stake-program = { path = "../programs/stake", version = "=1.7.0" } diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 9e73d4a6c07128..51a64075a5b371 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -3637,9 +3637,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e" +checksum = "debbc13545a1d972955a4fd3014e7c9d6d81da16c3626ee5f64bf3aa619548f8" dependencies = [ "byteorder 1.3.4", "combine", diff --git a/programs/bpf/Cargo.toml b/programs/bpf/Cargo.toml index 284c28b490a23c..d2138569c5f74d 100644 --- a/programs/bpf/Cargo.toml +++ b/programs/bpf/Cargo.toml @@ -30,7 +30,7 @@ solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.7.0" } solana-cli-output = { path = "../../cli-output", version = "=1.7.0" } solana-logger = { path = "../../logger", version = "=1.7.0" } solana-measure = { path = "../../measure", version = "=1.7.0" } -solana_rbpf = "=0.2.8" +solana_rbpf = "=0.2.9" solana-runtime = { path = "../../runtime", version = "=1.7.0" } solana-sdk = { path = "../../sdk", version = "=1.7.0" } solana-transaction-status = { path = "../../transaction-status", version = "=1.7.0" } diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index a2c0515f123387..c8b3400254642f 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -20,7 +20,7 @@ sha3 = "0.9.1" solana-measure = { path = "../../measure", version = "=1.7.0" } solana-runtime = { path = "../../runtime", version = "=1.7.0" } solana-sdk = { path = "../../sdk", version = "=1.7.0" } -solana_rbpf = "=0.2.8" +solana_rbpf = "=0.2.9" thiserror = "1.0" [dev-dependencies] diff --git a/programs/bpf_loader/benches/serialization.rs b/programs/bpf_loader/benches/serialization.rs new file mode 100644 index 00000000000000..e99c953b496d4d --- /dev/null +++ b/programs/bpf_loader/benches/serialization.rs @@ -0,0 +1,141 @@ +#![feature(test)] + +extern crate test; + +use solana_bpf_loader_program::serialization::{ + serialize_parameters_aligned, serialize_parameters_unaligned, +}; +use solana_sdk::{ + account::{Account, AccountSharedData}, + bpf_loader, +}; +use solana_sdk::{keyed_account::KeyedAccount, pubkey::Pubkey}; +use std::cell::RefCell; +use test::Bencher; + +fn create_inputs() -> ( + Pubkey, + Vec, + Vec>, + Vec, +) { + let program_id = solana_sdk::pubkey::new_rand(); + let dup_key = solana_sdk::pubkey::new_rand(); + let dup_key2 = solana_sdk::pubkey::new_rand(); + let keys = vec![ + dup_key, + dup_key, + solana_sdk::pubkey::new_rand(), + solana_sdk::pubkey::new_rand(), + dup_key2, + dup_key2, + solana_sdk::pubkey::new_rand(), + solana_sdk::pubkey::new_rand(), + ]; + let accounts = vec![ + RefCell::new(AccountSharedData::from(Account { + lamports: 1, + data: vec![1u8, 2, 3, 4, 5], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 100, + })), + // dup + RefCell::new(AccountSharedData::from(Account { + lamports: 1, + data: vec![1u8; 100000], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 100, + })), + RefCell::new(AccountSharedData::from(Account { + lamports: 2, + data: vec![11u8; 100000], + owner: bpf_loader::id(), + executable: true, + rent_epoch: 200, + })), + RefCell::new(AccountSharedData::from(Account { + lamports: 3, + data: vec![], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 3100, + })), + RefCell::new(AccountSharedData::from(Account { + lamports: 4, + data: vec![1u8; 100000], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 100, + })), + // dup + RefCell::new(AccountSharedData::from(Account { + lamports: 4, + data: vec![1u8; 1000000], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 100, + })), + RefCell::new(AccountSharedData::from(Account { + lamports: 5, + data: vec![11u8; 10000], + owner: bpf_loader::id(), + executable: true, + rent_epoch: 200, + })), + RefCell::new(AccountSharedData::from(Account { + lamports: 6, + data: vec![], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 3100, + })), + ]; + + let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + + (program_id, keys, accounts, instruction_data) +} + +#[bench] +fn bench_serialize_unaligned(bencher: &mut Bencher) { + let (program_id, keys, accounts, instruction_data) = create_inputs(); + let keyed_accounts: Vec<_> = keys + .iter() + .zip(&accounts) + .enumerate() + .map(|(i, (key, account))| { + if i <= accounts.len() / 2 { + KeyedAccount::new_readonly(&key, false, &account) + } else { + KeyedAccount::new(&key, false, &account) + } + }) + .collect(); + bencher.iter(|| { + let _ = serialize_parameters_unaligned(&program_id, &keyed_accounts, &instruction_data) + .unwrap(); + }); +} + +#[bench] +fn bench_serialize_aligned(bencher: &mut Bencher) { + let (program_id, keys, accounts, instruction_data) = create_inputs(); + let keyed_accounts: Vec<_> = keys + .iter() + .zip(&accounts) + .enumerate() + .map(|(i, (key, account))| { + if i <= accounts.len() / 2 { + KeyedAccount::new_readonly(&key, false, &account) + } else { + KeyedAccount::new(&key, false, &account) + } + }) + .collect(); + bencher.iter(|| { + let _ = + serialize_parameters_aligned(&program_id, &keyed_accounts, &instruction_data).unwrap(); + }); +} diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 5b0ef1af7fab3d..864440ebe5e638 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -148,7 +148,7 @@ pub fn create_vm<'a>( parameter_bytes: &mut [u8], invoke_context: &'a mut dyn InvokeContext, ) -> Result, EbpfError> { - let heap = AlignedMemory::new(DEFAULT_HEAP_SIZE, HOST_ALIGN); + let heap = AlignedMemory::new_with_size(DEFAULT_HEAP_SIZE, HOST_ALIGN); let heap_region = MemoryRegion::new_from_slice(heap.as_slice(), MM_HEAP_START, 0, true); let mut vm = EbpfVm::new(program, parameter_bytes, &[heap_region])?; syscalls::bind_syscall_context_objects(loader_id, &mut vm, invoke_context, heap)?; diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 79b8564a39d1d0..31683274e5950b 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -231,7 +231,7 @@ pub fn serialize_parameters_aligned( .map_err(|_| InstructionError::InvalidArgument)?; v.write_all(&keyed_account.try_account_ref()?.data()) .map_err(|_| InstructionError::InvalidArgument)?; - v.fill( + v.resize( MAX_PERMITTED_DATA_INCREASE + (v.write_index() as *const u8).align_offset(align_of::()), 0, diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 456c400f27433c..31325ed8d008b5 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -2689,7 +2689,7 @@ mod tests { fn test_syscall_sol_alloc_free() { // large alloc { - let heap = AlignedMemory::new(100, HOST_ALIGN); + let heap = AlignedMemory::new_with_size(100, HOST_ALIGN); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion::new_from_slice( heap.as_slice(), @@ -2716,7 +2716,7 @@ mod tests { } // many small unaligned allocs { - let heap = AlignedMemory::new(100, HOST_ALIGN); + let heap = AlignedMemory::new_with_size(100, HOST_ALIGN); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion::new_from_slice( heap.as_slice(), @@ -2742,7 +2742,7 @@ mod tests { } // many small aligned allocs { - let heap = AlignedMemory::new(100, HOST_ALIGN); + let heap = AlignedMemory::new_with_size(100, HOST_ALIGN); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion::new_from_slice( heap.as_slice(), @@ -2769,7 +2769,7 @@ mod tests { // aligned allocs fn check_alignment() { - let heap = AlignedMemory::new(100, HOST_ALIGN); + let heap = AlignedMemory::new_with_size(100, HOST_ALIGN); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion::new_from_slice( heap.as_slice(), @@ -2810,7 +2810,6 @@ mod tests { let bytes1 = "Gaggablaghblagh!"; let bytes2 = "flurbos"; - // lint warns field addr and len "never read" #[allow(dead_code)] struct MockSlice { pub addr: u64, From 13b032b2d4a1d7bf846d1355337edcaf3ba4b5c7 Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Wed, 19 May 2021 20:56:10 +0000 Subject: [PATCH 41/45] removes manual trait impl for contact-info (#17332) The current implementations use only the id and disregard other fields, in particular wallclock. This can lead to bugs where an outdated contact-info shadows or overrides a current one because they compare equal. --- core/src/contact_info.rs | 26 ++--------------------- core/src/crds.rs | 4 +--- core/src/crds_gossip_push.rs | 40 ++++++++++++++++-------------------- 3 files changed, 21 insertions(+), 49 deletions(-) diff --git a/core/src/contact_info.rs b/core/src/contact_info.rs index 59c4179937a712..eafaf636ba3d59 100644 --- a/core/src/contact_info.rs +++ b/core/src/contact_info.rs @@ -6,11 +6,10 @@ use solana_sdk::sanitize::{Sanitize, SanitizeError}; #[cfg(test)] use solana_sdk::signature::{Keypair, Signer}; use solana_sdk::timing::timestamp; -use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; use std::net::{IpAddr, SocketAddr}; /// Structure representing a node on the network -#[derive(Serialize, Deserialize, Clone, Debug, AbiExample)] +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, AbiExample, Deserialize, Serialize)] pub struct ContactInfo { pub id: Pubkey, /// gossip address @@ -48,34 +47,13 @@ impl Sanitize for ContactInfo { } } -impl Ord for ContactInfo { - fn cmp(&self, other: &Self) -> Ordering { - self.id.cmp(&other.id) - } -} - -impl PartialOrd for ContactInfo { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for ContactInfo { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -impl Eq for ContactInfo {} - #[macro_export] macro_rules! socketaddr { ($ip:expr, $port:expr) => { std::net::SocketAddr::from((std::net::Ipv4Addr::from($ip), $port)) }; ($str:expr) => {{ - let a: std::net::SocketAddr = $str.parse().unwrap(); - a + $str.parse::().unwrap() }}; } #[macro_export] diff --git a/core/src/crds.rs b/core/src/crds.rs index 4af80a7e5426c1..c5e231ae30f296 100644 --- a/core/src/crds.rs +++ b/core/src/crds.rs @@ -19,7 +19,7 @@ //! CrdsValue enums. //! //! Merge strategy is implemented in: -//! impl PartialOrd for VersionedCrdsValue +//! fn overrides(value: &CrdsValue, other: &VersionedCrdsValue) -> bool //! //! A value is updated to a new version if the labels match, and the value //! wallclock is later, or the value hash is greater. @@ -66,8 +66,6 @@ pub enum CrdsError { } /// This structure stores some local metadata associated with the CrdsValue -/// The implementation of PartialOrd ensures that the "highest" version is always picked to be -/// stored in the Crds #[derive(PartialEq, Debug, Clone)] pub struct VersionedCrdsValue { /// Ordinal index indicating insert order. diff --git a/core/src/crds_gossip_push.rs b/core/src/crds_gossip_push.rs index 7cf01776c11810..f0b3b95e85e451 100644 --- a/core/src/crds_gossip_push.rs +++ b/core/src/crds_gossip_push.rs @@ -753,36 +753,32 @@ mod test { #[test] fn test_personalized_push_messages() { let now = timestamp(); + let mut rng = rand::thread_rng(); let mut crds = Crds::default(); let mut push = CrdsGossipPush::default(); - let peer_1 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - assert_eq!(crds.insert(peer_1.clone(), now), Ok(None)); - let peer_2 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - assert_eq!(crds.insert(peer_2.clone(), now), Ok(None)); - let peer_3 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - now, - ))); + let peers: Vec<_> = vec![0, 0, now] + .into_iter() + .map(|wallclock| { + let mut peer = ContactInfo::new_rand(&mut rng, /*pubkey=*/ None); + peer.wallclock = wallclock; + CrdsValue::new_unsigned(CrdsData::ContactInfo(peer)) + }) + .collect(); + assert_eq!(crds.insert(peers[0].clone(), now), Ok(None)); + assert_eq!(crds.insert(peers[1].clone(), now), Ok(None)); assert_eq!( - push.process_push_message(&mut crds, &Pubkey::default(), peer_3.clone(), now), + push.process_push_message(&mut crds, &Pubkey::default(), peers[2].clone(), now), Ok(None) ); push.refresh_push_active_set(&crds, &HashMap::new(), None, &Pubkey::default(), 0, 1, 1); // push 3's contact info to 1 and 2 and 3 - let new_msg = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &peer_3.pubkey(), - 0, - ))); - let mut expected = HashMap::new(); - expected.insert(peer_1.pubkey(), vec![new_msg.clone()]); - expected.insert(peer_2.pubkey(), vec![new_msg]); + let expected: HashMap<_, _> = vec![ + (peers[0].pubkey(), vec![peers[2].clone()]), + (peers[1].pubkey(), vec![peers[2].clone()]), + ] + .into_iter() + .collect(); assert_eq!(push.active_set.len(), 3); assert_eq!(push.new_push_messages(&crds, now), expected); } From 32ec8341f9fe1328a1ca4de518bde1c11a379656 Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" <75863576+jeffwashington@users.noreply.github.com> Date: Wed, 19 May 2021 16:21:24 -0500 Subject: [PATCH 42/45] generate_index inserts ideal initial data (#17247) * improve insert into map initially * rework towards single code path * rename * update test --- runtime/src/accounts_index.rs | 244 +++++++++++++++++++++++++++------- 1 file changed, 197 insertions(+), 47 deletions(-) diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index 76761a44f1e9c1..75fddab6d4fe90 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -179,6 +179,18 @@ impl WriteAccountMapEntry { &self.borrow_owned_entry_contents().ref_count } + // create an entry that is equivalent to this process: + // 1. new empty (refcount=0, slot_list={}) + // 2. update(slot, account_info) + // This code is called when the first entry [ie. (slot,account_info)] for a pubkey is inserted into the index. + pub fn new_entry_after_update(slot: Slot, account_info: &T) -> AccountMapEntry { + let ref_count = if account_info.is_cached() { 0 } else { 1 }; + Arc::new(AccountMapEntryInner { + ref_count: AtomicU64::new(ref_count), + slot_list: RwLock::new(vec![(slot, account_info.clone())]), + }) + } + // Try to update an item in the slot list the given `slot` If an item for the slot // already exists in the list, remove the older item, add it to `reclaims`, and insert // the new item. @@ -496,7 +508,7 @@ pub trait ZeroLamport { } type MapType = AccountMap>; -type ReadWriteLockMapType<'a, T> = RwLockWriteGuard<'a, AccountMap>>; +type AccountMapsWriteLock<'a, T> = RwLockWriteGuard<'a, AccountMap>>; #[derive(Debug)] pub struct AccountsIndex { @@ -842,47 +854,55 @@ impl AccountsIndex { .map(WriteAccountMapEntry::from_account_map_entry) } - fn new_entry() -> AccountMapEntry { - Arc::new(AccountMapEntryInner { - ref_count: AtomicU64::new(0), - slot_list: RwLock::new(SlotList::with_capacity(1)), - }) - } - - fn insert_new_entry_if_missing(&self, pubkey: &Pubkey) -> (WriteAccountMapEntry, bool) { - let new_entry = Self::new_entry(); - let mut w_account_maps = self.get_account_maps_write_lock(); - self.insert_new_entry_if_missing_with_lock(pubkey, &mut w_account_maps, new_entry) + fn insert_new_entry_if_missing( + &self, + pubkey: &Pubkey, + slot: Slot, + info: &T, + w_account_maps: Option<&mut AccountMapsWriteLock>, + ) -> Option> { + let new_entry = WriteAccountMapEntry::new_entry_after_update(slot, info); + match w_account_maps { + Some(w_account_maps) => { + self.insert_new_entry_if_missing_with_lock(pubkey, w_account_maps, new_entry) + } + None => { + let mut w_account_maps = self.get_account_maps_write_lock(); + self.insert_new_entry_if_missing_with_lock(pubkey, &mut w_account_maps, new_entry) + } + } } + // return None if item was created new + // if entry for pubkey already existed, return Some(entry). Caller needs to call entry.update. fn insert_new_entry_if_missing_with_lock( &self, pubkey: &Pubkey, - w_account_maps: &mut ReadWriteLockMapType, + w_account_maps: &mut AccountMapsWriteLock, new_entry: AccountMapEntry, - ) -> (WriteAccountMapEntry, bool) { + ) -> Option> { let mut is_newly_inserted = false; let account_entry = w_account_maps.entry(*pubkey).or_insert_with(|| { is_newly_inserted = true; new_entry }); - let w_account_entry = WriteAccountMapEntry::from_account_map_entry(account_entry.clone()); - (w_account_entry, is_newly_inserted) + if is_newly_inserted { + None + } else { + Some(WriteAccountMapEntry::from_account_map_entry( + account_entry.clone(), + )) + } } fn get_account_write_entry_else_create( &self, pubkey: &Pubkey, - ) -> (WriteAccountMapEntry, bool) { - let mut w_account_entry = self.get_account_write_entry(pubkey); - let mut is_newly_inserted = false; - if w_account_entry.is_none() { - let entry_is_new = self.insert_new_entry_if_missing(pubkey); - w_account_entry = Some(entry_is_new.0); - is_newly_inserted = entry_is_new.1; - } - - (w_account_entry.unwrap(), is_newly_inserted) + slot: Slot, + info: &T, + ) -> Option> { + let w_account_entry = self.get_account_write_entry(pubkey); + w_account_entry.or_else(|| self.insert_new_entry_if_missing(pubkey, slot, info, None)) } pub fn handle_dead_keys( @@ -1159,7 +1179,7 @@ impl AccountsIndex { } } - pub(crate) fn get_account_maps_write_lock(&self) -> ReadWriteLockMapType { + pub(crate) fn get_account_maps_write_lock(&self) -> AccountMapsWriteLock { self.account_maps.write().unwrap() } @@ -1173,15 +1193,16 @@ impl AccountsIndex { pubkey: &Pubkey, account_info: T, reclaims: &mut SlotList, - w_account_maps: &mut ReadWriteLockMapType, + w_account_maps: &mut AccountMapsWriteLock, ) { - let new_entry = Self::new_entry(); - let (mut w_account_entry, _is_new) = - self.insert_new_entry_if_missing_with_lock(pubkey, w_account_maps, new_entry); + let account_entry = + self.insert_new_entry_if_missing(pubkey, slot, &account_info, Some(w_account_maps)); if account_info.is_zero_lamport() { self.zero_lamport_pubkeys.insert(*pubkey); } - w_account_entry.update(slot, account_info, reclaims); + if let Some(mut w_account_entry) = account_entry { + w_account_entry.update(slot, account_info, reclaims); + } } // Updates the given pubkey at the given slot with the new account information. @@ -1198,8 +1219,8 @@ impl AccountsIndex { reclaims: &mut SlotList, ) -> bool { let is_newly_inserted = { - let (mut w_account_entry, is_newly_inserted) = - self.get_account_write_entry_else_create(pubkey); + let w_account_entry = + self.get_account_write_entry_else_create(pubkey, slot, &account_info); // We don't atomically update both primary index and secondary index together. // This certainly creates small time window with inconsistent state across the two indexes. // However, this is acceptable because: @@ -1214,8 +1235,12 @@ impl AccountsIndex { if account_info.is_zero_lamport() { self.zero_lamport_pubkeys.insert(*pubkey); } - w_account_entry.update(slot, account_info, reclaims); - is_newly_inserted + if let Some(mut w_account_entry) = w_account_entry { + w_account_entry.update(slot, account_info, reclaims); + false + } else { + true + } }; self.update_secondary_indexes(pubkey, account_owner, account_data, account_indexes); is_newly_inserted @@ -2269,29 +2294,154 @@ pub mod tests { assert_eq!(num, 1); } + #[test] + fn test_new_entry() { + let slot = 0; + // account_info type that IS cached + let account_info = AccountInfoTest::default(); + + let new_entry = WriteAccountMapEntry::new_entry_after_update(slot, &account_info); + assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 0); + assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1); + assert_eq!( + new_entry.slot_list.read().unwrap().to_vec(), + vec![(slot, account_info)] + ); + + // account_info type that is NOT cached + let account_info = true; + + let new_entry = WriteAccountMapEntry::new_entry_after_update(slot, &account_info); + assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 1); + assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1); + assert_eq!( + new_entry.slot_list.read().unwrap().to_vec(), + vec![(slot, account_info)] + ); + } + + fn test_new_entry_code_paths_helper< + T: 'static + Clone + IsCached + ZeroLamport + std::cmp::PartialEq + std::fmt::Debug, + >( + account_infos: [T; 2], + is_cached: bool, + upsert: bool, + ) { + let slot0 = 0; + let slot1 = 1; + let key = Keypair::new().pubkey(); + + let index = AccountsIndex::::default(); + let mut gc = Vec::new(); + + if upsert { + // insert first entry for pubkey. This will use new_entry_after_update and not call update. + index.upsert( + slot0, + &key, + &Pubkey::default(), + &[], + &AccountSecondaryIndexes::default(), + account_infos[0].clone(), + &mut gc, + ); + } else { + let mut lock = index.get_account_maps_write_lock(); + index.insert_new_if_missing_into_primary_index( + slot0, + &key, + account_infos[0].clone(), + &mut gc, + &mut lock, + ); + } + assert!(gc.is_empty()); + + // verify the added entry matches expected + { + let entry = index.get_account_read_entry(&key).unwrap(); + assert_eq!( + entry.ref_count().load(Ordering::Relaxed), + if is_cached { 0 } else { 1 } + ); + let expected = vec![(slot0, account_infos[0].clone())]; + assert_eq!(entry.slot_list().to_vec(), expected); + let new_entry = WriteAccountMapEntry::new_entry_after_update(slot0, &account_infos[0]); + assert_eq!( + entry.slot_list().to_vec(), + new_entry.slot_list.read().unwrap().to_vec(), + ); + } + + // insert second entry for pubkey. This will use update and NOT use new_entry_after_update. + if upsert { + index.upsert( + slot1, + &key, + &Pubkey::default(), + &[], + &AccountSecondaryIndexes::default(), + account_infos[1].clone(), + &mut gc, + ); + } else { + let mut lock = index.get_account_maps_write_lock(); + index.insert_new_if_missing_into_primary_index( + slot1, + &key, + account_infos[1].clone(), + &mut gc, + &mut lock, + ); + } + assert!(gc.is_empty()); + + { + let entry = index.get_account_read_entry(&key).unwrap(); + assert_eq!( + entry.ref_count().load(Ordering::Relaxed), + if is_cached { 0 } else { 2 } + ); + assert_eq!( + entry.slot_list().to_vec(), + vec![ + (slot0, account_infos[0].clone()), + (slot1, account_infos[1].clone()) + ] + ); + + let new_entry = WriteAccountMapEntry::new_entry_after_update(slot1, &account_infos[1]); + assert_eq!(entry.slot_list()[1], new_entry.slot_list.read().unwrap()[0],); + } + } + + #[test] + fn test_new_entry_and_update_code_paths() { + for is_upsert in &[false, true] { + // account_info type that IS cached + test_new_entry_code_paths_helper([1.0, 2.0], true, *is_upsert); + + // account_info type that is NOT cached + test_new_entry_code_paths_helper([true, false], false, *is_upsert); + } + } + #[test] fn test_insert_with_lock_no_ancestors() { let key = Keypair::new(); let index = AccountsIndex::::default(); - let mut gc = Vec::new(); let slot = 0; + let account_info = true; - let new_entry = AccountsIndex::new_entry(); - assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 0); - assert!(new_entry.slot_list.read().unwrap().is_empty()); - assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1); + let new_entry = WriteAccountMapEntry::new_entry_after_update(slot, &account_info); let mut w_account_maps = index.get_account_maps_write_lock(); - let (mut write, insert) = index.insert_new_entry_if_missing_with_lock( + let write = index.insert_new_entry_if_missing_with_lock( &key.pubkey(), &mut w_account_maps, new_entry, ); - assert!(insert); + assert!(write.is_none()); drop(w_account_maps); - let account_info = true; - write.update(slot, account_info, &mut gc); - assert!(gc.is_empty()); - drop(write); let mut ancestors = Ancestors::default(); assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none()); From a544010b03d2aa69a953c957b68837b32fa6a5da Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" <75863576+jeffwashington@users.noreply.github.com> Date: Wed, 19 May 2021 19:15:35 -0500 Subject: [PATCH 43/45] don't log shrink metrics on first call (#17328) * don't log shrink metrics on first call * simplify logic --- runtime/src/accounts_db.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index 14a54d194741b8..0be550a69a1207 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -1057,13 +1057,17 @@ impl ShrinkStats { let last = self.last_report.load(Ordering::Relaxed); let now = solana_sdk::timing::timestamp(); + // last is initialized to 0 by ::default() + // thus, the first 'report' call would always log. + // Instead, the first call now initialializes 'last_report' to now. + let is_first_call = last == 0; let should_report = now.saturating_sub(last) > 1000 && self .last_report .compare_exchange(last, now, Ordering::Relaxed, Ordering::Relaxed) == Ok(last); - if should_report { + if !is_first_call && should_report { datapoint_info!( "shrink_stats", ( From 2ae57c172a71d0914e650791259a7ba099bea1e5 Mon Sep 17 00:00:00 2001 From: Dmitri Makarov Date: Tue, 18 May 2021 19:44:36 +0200 Subject: [PATCH 44/45] Bump bpf-tools version to 1.9 - upgrade rustc to 1.52.1 and clang to 12.0 --- programs/bpf/tests/programs.rs | 30 +++++++++++++++--------------- sdk/bpf/scripts/install.sh | 2 +- sdk/cargo-build-bpf/src/main.rs | 2 +- sdk/program/src/hash.rs | 2 +- sdk/program/src/keccak.rs | 2 +- sdk/program/src/pubkey.rs | 6 +++--- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 7dd5244640991d..9bbfabd885d98b 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1244,11 +1244,11 @@ fn assert_instruction_count() { ("alloc", 1137), ("bpf_to_bpf", 13), ("multiple_static", 8), - ("noop", 45), - ("noop++", 45), + ("noop", 5), + ("noop++", 5), ("relative_call", 10), - ("sanity", 175), - ("sanity++", 177), + ("sanity", 169), + ("sanity++", 168), ("sha", 694), ("struct_pass", 8), ("struct_ret", 22), @@ -1257,19 +1257,19 @@ fn assert_instruction_count() { #[cfg(feature = "bpf_rust")] { programs.extend_from_slice(&[ - ("solana_bpf_rust_128bit", 572), - ("solana_bpf_rust_alloc", 8906), - ("solana_bpf_rust_custom_heap", 516), + ("solana_bpf_rust_128bit", 584), + ("solana_bpf_rust_alloc", 4967), + ("solana_bpf_rust_custom_heap", 365), ("solana_bpf_rust_dep_crate", 2), - ("solana_bpf_rust_external_spend", 498), - ("solana_bpf_rust_iter", 724), - ("solana_bpf_rust_many_args", 237), - ("solana_bpf_rust_mem", 2297), - ("solana_bpf_rust_noop", 472), + ("solana_bpf_rust_external_spend", 334), + ("solana_bpf_rust_iter", 8), + ("solana_bpf_rust_many_args", 189), + ("solana_bpf_rust_mem", 1665), + ("solana_bpf_rust_noop", 322), ("solana_bpf_rust_param_passing", 46), - ("solana_bpf_rust_rand", 475), - ("solana_bpf_rust_sanity", 894), - ("solana_bpf_rust_sha", 29099), + ("solana_bpf_rust_rand", 325), + ("solana_bpf_rust_sanity", 587), + ("solana_bpf_rust_sha", 22417), ]); } diff --git a/sdk/bpf/scripts/install.sh b/sdk/bpf/scripts/install.sh index 2da6710be9b891..7bbabff3b35364 100755 --- a/sdk/bpf/scripts/install.sh +++ b/sdk/bpf/scripts/install.sh @@ -92,7 +92,7 @@ if [[ ! -e criterion-$version.md || ! -e criterion ]]; then fi # Install Rust-BPF -version=v1.8 +version=v1.9 if [[ ! -e bpf-tools-$version.md || ! -e bpf-tools ]]; then ( set -e diff --git a/sdk/cargo-build-bpf/src/main.rs b/sdk/cargo-build-bpf/src/main.rs index 0677517f7a2910..c60d1b7d7adced 100644 --- a/sdk/cargo-build-bpf/src/main.rs +++ b/sdk/cargo-build-bpf/src/main.rs @@ -360,7 +360,7 @@ fn build_bpf_package(config: &Config, target_directory: &Path, package: &cargo_m install_if_missing( &config, "bpf-tools", - "v1.8", + "v1.9", "https://github.com/solana-labs/bpf-tools/releases/download", &PathBuf::from(bpf_tools_filename), ) diff --git a/sdk/program/src/hash.rs b/sdk/program/src/hash.rs index cce0113ffd2c15..e39add147db6aa 100644 --- a/sdk/program/src/hash.rs +++ b/sdk/program/src/hash.rs @@ -135,7 +135,7 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { { extern "C" { fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64; - }; + } let mut hash_result = [0; HASH_BYTES]; unsafe { sol_sha256( diff --git a/sdk/program/src/keccak.rs b/sdk/program/src/keccak.rs index ab0572b2fa291f..b3df920f15008a 100644 --- a/sdk/program/src/keccak.rs +++ b/sdk/program/src/keccak.rs @@ -133,7 +133,7 @@ pub fn hashv(vals: &[&[u8]]) -> Hash { { extern "C" { fn sol_keccak256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64; - }; + } let mut hash_result = [0; HASH_BYTES]; unsafe { sol_keccak256( diff --git a/sdk/program/src/pubkey.rs b/sdk/program/src/pubkey.rs index 8718223bbccf04..eade06d999249b 100644 --- a/sdk/program/src/pubkey.rs +++ b/sdk/program/src/pubkey.rs @@ -227,7 +227,7 @@ impl Pubkey { program_id_addr: *const u8, address_bytes_addr: *const u8, ) -> u64; - }; + } let mut bytes = [0; 32]; let result = unsafe { sol_create_program_address( @@ -309,7 +309,7 @@ impl Pubkey { address_bytes_addr: *const u8, bump_seed_addr: *const u8, ) -> u64; - }; + } let mut bytes = [0; 32]; let mut bump_seed = std::u8::MAX; let result = unsafe { @@ -342,7 +342,7 @@ impl Pubkey { { extern "C" { fn sol_log_pubkey(pubkey_addr: *const u8); - }; + } unsafe { sol_log_pubkey(self.as_ref() as *const _ as *const u8) }; } From abe0064e4093fd4eb8da764ed88c7a8a0e522e71 Mon Sep 17 00:00:00 2001 From: "Frank V. Castellucci" Date: Thu, 20 May 2021 07:39:37 -0400 Subject: [PATCH 45/45] syscall corrections --- programs/bpf_loader/src/syscalls.rs | 43 ++++++++--------------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index b1c8185a975359..f46afe9f5cbea5 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -177,18 +177,11 @@ pub fn register_syscalls( .register_syscall_by_name(b"sol_invoke_signed_rust", SyscallInvokeSignedRust::call)?; syscall_registry.register_syscall_by_name(b"sol_alloc_free_", SyscallAllocFree::call)?; - // Bignum syscall names - // syscall_registry.register_syscall_by_name(b"sol_bignum_new", SyscallBigNumNew::call)?; - // syscall_registry - // .register_syscall_by_name(b"sol_bignum_size_in_bytes", SyscallBigNumSizeInBytes::call)?; syscall_registry .register_syscall_by_name(b"sol_bignum_from_u32", SyscallBigNumFromU32::call)?; syscall_registry .register_syscall_by_name(b"sol_bignum_from_dec_str", SyscallBigNumFromDecStr::call)?; - // syscall_registry - // .register_syscall_by_name(b"sol_bignum_to_bytes", SyscallBigNumToBytes::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_mod_exp", SyscallBigNumModExp::call)?; - // syscall_registry.register_syscall_by_name(b"sol_bignum_drop", SyscallBigNumDrop::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_log", SyscallBigNumLog::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_add", SyscallBigNumAdd::call)?; syscall_registry.register_syscall_by_name(b"sol_bignum_sub", SyscallBigNumSub::call)?; @@ -306,23 +299,17 @@ pub fn bind_syscall_context_objects<'a>( None, )?; - // Bignum bindings - // vm.bind_syscall_context_object( - // Box::new(SyscallBigNumNew { - // cost: bpf_compute_budget.bignum_new_base_cost, - // compute_meter: invoke_context.get_compute_meter(), - // loader_id, - // }), - // None, - // )?; - // vm.bind_syscall_context_object( - // Box::new(SyscallBigNumSizeInBytes { - // cost: bpf_compute_budget.bignum_size_base_cost, - // compute_meter: invoke_context.get_compute_meter(), - // loader_id, - // }), - // None, - // )?; + bind_feature_gated_syscall_context_object!( + vm, + invoke_context.is_feature_active(&keccak256_syscall_enabled::id()), + Box::new(SyscallKeccak256 { + base_cost: bpf_compute_budget.sha256_base_cost, + byte_cost: bpf_compute_budget.sha256_byte_cost, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + ); + vm.bind_syscall_context_object( Box::new(SyscallBigNumFromU32 { cost: bpf_compute_budget.bignum_from_u32_base_cost, @@ -339,14 +326,6 @@ pub fn bind_syscall_context_objects<'a>( }), None, )?; - // vm.bind_syscall_context_object( - // Box::new(SyscallBigNumToBytes { - // cost: bpf_compute_budget.bignum_to_bytes_base_cost, - // compute_meter: invoke_context.get_compute_meter(), - // loader_id, - // }), - // None, - // )?; vm.bind_syscall_context_object( Box::new(SyscallBigNumModExp {