solana/sdk/program/src/big_mod_exp.rs

142 lines
6.0 KiB
Rust

#[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<u8> {
#[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(
&param 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<TestCase> = 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);
});
}
}