Skip to content

Commit f245062

Browse files
committed
update miller-rabin
1 parent 8480d20 commit f245062

File tree

4 files changed

+112
-97
lines changed

4 files changed

+112
-97
lines changed

Cargo.lock

+5-54
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
num = "0.4.0"
10-
num-traits = "0.2.14"
11-
num-bigint-dig = { version = "0.8.0", features = ["prime"] }
9+
base64 = "0.13.0"
10+
num = { version = "0.4.0", features = ["rand"] }
11+
# num-traits = "0.2.14"
12+
# num-primes = "0.3.0"
13+
# num-bigint-dig = { version = "0.8.0", features = ["prime"] }
1214
rand = "0.8.4"

src/main.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use prime_check::miller_rabin_single;
2+
13
use crate::prime_check::{PrimeUtils, encrypt, decrypt};
24

35
mod prime_check;
@@ -6,7 +8,9 @@ fn main() {
68
let (pub_key, pri_key) = checker.gen_key();
79
let message = "moderncryptography";
810
let secret = encrypt(&pri_key, message);
11+
println!("{}", secret);
912
let message = decrypt(&pub_key, &secret);
1013
// checker.is_prime(testee)
1114
println!("{}", message);
15+
// println!("{}", miller_rabin_single(&341_u32, 20_u32));
1216
}

src/prime_check.rs

+98-40
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,83 @@
1-
use std::fmt::LowerHex;
2-
3-
use num_bigint_dig::BigUint;
4-
use num_bigint_dig::RandBigInt;
5-
use num_bigint_dig::RandPrime;
6-
use num_bigint_dig::BigInt;
7-
use num_bigint_dig::ToBigInt;
8-
use num_traits::{One, RefNum, Zero};
1+
use std::fmt::{Debug, Display};
2+
use std::process::Output;
3+
use std::ops::Sub;
4+
5+
use num::{BigUint, BigInt};
6+
use num::bigint::{ToBigInt, RandBigInt, ToBigUint};
7+
use num::traits::{One, RefNum, Zero, int};
8+
use num::Integer;
99
use rand::{prelude::ThreadRng, thread_rng};
1010

1111
pub struct PrimeUtils {
12-
bit_size: usize,
13-
times: usize,
12+
bit_size: u64,
1413
rng: ThreadRng,
14+
current_p: Option<BigUint>
1515
}
1616

1717
type RSAPublicKey = (BigUint, BigUint);
1818
type RSAPrivateKey = (BigUint, BigUint);
1919

