From 5f7fea100a0715772dd5acd8c460d6b1f875240c Mon Sep 17 00:00:00 2001 From: valiksinev <101261445+valiksinev@users.noreply.github.com> Date: Fri, 20 Jan 2023 12:42:37 +0300 Subject: [PATCH] Big integer modular exponentiation (EIP-198) (#28503) * big_mod_exp impl * fix programs/sbf/Cargo.lock * ComputeBudget impl * update compute_budget * compute_budget update * fix build * fix tests * fix cargo clippy * fix clippy * fix bpf_loader dependency sorting * fix sorting * fix merge from master * fix cargo fmt * fix C-tests * fix cargo fmt * comments apply * fix programs/sbf/Cargo.lock * update compude_budget cost * remove whitespaces * fix cargo fmt Co-authored-by: sinev-valentine --- Cargo.lock | 1 + program-runtime/src/compute_budget.rs | 3 + programs/bpf_loader/src/syscalls/mod.rs | 86 ++++++++++- programs/sbf/Cargo.lock | 11 ++ programs/sbf/Cargo.toml | 1 + programs/sbf/build.rs | 1 + programs/sbf/c/src/big_mod_exp/big_mod_exp.c | 49 +++++++ programs/sbf/rust/big_mod_exp/Cargo.toml | 22 +++ programs/sbf/rust/big_mod_exp/src/lib.rs | 93 ++++++++++++ sdk/bpf/c/inc/sol/big_mod_exp.h | 32 +++++ sdk/bpf/c/inc/sol/inc/big_mod_exp.inc | 23 +++ sdk/bpf/c/inc/solana_sdk.h | 1 + sdk/program/Cargo.toml | 1 + sdk/program/src/big_mod_exp.rs | 141 +++++++++++++++++++ sdk/program/src/lib.rs | 1 + sdk/program/src/syscalls/definitions.rs | 1 + sdk/sbf/c/inc/sol/big_mod_exp.h | 32 +++++ sdk/sbf/c/inc/sol/inc/big_mod_exp.inc | 23 +++ sdk/sbf/c/inc/solana_sdk.h | 1 + sdk/src/feature_set.rs | 5 + sdk/src/lib.rs | 2 +- 21 files changed, 528 insertions(+), 2 deletions(-) create mode 100644 programs/sbf/c/src/big_mod_exp/big_mod_exp.c create mode 100644 programs/sbf/rust/big_mod_exp/Cargo.toml create mode 100644 programs/sbf/rust/big_mod_exp/src/lib.rs create mode 100644 sdk/bpf/c/inc/sol/big_mod_exp.h create mode 100644 sdk/bpf/c/inc/sol/inc/big_mod_exp.inc create mode 100644 sdk/program/src/big_mod_exp.rs create mode 100644 sdk/sbf/c/inc/sol/big_mod_exp.h create mode 100644 sdk/sbf/c/inc/sol/inc/big_mod_exp.inc diff --git a/Cargo.lock b/Cargo.lock index 9db16d1eb8..a6b82eecf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5986,6 +5986,7 @@ dependencies = [ "libsecp256k1", "log", "memoffset", + "num-bigint 0.4.3", "num-derive", "num-traits", "parking_lot 0.12.1", diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 30ebed1de5..51e3c1e5ac 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -107,6 +107,8 @@ pub struct ComputeBudget { /// + alt_bn128_pairing_one_pair_cost_other * (num_elems - 1) pub alt_bn128_pairing_one_pair_cost_first: u64, pub alt_bn128_pairing_one_pair_cost_other: u64, + /// Big integer modular exponentiation cost + pub big_modular_exponentiation_cost: u64, } impl Default for ComputeBudget { @@ -154,6 +156,7 @@ impl ComputeBudget { alt_bn128_multiplication_cost: 3_840, alt_bn128_pairing_one_pair_cost_first: 36_364, alt_bn128_pairing_one_pair_cost_other: 12_121, + big_modular_exponentiation_cost: 33, } } diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 6176fdbb6a..c163089790 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -29,13 +29,14 @@ use { ALT_BN128_ADDITION_OUTPUT_LEN, ALT_BN128_MULTIPLICATION_OUTPUT_LEN, ALT_BN128_PAIRING_ELEMENT_LEN, ALT_BN128_PAIRING_OUTPUT_LEN, }, + big_mod_exp::{big_mod_exp, BigModExpParams}, blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS}, feature_set::FeatureSet, feature_set::{ self, blake3_syscall_enabled, check_syscall_outputs_do_not_overlap, curve25519_syscall_enabled, disable_cpi_setting_executable_and_rent_epoch, - disable_fees_sysvar, enable_alt_bn128_syscall, + disable_fees_sysvar, enable_alt_bn128_syscall, enable_big_mod_exp_syscall, enable_early_verification_of_account_modifications, error_on_syscall_bpf_function_hash_collisions, libsecp256k1_0_5_upgrade_enabled, limit_secp256k1_recovery_id, reject_callx_r10, @@ -186,6 +187,7 @@ pub fn create_loader<'a>( }; let enable_alt_bn128_syscall = feature_set.is_active(&enable_alt_bn128_syscall::id()); + let enable_big_mod_exp_syscall = feature_set.is_active(&enable_big_mod_exp_syscall::id()); let blake3_syscall_enabled = feature_set.is_active(&blake3_syscall_enabled::id()); let curve25519_syscall_enabled = feature_set.is_active(&curve25519_syscall_enabled::id()); let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id()); @@ -306,6 +308,14 @@ pub fn create_loader<'a>( "sol_alt_bn128_group_op", SyscallAltBn128::call, )?; + + // Big_mod_exp + register_feature_gated_function!( + result, + enable_big_mod_exp_syscall, + "sol_big_mod_exp", + SyscallBigModExp::call, + )?; } // Log data @@ -1718,6 +1728,80 @@ declare_syscall!( } ); +declare_syscall!( + /// Big integer modular exponentiation + SyscallBigModExp, + fn inner_call( + invoke_context: &mut InvokeContext, + params: u64, + return_value: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &mut MemoryMapping, + ) -> Result { + let params = &translate_slice::( + memory_mapping, + params, + 1, + invoke_context.get_check_aligned(), + invoke_context.get_check_size(), + )? + .get(0) + .ok_or(SyscallError::InvalidLength)?; + + let input_len: u64 = std::cmp::max(params.base_len, params.exponent_len); + let input_len: u64 = std::cmp::max(input_len, params.modulus_len); + + let budget = invoke_context.get_compute_budget(); + consume_compute_meter( + invoke_context, + budget.syscall_base_cost.saturating_add( + input_len + .saturating_mul(input_len) + .saturating_div(budget.big_modular_exponentiation_cost), + ), + )?; + + let base = translate_slice::( + memory_mapping, + params.base as *const _ as *const u8 as u64, + params.base_len, + invoke_context.get_check_aligned(), + invoke_context.get_check_size(), + )?; + + let exponent = translate_slice::( + memory_mapping, + params.exponent as *const _ as *const u8 as u64, + params.exponent_len, + invoke_context.get_check_aligned(), + invoke_context.get_check_size(), + )?; + + let modulus = translate_slice::( + memory_mapping, + params.modulus as *const _ as *const u8 as u64, + params.modulus_len, + invoke_context.get_check_aligned(), + invoke_context.get_check_size(), + )?; + + let value = big_mod_exp(base, exponent, modulus); + + let return_value = translate_slice_mut::( + memory_mapping, + return_value, + params.modulus_len, + invoke_context.get_check_aligned(), + invoke_context.get_check_size(), + )?; + return_value.copy_from_slice(value.as_slice()); + + Ok(0) + } +); + #[cfg(test)] mod tests { #[allow(deprecated)] diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index c02da723a9..a28285f7e8 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -4319,6 +4319,16 @@ dependencies = [ "solana-program 1.15.0", ] +[[package]] +name = "solana-bpf-rust-big-mod-exp" +version = "1.15.0" +dependencies = [ + "array-bytes", + "serde", + "serde_json", + "solana-program 1.15.0", +] + [[package]] name = "solana-bucket-map" version = "1.15.0" @@ -4974,6 +4984,7 @@ dependencies = [ "libsecp256k1 0.6.0", "log", "memoffset", + "num-bigint 0.4.3", "num-derive", "num-traits", "parking_lot 0.12.1", diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index 6fb7cb681d..5ab69cd8ee 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -52,6 +52,7 @@ members = [ "rust/128bit_dep", "rust/alloc", "rust/alt_bn128", + "rust/big_mod_exp", "rust/call_depth", "rust/caller_access", "rust/curve25519", diff --git a/programs/sbf/build.rs b/programs/sbf/build.rs index 79c9a37530..2248920408 100644 --- a/programs/sbf/build.rs +++ b/programs/sbf/build.rs @@ -61,6 +61,7 @@ fn main() { "128bit", "alloc", "alt_bn128", + "big_mod_exp", "call_depth", "caller_access", "curve25519", diff --git a/programs/sbf/c/src/big_mod_exp/big_mod_exp.c b/programs/sbf/c/src/big_mod_exp/big_mod_exp.c new file mode 100644 index 0000000000..e4cd4e646c --- /dev/null +++ b/programs/sbf/c/src/big_mod_exp/big_mod_exp.c @@ -0,0 +1,49 @@ +/** + * @brief Big integer modular exponentiation Syscall test + */ + +#include + +extern uint64_t entrypoint(const uint8_t *input) { + + struct BigModExpParam{ + char* base; + size_t base_len; + char* exponent; + size_t exponent_len; + char* modulus; + size_t modulus_len; + } params; + + uint8_t base[32] = { + 0x98, 0x74, 0x23, 0x14, 0x72, 0x31, 0x74, 0x32, 0x84, 0x79, 0x23, 0x17, 0x43, 0x92, 0x87, 0x49, + 0x18, 0x23, 0x74, 0x39, 0x28, 0x74, 0x92, 0x37, 0x49, 0x32, 0x87, 0x19, 0x37, 0x28, 0x97, 0x19 + }; + uint8_t exponent[32] = { + 0x09, 0x48, 0x40, 0x39, 0x85, 0x40, 0x12, 0x32, 0x88, 0x94, 0x38, 0x57, 0x94, 0x75, 0x81, 0x23, + 0x47, 0x23, 0x20, 0x99, 0x08, 0x00, 0x51, 0x35, 0x61, 0x65, 0x12, 0x61, 0x66, 0x26, 0x62, 0x22 + }; + uint8_t modulus[32] = { + 0x25, 0x53, 0x23, 0x21, 0xa2, 0x14, 0x32, 0x14, 0x23, 0x12, 0x42, 0x12, 0x22, 0x22, 0x24, 0x22, + 0x2b, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44 + }; + uint8_t expected[32] = { + 0x22, 0x0e, 0xce, 0x1c, 0x42, 0x62, 0x4e, 0x98, 0xae, 0xe7, 0xeb, 0x86, 0x57, 0x8b, 0x2f, 0xe5, + 0xc4, 0x85, 0x5d, 0xff, 0xac, 0xcb, 0x43, 0xcc, 0xbb, 0x70, 0x8a, 0x3a, 0xb3, 0x7f, 0x18, 0x4d + }; + uint8_t result[32]; + + params.base = (char*) base; + params.base_len = sizeof(base); + params.exponent = (char*) exponent; + params.exponent_len = sizeof(exponent); + params.modulus = (char*) modulus; + params.modulus_len = sizeof(modulus); + + uint64_t result_code = sol_big_mod_exp((uint8_t *) ¶ms, result); + + sol_assert(0 == result_code); + sol_assert(0 == sol_memcmp(result, expected, 32)); + + return SUCCESS; +} diff --git a/programs/sbf/rust/big_mod_exp/Cargo.toml b/programs/sbf/rust/big_mod_exp/Cargo.toml new file mode 100644 index 0000000000..0e00999b10 --- /dev/null +++ b/programs/sbf/rust/big_mod_exp/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "solana-bpf-rust-big-mod-exp" +version = "1.15.0" +description = "Solana BPF test program written in Rust" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" +documentation = "https://docs.rs/solana-bpf-rust-big-mod-exp" +edition = "2021" + +[dependencies] +array-bytes = "=1.4.1" +serde = { version = "1.0.112", features = ["derive"] } +serde_json = "1.0.56" +solana-program = { path = "../../../../sdk/program", version = "=1.15.0" } + +[lib] +crate-type = ["cdylib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/programs/sbf/rust/big_mod_exp/src/lib.rs b/programs/sbf/rust/big_mod_exp/src/lib.rs new file mode 100644 index 0000000000..d283806882 --- /dev/null +++ b/programs/sbf/rust/big_mod_exp/src/lib.rs @@ -0,0 +1,93 @@ +//! Big_mod_exp Syscall tests + +extern crate solana_program; +use solana_program::{big_mod_exp::big_mod_exp, custom_panic_default, msg}; + +fn big_mod_exp_test() { + #[derive(serde::Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + base: String, + exponent: String, + modulus: String, + expected: String, + } + + let test_data = r#"[ + { + "Base": "1111111111111111111111111111111111111111111111111111111111111111", + "Exponent": "1111111111111111111111111111111111111111111111111111111111111111", + "Modulus": "111111111111111111111111111111111111111111111111111111111111110A", + "Expected": "0A7074864588D6847F33A168209E516F60005A0CEC3F33AAF70E8002FE964BCD" + }, + { + "Base": "2222222222222222222222222222222222222222222222222222222222222222", + "Exponent": "2222222222222222222222222222222222222222222222222222222222222222", + "Modulus": "1111111111111111111111111111111111111111111111111111111111111111", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Base": "3333333333333333333333333333333333333333333333333333333333333333", + "Exponent": "3333333333333333333333333333333333333333333333333333333333333333", + "Modulus": "2222222222222222222222222222222222222222222222222222222222222222", + "Expected": "1111111111111111111111111111111111111111111111111111111111111111" + }, + { + "Base": "9874231472317432847923174392874918237439287492374932871937289719", + "Exponent": "0948403985401232889438579475812347232099080051356165126166266222", + "Modulus": "25532321a214321423124212222224222b242222222222222222222222222444", + "Expected": "220ECE1C42624E98AEE7EB86578B2FE5C4855DFFACCB43CCBB708A3AB37F184D" + }, + { + "Base": "3494396663463663636363662632666565656456646566786786676786768766", + "Exponent": "2324324333246536456354655645656616169896565698987033121934984955", + "Modulus": "0218305479243590485092843590249879879842313131156656565565656566", + "Expected": "012F2865E8B9E79B645FCE3A9E04156483AE1F9833F6BFCF86FCA38FC2D5BEF0" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000005", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000002", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000007", + "Expected": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000064", + "Expected": "0000000000000000000000000000000000000000000000000000000000000019" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000000", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000001", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + } + ]"#; + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + test_cases.iter().for_each(|test| { + let base = array_bytes::hex2bytes_unchecked(&test.base); + let exponent = array_bytes::hex2bytes_unchecked(&test.exponent); + let modulus = array_bytes::hex2bytes_unchecked(&test.modulus); + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + let result = big_mod_exp(base.as_slice(), exponent.as_slice(), modulus.as_slice()); + assert_eq!(result, expected); + }); +} + +#[no_mangle] +pub extern "C" fn entrypoint(_input: *mut u8) -> u64 { + msg!("big_mod_exp"); + + big_mod_exp_test(); + + 0 +} + +custom_panic_default!(); diff --git a/sdk/bpf/c/inc/sol/big_mod_exp.h b/sdk/bpf/c/inc/sol/big_mod_exp.h new file mode 100644 index 0000000000..b90c66a193 --- /dev/null +++ b/sdk/bpf/c/inc/sol/big_mod_exp.h @@ -0,0 +1,32 @@ +#pragma once +/** + * @brief Solana big_mod_exp system call +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Big integer modular exponentiation + * + * @param bytes Pointer to BigModExpParam struct + * @param result 32 byte array to hold the result + * @return 0 if executed successfully + */ +/* DO NOT MODIFY THIS GENERATED FILE. INSTEAD CHANGE sdk/bpf/c/inc/sol/inc/big_mod_exp.inc AND RUN `cargo run --bin gen-headers` */ +#ifndef SOL_SBFV2 +uint64_t sol_big_mod_exp(const uint8_t *, uint8_t *); +#else +typedef uint64_t(*sol_big_mod_exp_pointer_type)(const uint8_t *, uint8_t *); +static uint64_t sol_big_mod_exp(const uint8_t * arg1, uint8_t * arg2) { + sol_big_mod_exp_pointer_type sol_big_mod_exp_pointer = (sol_big_mod_exp_pointer_type) 2014202901; + return sol_big_mod_exp_pointer(arg1, arg2); +} +#endif + +#ifdef __cplusplus +} +#endif + +/**@}*/ diff --git a/sdk/bpf/c/inc/sol/inc/big_mod_exp.inc b/sdk/bpf/c/inc/sol/inc/big_mod_exp.inc new file mode 100644 index 0000000000..ce5c665629 --- /dev/null +++ b/sdk/bpf/c/inc/sol/inc/big_mod_exp.inc @@ -0,0 +1,23 @@ +#pragma once +/** + * @brief Solana big_mod_exp system call +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Big integer modular exponentiation + * + * @param bytes Pointer to BigModExpParam struct + * @param result 32 byte array to hold the result + * @return 0 if executed successfully + */ +@SYSCALL uint64_t sol_big_mod_exp(const uint8_t *, uint8_t *); + +#ifdef __cplusplus +} +#endif + +/**@}*/ diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index bc0a8eb803..98476758fd 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 04ccf97553..457143989a 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -47,6 +47,7 @@ curve25519-dalek = { version = "3.2.1", features = ["serde"] } itertools = "0.10.5" libc = { version = "0.2.126", features = ["extra_traits"] } libsecp256k1 = "0.6.0" +num-bigint = "0.4.3" rand = "0.7" rand_chacha = { version = "0.2.2", default-features = true, features = ["simd", "std"] } tiny-bip39 = "0.8.2" diff --git a/sdk/program/src/big_mod_exp.rs b/sdk/program/src/big_mod_exp.rs new file mode 100644 index 0000000000..11bd7098f1 --- /dev/null +++ b/sdk/program/src/big_mod_exp.rs @@ -0,0 +1,141 @@ +#[repr(C)] +pub struct BigModExpParams { + pub base: *const u8, + pub base_len: u64, + pub exponent: *const u8, + pub exponent_len: u64, + pub modulus: *const u8, + pub modulus_len: u64, +} + +/// Big integer modular exponentiation +pub fn big_mod_exp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { + #[cfg(not(target_os = "solana"))] + { + use { + num_bigint::BigUint, + num_traits::{One, Zero}, + }; + + let modulus_len = modulus.len(); + let base = BigUint::from_bytes_be(base); + let exponent = BigUint::from_bytes_be(exponent); + let modulus = BigUint::from_bytes_be(modulus); + + if modulus.is_zero() || modulus.is_one() { + return vec![0_u8; modulus_len]; + } + + let ret_int = base.modpow(&exponent, &modulus); + let ret_int = ret_int.to_bytes_be(); + let mut return_value = vec![0_u8; modulus_len.saturating_sub(ret_int.len())]; + return_value.extend(ret_int); + return_value + } + + #[cfg(target_os = "solana")] + { + let mut return_value = vec![0_u8; modulus.len()]; + + let param = BigModExpParams { + base: base as *const _ as *const u8, + base_len: base.len() as u64, + exponent: exponent as *const _ as *const u8, + exponent_len: exponent.len() as u64, + modulus: modulus as *const _ as *const u8, + modulus_len: modulus.len() as u64, + }; + unsafe { + crate::syscalls::sol_big_mod_exp( + ¶m as *const _ as *const u8, + return_value.as_mut_slice() as *mut _ as *mut u8, + ) + }; + + return_value + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn big_mod_exp_test() { + #[derive(serde::Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + base: String, + exponent: String, + modulus: String, + expected: String, + } + + let test_data = r#"[ + { + "Base": "1111111111111111111111111111111111111111111111111111111111111111", + "Exponent": "1111111111111111111111111111111111111111111111111111111111111111", + "Modulus": "111111111111111111111111111111111111111111111111111111111111110A", + "Expected": "0A7074864588D6847F33A168209E516F60005A0CEC3F33AAF70E8002FE964BCD" + }, + { + "Base": "2222222222222222222222222222222222222222222222222222222222222222", + "Exponent": "2222222222222222222222222222222222222222222222222222222222222222", + "Modulus": "1111111111111111111111111111111111111111111111111111111111111111", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Base": "3333333333333333333333333333333333333333333333333333333333333333", + "Exponent": "3333333333333333333333333333333333333333333333333333333333333333", + "Modulus": "2222222222222222222222222222222222222222222222222222222222222222", + "Expected": "1111111111111111111111111111111111111111111111111111111111111111" + }, + { + "Base": "9874231472317432847923174392874918237439287492374932871937289719", + "Exponent": "0948403985401232889438579475812347232099080051356165126166266222", + "Modulus": "25532321a214321423124212222224222b242222222222222222222222222444", + "Expected": "220ECE1C42624E98AEE7EB86578B2FE5C4855DFFACCB43CCBB708A3AB37F184D" + }, + { + "Base": "3494396663463663636363662632666565656456646566786786676786768766", + "Exponent": "2324324333246536456354655645656616169896565698987033121934984955", + "Modulus": "0218305479243590485092843590249879879842313131156656565565656566", + "Expected": "012F2865E8B9E79B645FCE3A9E04156483AE1F9833F6BFCF86FCA38FC2D5BEF0" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000005", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000002", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000007", + "Expected": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000064", + "Expected": "0000000000000000000000000000000000000000000000000000000000000019" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000000", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "Base": "0000000000000000000000000000000000000000000000000000000000000019", + "Exponent": "0000000000000000000000000000000000000000000000000000000000000019", + "Modulus": "0000000000000000000000000000000000000000000000000000000000000001", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000" + } + ]"#; + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + test_cases.iter().for_each(|test| { + let base = array_bytes::hex2bytes_unchecked(&test.base); + let exponent = array_bytes::hex2bytes_unchecked(&test.exponent); + let modulus = array_bytes::hex2bytes_unchecked(&test.modulus); + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + let result = big_mod_exp(base.as_slice(), exponent.as_slice(), modulus.as_slice()); + assert_eq!(result, expected); + }); + } +} diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 199b8f273f..dab056c29b 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -478,6 +478,7 @@ pub mod account_info; pub mod address_lookup_table_account; pub mod alt_bn128; pub(crate) mod atomic_u64; +pub mod big_mod_exp; pub mod blake3; pub mod borsh; pub mod bpf_loader; diff --git a/sdk/program/src/syscalls/definitions.rs b/sdk/program/src/syscalls/definitions.rs index 67052e611a..2926ab584a 100644 --- a/sdk/program/src/syscalls/definitions.rs +++ b/sdk/program/src/syscalls/definitions.rs @@ -66,6 +66,7 @@ define_syscall!(fn sol_curve_group_op(curve_id: u64, group_op: u64, left_input_a define_syscall!(fn sol_curve_multiscalar_mul(curve_id: u64, scalars_addr: *const u8, points_addr: *const u8, points_len: u64, result_point_addr: *mut u8) -> u64); define_syscall!(fn sol_curve_pairing_map(curve_id: u64, point: *const u8, result: *mut u8) -> u64); define_syscall!(fn sol_alt_bn128_group_op(group_op: u64, input: *const u8, input_size: u64, result: *mut u8) -> u64); +define_syscall!(fn sol_big_mod_exp(params: *const u8, result: *mut u8) -> u64); #[cfg(target_feature = "static-syscalls")] pub const fn sys_hash(name: &str) -> usize { diff --git a/sdk/sbf/c/inc/sol/big_mod_exp.h b/sdk/sbf/c/inc/sol/big_mod_exp.h new file mode 100644 index 0000000000..cb8f0033ec --- /dev/null +++ b/sdk/sbf/c/inc/sol/big_mod_exp.h @@ -0,0 +1,32 @@ +#pragma once +/** + * @brief Solana big_mod_exp system call +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Big integer modular exponentiation + * + * @param bytes Pointer to BigModExpParam struct + * @param result 32 byte array to hold the result + * @return 0 if executed successfully + */ +/* DO NOT MODIFY THIS GENERATED FILE. INSTEAD CHANGE sdk/sbf/c/inc/sol/inc/big_mod_exp.inc AND RUN `cargo run --bin gen-headers` */ +#ifndef SOL_SBFV2 +uint64_t sol_big_mod_exp(const uint8_t *, uint8_t *); +#else +typedef uint64_t(*sol_big_mod_exp_pointer_type)(const uint8_t *, uint8_t *); +static uint64_t sol_big_mod_exp(const uint8_t * arg1, uint8_t * arg2) { + sol_big_mod_exp_pointer_type sol_big_mod_exp_pointer = (sol_big_mod_exp_pointer_type) 2014202901; + return sol_big_mod_exp_pointer(arg1, arg2); +} +#endif + +#ifdef __cplusplus +} +#endif + +/**@}*/ diff --git a/sdk/sbf/c/inc/sol/inc/big_mod_exp.inc b/sdk/sbf/c/inc/sol/inc/big_mod_exp.inc new file mode 100644 index 0000000000..ce5c665629 --- /dev/null +++ b/sdk/sbf/c/inc/sol/inc/big_mod_exp.inc @@ -0,0 +1,23 @@ +#pragma once +/** + * @brief Solana big_mod_exp system call +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Big integer modular exponentiation + * + * @param bytes Pointer to BigModExpParam struct + * @param result 32 byte array to hold the result + * @return 0 if executed successfully + */ +@SYSCALL uint64_t sol_big_mod_exp(const uint8_t *, uint8_t *); + +#ifdef __cplusplus +} +#endif + +/**@}*/ diff --git a/sdk/sbf/c/inc/solana_sdk.h b/sdk/sbf/c/inc/solana_sdk.h index 27cb3a6a7e..5c8e437018 100644 --- a/sdk/sbf/c/inc/solana_sdk.h +++ b/sdk/sbf/c/inc/solana_sdk.h @@ -4,6 +4,7 @@ */ #include +#include #include #include #include diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 783ead1514..8a6a6953e6 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -586,6 +586,10 @@ pub mod update_hashes_per_tick { solana_sdk::declare_id!("3uFHb9oKdGfgZGJK9EHaAXN4USvnQtAFC13Fh5gGFS5B"); } +pub mod enable_big_mod_exp_syscall { + solana_sdk::declare_id!("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXBGMDEXP"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -727,6 +731,7 @@ lazy_static! { (keep_merkle_shreds::id(), "keep merkle shreds #29711"), (move_serialized_len_ptr_in_cpi::id(), "cpi ignore serialized_len_ptr #29592"), (update_hashes_per_tick::id(), "Update desired hashes per tick on epoch boundary"), + (enable_big_mod_exp_syscall::id(), "add big_mod_exp syscall #28503"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter() diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index d2e743e30c..f6c312664b 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -43,7 +43,7 @@ pub use signer::signers; #[cfg(not(target_os = "solana"))] pub use solana_program::program_stubs; pub use solana_program::{ - account_info, address_lookup_table_account, alt_bn128, blake3, borsh, bpf_loader, + account_info, address_lookup_table_account, alt_bn128, big_mod_exp, blake3, borsh, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock, config, custom_heap_default, custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, declare_sysvar_id, decode_error, ed25519_program, epoch_schedule, fee_calculator, impl_sysvar_get, incinerator,