Skip to content
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): bench rsa vs class #37

Closed
wants to merge 16 commits into from
13 changes: 13 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,17 @@ git = "https://github.com/KZen-networks/curv"
tag = "v0.2.6"
features = ["ec_secp256k1"]

[dev-dependencies]
criterion = ">=0.2"
rug = "1.2.1"
sha2 = "0.9.1"

[[bench]]
name = "bench-vdf-rsa"
path = "benches/vdf/rsa_group.rs"
harness = false

[[bench]]
name = "bench-vdf-class"
path = "benches/vdf/class_group.rs"
harness = false
41 changes: 41 additions & 0 deletions benches/vdf/class_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#[macro_use]
extern crate criterion;

use class_group::primitives::vdf::VDF;
use criterion::Criterion;
use curv::BigInt;
use class_group::ABDeltaTriple;

fn benches_class(c: &mut Criterion) {
let bench_eval = |c: &mut Criterion, difficulty: &BigInt, a_b_delta: &ABDeltaTriple, seed: &BigInt| {
c.bench_function(&format!("eval with difficulty {}", difficulty), move |b| {
b.iter(|| VDF::eval(&a_b_delta, &seed, &difficulty))
});
};
let bench_verify =
|c: &mut Criterion, difficulty: &BigInt, vdf_out_proof: &VDF| {
c.bench_function(
&format!("verify with difficulty {}", difficulty),
move |b| b.iter(|| vdf_out_proof.verify()),
);
};

let sec = 1600;
const TEST_HASH: &str = "1eeb30c7163271850b6d018e8282093ac6755a771da6267edf6c9b4fce9242ba";
let seed = BigInt::from_str_radix(TEST_HASH, 16).unwrap();
let a_b_delta = VDF::setup(sec, &seed);

for &i in &[1_000, 2_000, 5_000, 10_000, 100_000, 1_000_000] {
// precompute for verification
let t = BigInt::from(i);
let vdf_out_proof = VDF::eval(&a_b_delta, &seed, &t);
let res = vdf_out_proof.verify();
assert!(res.is_ok());

bench_eval(c, &t, &a_b_delta, &seed);
bench_verify(c, &t, &vdf_out_proof)
}
}

criterion_group!(benches, benches_class);
criterion_main!(benches);
132 changes: 132 additions & 0 deletions benches/vdf/rsa_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#[macro_use]
extern crate criterion;

use criterion::Criterion;
use rug::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.clone().to_string_radix(16).as_bytes());
let result_hex = hasher.finalize();
let result_hex_str = format!("{:#x}", result_hex);
let result_int = Integer::from_str_radix(&result_hex_str, 16).unwrap();

// invert to get enough security bits
match result_int.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_string_radix(16).as_bytes());
hasher.update("\n".as_bytes());
}
let hashed_hex = hasher.finalize();
let hashed_hex_str = format!("{:#x}", hashed_hex);
let hashed_int = Integer::from_str_radix(&hashed_hex_str, 16).unwrap();

// invert to get enough security bits
let inverse = match hashed_int.invert(&modulus.clone()) {
Ok(inverse) => inverse,
Err(unchanged) => unchanged,
};

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)),
);
};

// (M13 prime)
const MODULUS: &str = "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"; // (M13 prime)
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 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);
56 changes: 27 additions & 29 deletions src/primitives/vdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ pub struct VDF {
pub y: BinaryQF,
pub pi: BinaryQF,
pub t: BigInt,
a_b_delta: ABDeltaTriple,
}

