use crate::prelude_internal::*;
#[cfg(feature = "openssl")]
use openssl::bn::{BigNum, BigNumContext};
pub trait ExtractPrimeV1 {
#[cfg(feature = "openssl")]
fn extract_prime_v1_bignum(&self, bit_length: u16) -> Result<BigNum>;
fn extract_prime_v1_big_uint(&self, bit_length: u16) -> Result<num_bigint::BigUint>;
}
impl ExtractPrimeV1 for Secret {
#[cfg(feature = "openssl")]
fn extract_prime_v1_bignum(&self, bit_length: u16) -> Result<BigNum> {
const SALT: &[u8] = b"\x00Prime_v1";
let msecret = self.subsecret_from_salt(SALT)?;
let mut ctx = BigNumContext::new_secure()?;
if bit_length < 4 {
bail!("Invalid bit length {}", bit_length);
}
let mut max = BigNum::new_secure()?;
max.set_bit(bit_length.into())?;
max.sub_word(1)?;
let mut prime = msecret.extract_big_num(&max)?;
prime.set_bit(0)?;
prime.set_bit((bit_length - 1).into())?;
if bit_length > 32 {
prime.set_bit((bit_length - 2).into())?;
}
while !prime.is_prime_fasttest(0, &mut ctx, true)? {
prime.add_word(2)?;
}
Ok(prime)
}
fn extract_prime_v1_big_uint(&self, bit_length: u16) -> Result<num_bigint::BigUint> {
use num_bigint::BigUint;
use num_bigint_dig::prime::*;
use num_traits::identities::*;
const SALT: &[u8] = b"\x00Prime_v1";
let bit_length: usize = bit_length.into();
let msecret = self.subsecret_from_salt(SALT)?;
if bit_length < 4 {
bail!("Invalid bit length {}", bit_length);
}
let one = BigUint::one();
let max = (&one << bit_length) - &one;
let mut prime = msecret.extract_big_uint(&max)?;
prime |= &one;
prime |= &one << (bit_length - 1);
if bit_length > 32 {
prime |= &one << (bit_length - 2);
}
if probably_prime(&prime, 20) {
Ok(prime)
} else {
Ok(next_prime(&prime))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::prime::probably_prime;
use num_bigint::BigUint;
#[test]
fn test_prime_smoketest() {
let prime = Secret::ZERO.extract_prime_v1_big_uint(512).unwrap();
assert_eq!(hex::encode(prime.to_bytes_be()),"df5fcd4d2f06b8ea31b0a579774925d4356396af9532e50f4defe9449f5922312ed145b1bb8452ad46116aba52d3296407054ee3c5e5d32ed1627063c3a8087d".to_string());
assert!(probably_prime(&BigUint::from(1579751u32), 20));
assert!(probably_prime(&BigUint::from(1884791u32), 20));
assert!(probably_prime(&BigUint::from(3818929u32), 20));
assert!(probably_prime(&BigUint::from(4080359u32), 20));
assert!(probably_prime(&BigUint::from(4145951u32), 20));
}
#[test]
fn test_prime_shorttest() {
let mut hash = Sha256::default();
for m in [32, 128, 256, 512, 1024] {
for i in 0..100 {
let secret = Secret::ZERO.subsecret_from_label(&i.to_string()).unwrap();
let prime = secret.extract_prime_v1_big_uint(m).unwrap().to_bytes_be();
hash.update(&prime);
}
}
let hash = hex::encode(hash.finalize().as_slice());
assert_eq!(
hash,
"debb8b2c26b0e8012f3e0a4d42381fc2220e946cecfc17186958c2209c81eeff"
);
}
#[test]
#[cfg(feature = "openssl")]
fn test_prime_shorttest_openssl() {
let mut hash = Sha256::default();
for m in [32, 128, 256, 512, 1024] {
for i in 0..100 {
let secret = Secret::ZERO.subsecret_from_label(&i.to_string()).unwrap();
let prime = secret.extract_prime_v1_bignum(m).unwrap().to_vec();
hash.update(&prime);
}
}
let hash = hex::encode(hash.finalize().as_slice());
assert_eq!(
hash,
"debb8b2c26b0e8012f3e0a4d42381fc2220e946cecfc17186958c2209c81eeff"
);
}
#[cfg(feature = "longtest")]
#[test]
fn test_prime_longtest() {
let mut hash = Sha256::default();
for m in [32, 128, 256, 512, 1024] {
for i in 0..5000 {
let secret = Secret::ZERO.subsecret_from_label(&i.to_string()).unwrap();
let prime = secret.extract_prime_v1_big_uint(m).unwrap().to_bytes_be();
hash.update(&prime);
}
}
let hash = hex::encode(hash.finalize().as_slice());
assert_eq!(
hash,
"f2e74d37971abb63ba2422f9341a2d555aa52cf8403f6c00451725a1404219f8"
);
}
#[cfg(all(feature = "openssl", feature = "longtest"))]
#[test]
fn test_prime_longtest_openssl() {
let mut hash = Sha256::default();
for m in [32, 128, 256, 512, 1024] {
for i in 0..5000 {
let secret = Secret::ZERO.subsecret_from_label(&i.to_string()).unwrap();
let prime = secret.extract_prime_v1_bignum(m).unwrap().to_vec();
hash.update(&prime);
}
}
let hash = hex::encode(hash.finalize().as_slice());
assert_eq!(
hash,
"f2e74d37971abb63ba2422f9341a2d555aa52cf8403f6c00451725a1404219f8"
);
}
}