-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test(VDF): add bench tests for VDF in rsa group #42
base: master
Are you sure you want to change the base?
Changes from 3 commits
5f3be9f
e778a1d
0005c53
3b73170
f590cd6
72767a3
04c8818
183b69c
ecfa87e
5f440ce
cde9abe
cddeb50
16b1817
34ebb4a
ee291ab
b5ed110
7f17149
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#[macro_use] | ||
extern crate criterion; | ||
|
||
use criterion::Criterion; | ||
use rug::{integer::Order, Integer}; | ||
use sha2::{Digest, Sha256}; | ||
|
||
/// algo_2 from the paper | ||
fn verify(modulus: &Integer, g: &Integer, t: u64, y: &Integer, pi: &Integer) -> bool { | ||
let modulus = modulus.clone(); | ||
|
||
let l = hash_to_prime(&modulus, &[&g, &y]); | ||
|
||
let r = Integer::from(2).pow_mod(&Integer::from(t), &l).unwrap(); | ||
let pi_l = pi.clone().pow_mod(&l, &modulus).unwrap(); | ||
let g_r = g.clone().pow_mod(&r, &modulus).unwrap(); | ||
let pi_l_g_r = pi_l * g_r; | ||
|
||
Integer::from(pi_l_g_r.div_rem_floor(modulus.clone()).1) == y.clone() | ||
} | ||
|
||
/// algo_3 from the paper | ||
fn eval(modulus: &Integer, g: &Integer, t: u64) -> (Integer, Integer) { | ||
let modulus = modulus.clone(); | ||
|
||
// y <- (g^2)^t | ||
let mut y = g.clone(); | ||
for _ in 0..t { | ||
y = y.clone() * y.clone(); | ||
y = y.div_rem_floor(modulus.clone()).1; | ||
} | ||
|
||
let l = hash_to_prime(&modulus, &[&g, &y]); | ||
|
||
// algo_4 from the paper, long division | ||
// TODO: consider algo_5 instead | ||
let mut b: Integer; | ||
let mut r = Integer::from(1); | ||
let mut r2: Integer; | ||
let two = Integer::from(2); | ||
let mut pi = Integer::from(1); | ||
|
||
for _ in 0..t { | ||
r2 = r.clone() * two.clone(); | ||
b = r2.clone().div_rem_floor(l.clone()).0; | ||
r = r2.clone().div_rem_floor(l.clone()).1; | ||
let pi_2 = pi.clone().pow_mod(&two, &modulus).unwrap(); | ||
let g_b = g.clone().pow_mod(&b, &modulus).unwrap(); | ||
pi = pi_2 * g_b; | ||
} | ||
pi = Integer::from(pi.div_rem_floor(modulus.clone()).1); | ||
(y, pi) | ||
} | ||
|
||
/// int(H("residue"||x)) mod N | ||
fn h_g(modulus: &Integer, seed: &Integer) -> Integer { | ||
let modulus = modulus.clone(); | ||
let mut hasher = Sha256::new(); | ||
hasher.update("residue".as_bytes()); | ||
hasher.update(seed.to_digits::<u8>(Order::Lsf)); | ||
let hashed = Integer::from_digits(&hasher.finalize(), Order::Lsf); | ||
|
||
// inverse, to get enough security bits | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I double checked and we can actually cannot do the inverse trick as it do not provide a random element in the group. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should I run recursive hashing only on the imtermediate hashing result itself, then at the end use them to reconstruct the randomness? Or should I hash->construct->hash->construct repeatedly? The latter seems can offer more entropy? i.e., should I
or
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also come up with another idea. We can actually sha256("part1"||seed) || sha256("part2"||seed) || ... || sha256("part8"||seed) i.e., we keep using the same seed for a part of the input, but introduces "partXXX" to provide different randomness. We then concat then all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think all of the methods above works and we should take the fastest |
||
match hashed.invert(&modulus.clone()) { | ||
Ok(inverse) => inverse, | ||
Err(unchanged) => unchanged, | ||
} | ||
} | ||
|
||
fn hash_to_prime(modulus: &Integer, inputs: &[&Integer]) -> Integer { | ||
let mut hasher = Sha256::new(); | ||
for input in inputs { | ||
hasher.update(input.to_digits::<u8>(Order::Lsf)); | ||
hasher.update("\n".as_bytes()); | ||
} | ||
let hashed = Integer::from_digits(&hasher.finalize(), Order::Lsf); | ||
|
||
// inverse, to get enough security bits | ||
let inverse = match hashed.invert(&modulus.clone()) { | ||
Ok(inverse) => inverse, | ||
Err(unchanged) => unchanged, | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually not needed in this function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need the same trick as #42 (comment) here? |
||
|
||
Integer::from(inverse.next_prime().div_rem_floor(modulus.clone()).1) | ||
} | ||
|
||
fn benches_rsa(c: &mut Criterion) { | ||
let bench_eval = |c: &mut Criterion, difficulty: u64, modulus: &Integer, seed: &Integer| { | ||
c.bench_function(&format!("eval with difficulty {}", difficulty), move |b| { | ||
b.iter(|| eval(&modulus, &seed, difficulty)) | ||
}); | ||
}; | ||
let bench_verify = |c: &mut Criterion, | ||
difficulty: u64, | ||
modulus: &Integer, | ||
seed: &Integer, | ||
y: &Integer, | ||
pi: &Integer| { | ||
c.bench_function( | ||
&format!("verify with difficulty {}", difficulty), | ||
move |b| b.iter(|| verify(&modulus, &seed, difficulty, &y, &pi)), | ||
); | ||
}; | ||
|
||
/// RSA-2048 modulus, taken from [Wikipedia](https://en.wikipedia.org/wiki/RSA_numbers#RSA-2048). | ||
pub const MODULUS: &str = | ||
"251959084756578934940271832400483985714292821262040320277771378360436620207075955562640185258807\ | ||
8440691829064124951508218929855914917618450280848912007284499268739280728777673597141834727026189\ | ||
6375014971824691165077613379859095700097330459748808428401797429100642458691817195118746121515172\ | ||
6546322822168699875491824224336372590851418654620435767984233871847744479207399342365848238242811\ | ||
9816381501067481045166037730605620161967625613384414360383390441495263443219011465754445417842402\ | ||
0924616515723350778707749817125772467962926386356373289912154831438167899885040445364023527381951\ | ||
378636564391212010397122822120720357"; | ||
let modulus = Integer::from_str_radix(MODULUS, 10).unwrap(); | ||
|
||
const TEST_HASH: &str = "1eeb30c7163271850b6d018e8282093ac6755a771da6267edf6c9b4fce9242ba"; | ||
let seed_hash = Integer::from_str_radix(TEST_HASH, 16).unwrap(); | ||
let seed = Integer::from(seed_hash.div_rem_floor(modulus.clone()).1); | ||
|
||
// g <- H_G(x) | ||
let g = h_g(&modulus, &seed); | ||
|
||
for &i in &[1_000, 2_000, 5_000, 10_000, 100_000, 1_000_000] { | ||
// precompute for benchmarking verification | ||
let (y, pi) = eval(&modulus, &g, i); | ||
let result = verify(&modulus, &g, i, &y, &pi); | ||
assert!(result); | ||
|
||
bench_eval(c, i, &modulus, &seed); | ||
bench_verify(c, i, &modulus, &seed, &y, &pi) | ||
} | ||
} | ||
|
||
criterion_group!(benches, benches_rsa); | ||
criterion_main!(benches); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to run
r2.clone().div_rem_floor(l.clone())
only once. (instead of twice)