impl VDF {
pub fn setup(security_param: usize) -> BigInt {
pub fn setup(security_param: usize, x: &BigInt) -> ABDeltaTriple {
let mut disc: BigInt;

disc = -BigInt::sample(security_param.clone()); // TODO: double check 1600 bits determinant should provide 120 bit security
Expand All @@ -29,22 +30,24 @@ impl VDF {
disc = -BigInt::sample(security_param);
}

disc
}

//algorithm 3 from https://eprint.iacr.org/2018/623.pdf
pub fn eval(disc: &BigInt, x: &BigInt, t: &BigInt) -> Self {
unsafe {
pari_init(1000000000, 2);
}
//first line: g <- H_G(x). We will use x to seed a prng and use the prng to choose random
// a and b.
let (a, b) = h_g(disc, x);
let a_b_delta = ABDeltaTriple {
let (a, b) = h_g(&disc, x);
ABDeltaTriple {
a,
b,
delta: disc.clone(),
};
}
}

//algorithm 3 from https://eprint.iacr.org/2018/623.pdf
pub fn eval(a_b_delta: &ABDeltaTriple, x: &BigInt, t: &BigInt) -> Self {
unsafe {
pari_init(1000000000, 2);
}

let g = BinaryQF::binary_quadratic_form_disc(&a_b_delta).reduce();
let mut y = g.clone();
Expand All @@ -55,7 +58,7 @@ impl VDF {
i = i + BigInt::one();
}
let l = hash_to_prime(&g, &y);
println!("y: {:?}", y.clone());
// println!("y: {:?}", y.clone());

//algorithm 4 from https://eprint.iacr.org/2018/623.pdf
// long division TODO: consider alg 5 instead
Expand All @@ -64,7 +67,7 @@ impl VDF {
let mut r = BigInt::one();
let mut r2: BigInt;
let two = BigInt::from(2);
let mut pi = BinaryQF::binary_quadratic_form_principal(&disc);
let mut pi = BinaryQF::binary_quadratic_form_principal(&a_b_delta.delta);

while &i < t {
r2 = &r * &two;
Expand All @@ -79,27 +82,23 @@ impl VDF {
y,
pi,
t: t.clone(),
a_b_delta: a_b_delta.clone(),
};
vdf
}

//algorithm 2 from https://eprint.iacr.org/2018/623.pdf
pub fn verify(&self, disc: &BigInt) -> Result<(), ErrorReason> {
pub fn verify(&self) -> Result<(), ErrorReason> {
unsafe {
pari_init(1000000000, 2);
}
let (a, b) = h_g(disc, &self.x);
let a_b_delta = ABDeltaTriple {
a,
b,
delta: disc.clone(),
};
let g = BinaryQF::binary_quadratic_form_disc(&a_b_delta).reduce();

let g = BinaryQF::binary_quadratic_form_disc(&self.a_b_delta).reduce();

// test that g,y are elements of the class : https://eprint.iacr.org/2018/712.pdf 2.1 line 0
if &g.discriminant() != disc
|| &self.y.discriminant() != disc
|| &self.pi.discriminant() != disc
if &g.discriminant() != &self.a_b_delta.delta
|| &self.y.discriminant() != &self.a_b_delta.delta
|| &self.pi.discriminant() != &self.a_b_delta.delta
{
return Err(ErrorReason::VDFVerifyError);
}
Expand Down Expand Up @@ -154,18 +153,17 @@ mod tests {
#[test]
fn test_vdf_valid_proof() {
let sec = 1600;
let disc = VDF::setup(sec);
let t = BigInt::sample(10); // TODO: make sure T is not too big to avoid memory overflow

let x = BigInt::from(10);
let a_b_delta = VDF::setup(sec, &x);

let mut i = 0;
while i < 10 {
let start = Instant::now();
let vdf_out_proof = VDF::eval(&disc, &x, &t);
let vdf_out_proof = VDF::eval(&a_b_delta, &x, &t);
let duration1 = start.elapsed();
let start = Instant::now();
let res = vdf_out_proof.verify(&disc);
let res = vdf_out_proof.verify();
let duration2 = start.elapsed();
i = i + 1;

Expand All @@ -182,16 +180,16 @@ mod tests {
#[should_panic]
fn test_vdf_wrong_proof() {
let sec = 1600;
let disc = VDF::setup(sec);
let t = BigInt::sample(10);
let x = BigInt::from(10);
let a_b_delta = VDF::setup(sec, &x);

let mut vdf_out_proof = VDF::eval(&disc, &x, &t);
let mut vdf_out_proof = VDF::eval(&a_b_delta, &x, &t);
println!("before: {:?}", vdf_out_proof.y.clone());

vdf_out_proof.y = vdf_out_proof.y.exp(&BigInt::from(3));
println!("after: {:?}", vdf_out_proof.y.clone());
let res = vdf_out_proof.verify(&disc);
let res = vdf_out_proof.verify();

assert!(res.is_ok());
}
Expand Down