use openssl::{
bn::{BigNum, BigNumContext},
error::ErrorStack,
};
pub fn i20sp(num: &mut BigNum, xlen: usize) -> Result<Vec<u8>, ErrorStack> {
let base = BigNum::from_u32(256)?;
let mut bn_ctx = BigNumContext::new()?;
let mut limit = BigNum::new()?;
limit.exp(&base, &BigNum::from_u32(xlen as u32).unwrap(), &mut bn_ctx)?;
if num >= &mut limit {
panic!("Above limit");
}
let mut octet: Vec<u8> = Vec::with_capacity(xlen);
let mut rem = BigNum::new()?;
for _ in 0..xlen {
let mut div = BigNum::new()?;
div.div_rem(&mut rem, num, &base, &mut bn_ctx)?;
*num = div;
let r: u8 = rem.to_dec_str()?.parse().unwrap();
octet.push(r);
}
octet.reverse();
Ok(octet)
}
pub fn os2ip(octet: &[u8]) -> Result<BigNum, ErrorStack> {
let base = BigNum::from_u32(256)?;
let mut bn_ctx = BigNumContext::new()?;
let length = octet.len();
let mut sum = BigNum::new()?;
let mut step = BigNum::new()?;
let mut mul = BigNum::new()?;
for (index, num) in octet.iter().enumerate() {
let mut dup = BigNum::new()?;
let num = BigNum::from_u32(*num as u32).unwrap();
let pow = BigNum::from_u32((&length - 1 - index) as u32)?;
step.exp(&base, &pow, &mut bn_ctx)?;
mul.checked_mul(&num, &step, &mut bn_ctx)?;
dup.checked_add(&sum, &mul)?;
sum = dup;
}
Ok(sum)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn i20sp_test() {
let mut result = BigNum::from_dec_str("234567817231231").unwrap();
let result = i20sp(&mut result, 6).unwrap();
let expected_result = vec![213, 86, 147, 107, 251, 127];
assert_eq!(result, expected_result);
}
#[test]
fn os2ip_test() {
let octets = vec![213, 86, 147, 107, 251, 127];
let result = os2ip(&octets).unwrap();
let expected_result = BigNum::from_dec_str("234567817231231").unwrap();
assert_eq!(result, expected_result);
}
}