From bd9c10d89be6520ce5b37059d11fb9591988a7d9 Mon Sep 17 00:00:00 2001 From: sangge <2251250136@qq.com> Date: Mon, 1 Sep 2025 17:34:31 +0800 Subject: [PATCH] feat: use crypto-bigint crate --- Cargo.lock | 79 +++++-------- Cargo.toml | 1 + problems/p33/Cargo.toml | 4 +- problems/p33/src/main.rs | 232 +++++++++------------------------------ 4 files changed, 84 insertions(+), 232 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52f3faf..0f2a24f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ name = "common" version = "0.1.0" dependencies = [ "anyhow", - "rand 0.9.2", + "rand", ] [[package]] @@ -65,6 +65,17 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-bigint" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96272c2ff28b807e09250b180ad1fb7889a3258f7455759b5c3c58b719467130" +dependencies = [ + "num-traits", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "cryptopal_rs" version = "0.1.0" @@ -110,26 +121,6 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -167,7 +158,7 @@ name = "p11" version = "0.1.0" dependencies = [ "common", - "rand 0.9.2", + "rand", ] [[package]] @@ -177,7 +168,7 @@ dependencies = [ "anyhow", "base64", "common", - "rand 0.9.2", + "rand", ] [[package]] @@ -195,7 +186,7 @@ dependencies = [ "anyhow", "base64", "common", - "rand 0.9.2", + "rand", ] [[package]] @@ -240,6 +231,9 @@ dependencies = [ [[package]] name = "p20" version = "0.1.0" +dependencies = [ + "base64", +] [[package]] name = "p21" @@ -250,14 +244,14 @@ name = "p22" version = "0.1.0" dependencies = [ "common", - "rand 0.9.2", + "rand", ] [[package]] name = "p23" version = "0.1.0" dependencies = [ - "rand 0.9.2", + "rand", ] [[package]] @@ -281,10 +275,8 @@ name = "p33" version = "0.1.0" dependencies = [ "anyhow", - "num-bigint", - "num-traits", + "crypto-bigint", "once_cell", - "rand 0.8.5", ] [[package]] @@ -369,37 +361,16 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.3", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -448,6 +419,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.103" diff --git a/Cargo.toml b/Cargo.toml index 2c74591..7c3820c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ num-bigint = { version = "0.4", features = ["rand"] } num-traits = "0.2" once_cell = "1.21" rayon = "1.11.0" +crypto-bigint = "0.6" diff --git a/problems/p33/Cargo.toml b/problems/p33/Cargo.toml index 1fe1f9a..d3cffb7 100644 --- a/problems/p33/Cargo.toml +++ b/problems/p33/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] -num-bigint = { workspace = true } -num-traits = { workspace = true } -rand = { version = "0.8" } # rand_biguint need 0.8 +crypto-bigint = { workspace = true } anyhow = { workspace = true } once_cell = { workspace = true } diff --git a/problems/p33/src/main.rs b/problems/p33/src/main.rs index 4910003..4fe9f87 100644 --- a/problems/p33/src/main.rs +++ b/problems/p33/src/main.rs @@ -1,58 +1,80 @@ use anyhow::{Ok, Result, anyhow}; -use num_bigint::{BigUint, RandBigInt}; -use num_traits::{One, Zero}; +use crypto_bigint::{ + NonZero, Odd, Random, U2048, Zero, + modular::{MontyForm, MontyParams}, + rand_core::OsRng, +}; use once_cell::sync::Lazy; -use rand::thread_rng; -static NIST_P: Lazy = Lazy::new(|| { - BigUint::parse_bytes(b"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff",16).unwrap() +static NIST_P: Lazy = Lazy::new(|| { + U2048::from_be_hex( + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", + ) }); +static NIST_G: Lazy = Lazy::new(|| U2048::from(2u8)); -static NIST_G: Lazy = Lazy::new(|| BigUint::from(2u8)); - -fn mod_exp(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> Result { - if modulus.is_zero() { +fn mod_exp(base: &U2048, exp: &U2048, modulus: &U2048) -> Result { + let modulus = if NonZero::new(*modulus).is_some().into() { + NonZero::new(*modulus).unwrap() + } else { return Err(anyhow!("modulus should greater than 0")); - } - let mut base = base % modulus; - if exp.is_zero() { - return Ok(BigUint::one()); - } - if base.is_zero() { - return Ok(base); - } - let mut result = BigUint::one(); - let mut exp = exp.clone(); - while !exp.is_zero() { - if exp.bit(0) { - result = (&result * &base) % modulus; - } - base = (&base * &base) % modulus; - exp >>= 1; + }; + + if exp.is_zero().into() { + return Ok(U2048::ONE); } - Ok(result) + if base.is_zero().into() { + return Ok(*base); + } + + // let mut result = U2048::ONE; + // let mut exp = *exp; + // + // let mut base = *base; // 在循环前解引用 + // while (!exp.is_zero()).into() { + // if exp.bit(0).into() { + // result = result.mul_mod(&base, &modulus); + // } + // base = base.mul_mod(&base, &modulus); + // exp >>= 1; + // } + // Ok(result) + + let modulus_odd = if Odd::new(*modulus).is_some().into() { + Odd::new(*modulus).unwrap() + } else { + return Err(anyhow!("modulus should greater than 0")); + }; + let params = MontyParams::new(modulus_odd); + let base_monty = MontyForm::new(base, params); + let result_monty = base_monty.pow(exp); + + Ok(result_monty.retrieve()) } -type PublicKey = BigUint; -type PrivateKey = BigUint; +type PublicKey = U2048; +type PrivateKey = U2048; fn gen_dh_keypair() -> Result<(PrivateKey, PublicKey)> { - let mut rng = thread_rng(); - let private_key = rng.gen_biguint_range(&BigUint::zero(), &NIST_P); + let private_key = U2048::random(&mut OsRng); + let nist_p_nonzero = NonZero::new(*NIST_P).unwrap(); + let private_key = private_key.rem(&nist_p_nonzero); let public_key = mod_exp(&NIST_G, &private_key, &NIST_P)?; Ok((private_key, public_key)) } -fn gen_secret(public_key: &BigUint, privite_key: &BigUint) -> Result { - mod_exp(public_key, privite_key, &NIST_P) +fn gen_secret(public_key: &U2048, private_key: &U2048) -> Result { + mod_exp(public_key, private_key, &NIST_P) } fn main() -> Result<()> { let (sk_alice, pk_alice) = gen_dh_keypair()?; let (sk_bob, pk_bob) = gen_dh_keypair()?; + let secret_alice = gen_secret(&pk_bob, &sk_alice)?; let secret_bob = gen_secret(&pk_alice, &sk_bob)?; + if secret_alice == secret_bob { println!("We share the same secret"); } else { @@ -61,149 +83,3 @@ fn main() -> Result<()> { Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - use num_bigint::BigUint; - use num_traits::{One, Zero}; - - #[test] - fn test_basic_modexp() { - // 3^4 mod 5 = 81 mod 5 = 1 - let result = mod_exp( - &BigUint::from(3u32), - &BigUint::from(4u32), - &BigUint::from(5u32), - ) - .unwrap(); - assert_eq!(result, BigUint::from(1u32)); - } - - #[test] - fn test_large_numbers() { - // 2^100 mod 17 - let result = mod_exp( - &BigUint::from(2u32), - &BigUint::from(100u32), - &BigUint::from(17u32), - ) - .unwrap(); - // 2^100 mod 17 = 16 (can verify with smaller calculation) - assert_eq!(result, BigUint::from(16u32)); - } - - #[test] - fn test_zero_exponent() { - // Any number^0 mod m = 1 (except 0^0) - let result = mod_exp( - &BigUint::from(123u32), - &BigUint::zero(), - &BigUint::from(456u32), - ) - .unwrap(); - assert_eq!(result, BigUint::one()); - } - - #[test] - fn test_zero_base() { - // 0^n mod m = 0 (for n > 0) - let result = mod_exp(&BigUint::zero(), &BigUint::from(5u32), &BigUint::from(7u32)).unwrap(); - assert_eq!(result, BigUint::zero()); - } - - #[test] - fn test_one_base() { - // 1^n mod m = 1 - let result = mod_exp( - &BigUint::one(), - &BigUint::from(999u32), - &BigUint::from(123u32), - ) - .unwrap(); - assert_eq!(result, BigUint::one()); - } - - #[test] - fn test_modulus_one() { - // Any number mod 1 = 0 - let result = mod_exp( - &BigUint::from(123u32), - &BigUint::from(456u32), - &BigUint::one(), - ) - .unwrap(); - assert_eq!(result, BigUint::zero()); - } - - #[test] - fn test_rsa_example() { - // RSA-like calculation: 42^17 mod 77 - let result = mod_exp( - &BigUint::from(42u32), - &BigUint::from(17u32), - &BigUint::from(77u32), - ) - .unwrap(); - // Can verify this manually or with known RSA test vectors - assert_eq!(result, BigUint::from(70u32)); - } - - #[test] - fn test_fermat_little_theorem() { - // p = 7 (prime), a = 3 - // 3^6 mod 7 should equal 1 (Fermat's Little Theorem: a^(p-1) ≡ 1 mod p) - let result = mod_exp( - &BigUint::from(3u32), - &BigUint::from(6u32), - &BigUint::from(7u32), - ) - .unwrap(); - assert_eq!(result, BigUint::one()); - } - - #[test] - fn test_very_large_numbers() { - // Test with very large numbers - let base = BigUint::parse_bytes(b"123456789012345678901234567890", 10).unwrap(); - let exp = BigUint::from(1000u32); - let modulus = BigUint::parse_bytes(b"987654321098765432109876543210987654321", 10).unwrap(); - - let result = mod_exp(&base, &exp, &modulus); - assert!(result.is_ok()); - // Result should be less than modulus - assert!( - result.unwrap() - < BigUint::parse_bytes(b"987654321098765432109876543210987654321", 10).unwrap() - ); - } - - #[test] - fn test_error_zero_modulus() { - // Division by zero should return error - let result = mod_exp(&BigUint::from(5u32), &BigUint::from(3u32), &BigUint::zero()); - assert!(result.is_err()); - } - - #[test] - fn test_zero_zero_case() { - // 0^0 is mathematically undefined, should handle appropriately - let result = mod_exp(&BigUint::zero(), &BigUint::zero(), &BigUint::from(5u32)); - // Depending on your implementation, this might return 1 or error - // Common convention is 0^0 = 1 in many contexts - assert!(result.is_ok() || result.is_err()); // Just ensure it's handled - } - - #[test] - fn test_equal_base_modulus() { - // base == modulus, so base mod modulus = 0 - // 0^exp mod modulus = 0 (for exp > 0) - let result = mod_exp( - &BigUint::from(7u32), - &BigUint::from(3u32), - &BigUint::from(7u32), - ) - .unwrap(); - assert_eq!(result, BigUint::zero()); - } -}