2020
impl PrimeUtils {
21-
pub fn new(bit_size: usize) -> Self {
22-
let bit_size_f64 = bit_size as f64;
23-
let times = (bit_size_f64 / bit_size_f64.ln() / 2_f64) as usize;
24-
// println!("Times is {}", &times);
21+
pub fn new(bit_size: u64) -> Self {
2522
Self {
2623
bit_size,
27-
times,
2824
rng: thread_rng(),
25+
current_p: None
2926
}
3027
}
3128

32-
fn is_prime(&mut self, testee: &BigUint) -> bool {
33-
let mut count = 0;
34-
let one: BigUint = One::one();
35-
let testee_minus_one: BigUint = testee.clone() - &one;
36-
while count < self.times {
37-
let rand_num = self.rng.gen_biguint(self.bit_size) % testee;
38-
if &rand_num == &one || &rand_num == &testee_minus_one {
39-
continue;
29+
fn is_prime(&mut self) -> bool {
30+
self.current_p.as_ref().map_or(false, |testee| {
31+
let mut count = 0;
32+
let one: BigUint = One::one();
33+
let testee_minus_one: BigUint = testee.clone() - &one;
34+
// let prime_factor = Factorization::prime_factor(testee_minus_one).unwrap();
35+
while count < 10 {
36+
let rand_num = self.rng.gen_biguint(self.bit_size) % testee;
37+
if &rand_num == &one || &rand_num == &testee_minus_one {
38+
continue;
39+
}
40+
if !miller_rabin_single(testee, rand_num.clone()) {
41+
// println!("This is not a prime");
42+
return false;
43+
}
44+
count += 1;
4045
}
41-
if !miller_rabin_single(testee, rand_num.clone()) {
42-
println!("This is not a prime");
43-
return false;
46+
true
47+
})
48+
}
49+
50+
pub fn gen_prime(&mut self) -> BigUint {
51+
if self.current_p.is_none() {
52+
let random_val = self.rng.gen_biguint(self.bit_size);
53+
self.current_p = Some(if &random_val % BigUint::from(2_u32) == Zero::zero() {
54+
random_val + BigUint::from(1_u32)
55+
} else {
56+
random_val
57+
});
58+
}
59+
loop {
60+
if self.is_prime() {
61+
break self.current_p.as_ref().unwrap().clone()
62+
} else {
63+
self.current_p = Some(self.current_p.as_ref().unwrap() + BigUint::from(2_u32))
4464
}
45-
count += 1;
4665
}
47-
true
4866
}
4967

5068
pub fn gen_key(&mut self) -> (RSAPublicKey, RSAPrivateKey) {
5169
// (pub_key, pri_key)
5270
// ((N, e), (N, d))
5371
let e = BigUint::from(65537_u32);
5472
loop {
55-
let p = self.rng.gen_prime(self.bit_size);
56-
let q = self.rng.gen_prime(self.bit_size);
73+
let p = self.gen_prime();
74+
let q = self.gen_prime();
75+
// let p = self.rng.gen_prime(self.bit_size);
76+
// let q = self.rng.gen_prime(self.bit_size);
5777
let n = &p * &q;
5878
let phi = &n - &p - &q + BigUint::from(1_u32);
59-
let (mut x, _, d) = exgcd(&e, &phi);
79+
let result = BigInt::extended_gcd(&e.to_bigint().unwrap(), &phi.to_bigint().unwrap());
80+
let (mut x, d) = (result.x, result.gcd);
6081
if d == One::one() {
6182
if x < Zero::zero() {
6283
let k = (-&x).to_biguint().unwrap() / &phi + BigUint::from(1_u32);
@@ -75,6 +96,21 @@ impl PrimeUtils {
7596
}
7697
}
7798

99+
fn get_rank<T>(testee: &T) -> T
100+
where
101+
T: RefNum<T> + From<u32> + Ord + Clone,
102+
for<'a> &'a T: RefNum<T>,
103+
{
104+
let zero = T::from(0_u32);
105+
let one = T::from(1_u32);
106+
let two = T::from(2_u32);
107+
let mut num: T = testee.clone() - &one;
108+
while &num % &two == zero {
109+
num = num / &two;
110+
}
111+
num
112+
}
113+
78114
fn encrypt_uint(private_key: &RSAPublicKey, message: &BigUint) -> BigUint {
79115
let (n, e) = private_key;
80116
quick_pow(message.clone(), e.clone(), Some(n.clone()))
@@ -85,35 +121,57 @@ fn decrypt_uint(public_key: &RSAPrivateKey, secret: &BigUint) -> BigUint {
85121
quick_pow(secret.clone(), d.clone(), Some(n.clone()))
86122
}
87123

124+
pub fn oct_to_base64(octet: &BigUint) -> String {
125+
base64::encode(octet.to_bytes_be())
126+
}
127+
128+
pub fn base64_to_oct(base64: &str) -> BigUint {
129+
BigUint::from_bytes_be(&base64::decode(base64.as_bytes()).unwrap())
130+
}
131+
88132
pub fn oct_to_str(encoded: BigUint) -> String {
89-
let ret = unsafe {
133+
unsafe {
90134
String::from_utf8_unchecked(encoded
91135
.to_bytes_be()
92136
)
93-
};
94-
println!("From oct is: {}", ret);
95-
ret
137+
}
96138
}
97139

98140
fn str_to_oct(to_encode: &str) -> BigUint {
99141
BigUint::from_radix_be(to_encode.as_bytes(), 256).unwrap()
100142
}
101143

102144
pub fn encrypt(private_key: &RSAPublicKey, message: &str) -> String {
103-
oct_to_str(encrypt_uint(private_key, &str_to_oct(message)))
145+
oct_to_base64(&encrypt_uint(private_key, &str_to_oct(message)))
104146
}
105147

106148
pub fn decrypt(public_key: &RSAPrivateKey, secret: &str) -> String {
107-
oct_to_str(decrypt_uint(public_key, &str_to_oct(secret)))
149+
oct_to_str(decrypt_uint(public_key, &base64_to_oct(secret)))
108150
}
109151

110152
pub fn miller_rabin_single<T>(testee: &T, base: T) -> bool
111153
where
112-
T: RefNum<T> + From<u32> + Ord + Clone,
154+
T: RefNum<T> + From<u32> + Ord + Clone + Display,
113155
for<'a> &'a T: RefNum<T>,
114156
{
115-
let exp: T = testee.clone() - T::from(1_u32);
116-
quick_pow(base, exp, Some(testee.clone())) == 1.into()
157+
let mut exp: T = get_rank(testee);
158+
// println!("testee is {}, rank is {}", &testee, &exp);
159+
let one: T = 1.into();
160+
let two: T = 2.into();
161+
let testee_minus_one = testee - &one;
162+
let mut intermediate = quick_pow(base.clone(), exp.clone(), Some(testee.clone()));
163+
if intermediate == one {
164+
return true;
165+
}
166+
exp = exp * &two;
167+
while &exp <= testee {
168+
intermediate = &intermediate * &intermediate % testee;
169+
if intermediate == testee_minus_one {
170+
return true;
171+
}
172+
exp = exp * &two;
173+
}
174+
false
117175
}
118176

119177
pub fn quick_pow<T>(base: T, mut exp: T, prime: Option<T>) -> T

0 commit comments

Comments
 (0)