#[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); }); } }