diff --git a/bip-340/Cargo.toml b/bip-340/Cargo.toml index 8960405..e44b47a 100644 --- a/bip-340/Cargo.toml +++ b/bip-340/Cargo.toml @@ -17,6 +17,9 @@ ff = "0.13" subtle = "*" rand_core = "0.6" +hacspec-concordium = { path = "../concordium" } # 4d4b024b547a1f120f6d6951cbc409c94f8f146a +hacspec-concordium-derive = { path = "../concordium-derive" } # 4d4b024b547a1f120f6d6951cbc409c94f8f146a + [dev-dependencies] quickcheck = "1" quickcheck_macros = "1" diff --git a/bip-340/src/bip-340.rs b/bip-340/src/bip-340.rs index a5b4e6d..881bd2e 100644 --- a/bip-340/src/bip-340.rs +++ b/bip-340/src/bip-340.rs @@ -783,4 +783,28 @@ pub mod GroupTrait { finite(*self).unwrap() } } + + +use hacspec_concordium::*; +use hacspec_concordium_derive::*; + +impl hacspec_concordium::Deserial for Scalar { + // TODO: + fn deserial(_source: &mut R) -> ParseResult { + let buffer: &mut [u8] = &mut []; + let _ = _source.read(buffer)?; + + Ok(Scalar::from_public_byte_seq_be(Seq::::from_native_slice(buffer))) + } } + +impl hacspec_concordium::Serial for Scalar { + // TODO: + fn serial(&self, _out: &mut W) -> Result<(), W::Err> { + _out.write(self.to_public_byte_seq_be().native_slice()); + Ok(()) + } +} + +} + diff --git a/ovn/src/ovn_zk_secp256k1.rs b/ovn/src/ovn_zk_secp256k1.rs index 8dbf265..d5356db 100644 --- a/ovn/src/ovn_zk_secp256k1.rs +++ b/ovn/src/ovn_zk_secp256k1.rs @@ -11,6 +11,7 @@ pub use crate::ovn_zkgroup::*; use hacspec_bip_340::{GroupTrait::*, Point, *}; + impl MGroup for Point { fn pow (p: Self,exp: Self::Scalar) -> Self { point_mul(exp,p) diff --git a/ovn/src/ovn_zkgroup.rs b/ovn/src/ovn_zkgroup.rs index ef5fd60..e8244b9 100644 --- a/ovn/src/ovn_zkgroup.rs +++ b/ovn/src/ovn_zkgroup.rs @@ -359,7 +359,7 @@ where Ok((A::accept(), cast_vote_state_ret)) } -#[derive(SchemaType)] +#[derive(Serialize, SchemaType)] pub struct TallyParameter {} #[hax::receive(contract = "OVN", name = "tally", parameter = "TallyParameter")] diff --git a/ovn/tests/ovn_zk_example.rs b/ovn/tests/ovn_zk_example.rs index 2cdbb9c..ec9a4da 100644 --- a/ovn/tests/ovn_zk_example.rs +++ b/ovn/tests/ovn_zk_example.rs @@ -17,7 +17,7 @@ use quickcheck::*; pub use bls12_381::*; pub use group::{ff::Field, Group}; -pub use hacspec_ovn::{ovn_zkgroup::*, ovn_zk_secp256k1::*}; +pub use hacspec_ovn::{ovn_zk_secp256k1::*, ovn_zkgroup::*}; use rand_core::{RngCore, *}; // use quickcheck::RngCore; @@ -25,230 +25,206 @@ use hacspec_bip_340::{GroupTrait::*, Point, *}; use rand::rngs::StdRng; -#[test] -pub fn zk_group_schorr_zkp_correctness() { - fn test() -> bool { - type G = Point; // Gt; +#[cfg(test)] +pub fn schnorr_zkp_correctness() -> bool { + let mut x: ::Scalar = ::Scalar::random(rand::thread_rng()); + let pow_x = G::g_pow(x); - let mut x: ::Scalar = ::Scalar::random(rand::thread_rng()); - let pow_x = G::g_pow(x); + let random_r: ::Scalar = ::Scalar::random(rand::thread_rng()); + let pi: SchnorrZKPCommit = schnorr_zkp(random_r, pow_x, x); - let random_r: ::Scalar = ::Scalar::random(rand::thread_rng()); - let pi: SchnorrZKPCommit = schnorr_zkp(random_r, pow_x, x); + let valid = schnorr_zkp_validate::(pow_x, pi); + valid +} - let valid = schnorr_zkp_validate::(pow_x, pi); - valid - } +#[test] +pub fn schorr_zkp_correctness() { + QuickCheck::new() + .tests(1000) + .quickcheck(schnorr_zkp_correctness:: as fn() -> bool) +} - QuickCheck::new().tests(1000).quickcheck(test as fn() -> bool) +#[cfg(test)] +pub fn or_zkp_correctness(v: bool) -> bool { + let random_w: ::Scalar = ::Scalar::random(rand::thread_rng()); + let random_r: ::Scalar = ::Scalar::random(rand::thread_rng()); + let random_d: ::Scalar = ::Scalar::random(rand::thread_rng()); + let random_h: ::Scalar = ::Scalar::random(rand::thread_rng()); + let random_x: ::Scalar = ::Scalar::random(rand::thread_rng()); + let mut h = G::g_pow(random_h); + let x = random_x; + let pi: OrZKPCommit = zkp_one_out_of_two(random_w, random_r, random_d, h, x, v); + let valid = zkp_one_out_of_two_validate::(h, pi); + valid } -// #[test] -// pub fn schorr_zkp_secp256k1_correctness() { -// fn test(random_x: u32, random_r: u32) -> bool { -// type Z = Z_curve; -// type G = Group_curve; +#[test] +// TODO: Fix inverse opeation, should make this test parse +pub fn or_zkp_secp256k1_correctness() { + QuickCheck::new() + .tests(10) + .quickcheck(or_zkp_correctness:: as fn(bool) -> bool) +} -// let x: Z_curve = Z::random_field_elem(random_x); -// let pow_x = G::g_pow(x); +#[cfg(test)] +pub fn sum_to_zero() { + let mut xis: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut g_pow_xis: [G; n] = [G::identity(); n]; + use rand::random; + for i in 0..n { + xis[i] = G::Scalar::random(rand::thread_rng()); + g_pow_xis[i] = G::g_pow(xis[i]); + } -// let pi: SchnorrZKPCommit = schnorr_zkp(random_r, pow_x, x); + let mut res = G::identity(); + for i in 0..n { + let g_pow_yi = compute_g_pow_yi::(i, g_pow_xis); + res = res + G::pow(g_pow_yi, xis[i]); + } -// let valid = schnorr_zkp_validate::(pow_x, pi); -// valid -// } + assert!(res == G::identity()); +} -// QuickCheck::new() -// .tests(10) -// .quickcheck(test as fn(u32, u32) -> bool) +// #[test] +// pub fn sum_to_zero_z89() { +// sum_to_zero::() // } -// #[cfg(test)] -// pub fn or_zkp_correctness>( -// random_w: u32, -// random_r: u32, -// random_d: u32, -// random_h: u32, -// random_x: u32, -// v: bool, -// ) -> bool { -// let mut h = G::g_pow(Z::random_field_elem(random_h)); -// let x = Z::random_field_elem(random_x); -// let pi: OrZKPCommit = zkp_one_out_of_two(random_w, random_r, random_d, h, x, v); -// let valid = zkp_one_out_of_two_validate::(h, pi); -// valid -// } +#[test] +pub fn sum_to_zero_secp256k1() { + sum_to_zero::() +} -// #[test] -// pub fn or_zkp_correctness_z89(){ -// QuickCheck::new() -// .tests(10000) -// .quickcheck(or_zkp_correctness:: as fn(u32, u32, u32, u32, u32, bool) -> bool) -// } +#[cfg(test)] +pub fn test_correctness( + votes: [bool; n], + xis: [G::Scalar; n], + rp_zkp_randoms: [G::Scalar; n], + cvp_zkp_random_ws1: [G::Scalar; n], + cvp_zkp_random_rs1: [G::Scalar; n], + cvp_zkp_random_ds1: [G::Scalar; n], + cvp_zkp_random_ws2: [G::Scalar; n], + cvp_zkp_random_rs2: [G::Scalar; n], + cvp_zkp_random_ds2: [G::Scalar; n], +) -> bool +where + G::Scalar: hacspec_concordium::Serial + hacspec_concordium::Deserial, +{ + // Setup the context + let mut ctx = hacspec_concordium::test_infrastructure::ReceiveContextTest::empty(); + + let mut state: OvnContractState = init_ovn_contract().unwrap(); + + for i in 0..n { + let parameter = RegisterParam:: { + rp_i: i as u32, + rp_xi: xis[i], + rp_zkp_random: rp_zkp_randoms[i], + }; + let parameter_bytes = to_bytes(¶meter); + (_, state) = + register_vote::(ctx.clone().set_parameter(¶meter_bytes), state).unwrap(); + } -// #[test] -// // TODO: Fix inverse opeation, should make this test parse -// pub fn or_zkp_secp256k1_correctness() { -// QuickCheck::new() -// .tests(10) -// .quickcheck(or_zkp_correctness:: as fn(u32, u32, u32, u32, u32, bool) -> bool) -// } + for i in 0..n { + let parameter = CastVoteParam:: { + cvp_i: i as u32, + cvp_xi: xis[i], + cvp_zkp_random_w: cvp_zkp_random_ws1[i], + cvp_zkp_random_r: cvp_zkp_random_rs1[i], + cvp_zkp_random_d: cvp_zkp_random_ds1[i], + cvp_vote: votes[i], + }; + let parameter_bytes = to_bytes(¶meter); + (_, state) = + commit_to_vote::(ctx.clone().set_parameter(¶meter_bytes), state) + .unwrap(); + } -// #[cfg(test)] -// pub fn sum_to_zero, const n: usize>() { -// let mut xis: [Z::field_type; n] = [Z::field_zero(); n]; -// let mut g_pow_xis: [G::group_type; n] = [G::group_one(); n]; -// use rand::random; -// for i in 0..n { -// xis[i] = Z::random_field_elem(random()); -// g_pow_xis[i] = G::g_pow(xis[i]); -// } - -// let mut res = G::group_one(); -// for i in 0..n { -// let g_pow_yi = compute_g_pow_yi::(i, g_pow_xis); -// res = G::prod(res, G::pow(g_pow_yi, xis[i])); -// } - -// assert!(res == G::group_one()); -// } + for i in 0..n { + let parameter = CastVoteParam:: { + cvp_i: i as u32, + cvp_xi: xis[i], + cvp_zkp_random_w: cvp_zkp_random_ws2[i], + cvp_zkp_random_r: cvp_zkp_random_rs2[i], + cvp_zkp_random_d: cvp_zkp_random_ds2[i], + cvp_vote: votes[i], + }; + let parameter_bytes = to_bytes(¶meter); + (_, state) = + cast_vote::(ctx.clone().set_parameter(¶meter_bytes), state).unwrap(); + } -// #[test] -// pub fn sum_to_zero_z89() { -// sum_to_zero::() -// } + let parameter = TallyParameter {}; + let parameter_bytes = to_bytes(¶meter); + ctx = ctx.set_parameter(¶meter_bytes); -// #[test] -// pub fn sum_to_zero_secp256k1() { -// sum_to_zero::() -// } + (_, state) = tally_votes::(ctx.clone(), state).unwrap(); -// #[cfg(test)] -// pub fn test_correctness, const n: usize, A: HasActions>( -// votes: [bool; n], -// xis: [Z::field_type; n], -// rp_zkp_randoms: [u32; n], -// cvp_zkp_random_ws1: [u32; n], -// cvp_zkp_random_rs1: [u32; n], -// cvp_zkp_random_ds1: [u32; n], -// cvp_zkp_random_ws2: [u32; n], -// cvp_zkp_random_rs2: [u32; n], -// cvp_zkp_random_ds2: [u32; n], -// ) -> bool { -// // Setup the context -// let mut ctx = hacspec_concordium::test_infrastructure::ReceiveContextTest::empty(); - -// let mut state: OvnContractState = init_ovn_contract().unwrap(); - -// for i in 0..n { -// let parameter = RegisterParam:: { -// rp_i: i as u32, -// rp_xi: xis[i], -// rp_zkp_random: rp_zkp_randoms[i], -// }; -// let parameter_bytes = to_bytes(¶meter); -// (_, state) = -// register_vote::(ctx.clone().set_parameter(¶meter_bytes), state) -// .unwrap(); -// } - -// for i in 0..n { -// let parameter = CastVoteParam:: { -// cvp_i: i as u32, -// cvp_xi: xis[i], -// cvp_zkp_random_w: cvp_zkp_random_ws1[i], -// cvp_zkp_random_r: cvp_zkp_random_rs1[i], -// cvp_zkp_random_d: cvp_zkp_random_ds1[i], -// cvp_vote: votes[i], -// }; -// let parameter_bytes = to_bytes(¶meter); -// (_, state) = -// commit_to_vote::(ctx.clone().set_parameter(¶meter_bytes), state) -// .unwrap(); -// } - -// for i in 0..n { -// let parameter = CastVoteParam:: { -// cvp_i: i as u32, -// cvp_xi: xis[i], -// cvp_zkp_random_w: cvp_zkp_random_ws2[i], -// cvp_zkp_random_r: cvp_zkp_random_rs2[i], -// cvp_zkp_random_d: cvp_zkp_random_ds2[i], -// cvp_vote: votes[i], -// }; -// let parameter_bytes = to_bytes(¶meter); -// (_, state) = -// cast_vote::(ctx.clone().set_parameter(¶meter_bytes), state).unwrap(); -// } - -// let parameter = TallyParameter {}; -// let parameter_bytes = to_bytes(¶meter); -// ctx = ctx.set_parameter(¶meter_bytes); - -// (_, state) = tally_votes::(ctx.clone(), state).unwrap(); - -// let mut count = 0u32; -// for v in votes { -// if v { -// count = count + 1; // += 1 does not work correctly -// } -// } - -// assert_eq!(state.tally, count); -// state.tally == count -// } + let mut count = 0u32; + for v in votes { + if v { + count = count + 1; // += 1 does not work correctly + } + } -// #[cfg(test)] -// fn randomized_full_test, const n: usize> () -> bool { -// use rand::random; -// let mut votes: [bool; n] = [false; n]; -// let mut xis: [Z::field_type; n] = [Z::field_zero(); n]; -// let mut rp_zkp_randoms: [u32; n] = [0; n]; -// let mut cvp_zkp_random_ws1: [u32; n] = [0; n]; -// let mut cvp_zkp_random_rs1: [u32; n] = [0; n]; -// let mut cvp_zkp_random_ds1: [u32; n] = [0; n]; - -// let mut cvp_zkp_random_ws2: [u32; n] = [0; n]; -// let mut cvp_zkp_random_rs2: [u32; n] = [0; n]; -// let mut cvp_zkp_random_ds2: [u32; n] = [0; n]; - -// for i in 0..n { -// votes[i] = random(); -// xis[i] = Z::random_field_elem(random()); -// rp_zkp_randoms[i] = random(); -// cvp_zkp_random_ws1[i] = random(); -// cvp_zkp_random_rs1[i] = random(); -// cvp_zkp_random_ds1[i] = random(); -// cvp_zkp_random_ws2[i] = random(); -// cvp_zkp_random_rs2[i] = random(); -// cvp_zkp_random_ds2[i] = random(); -// } - -// test_correctness::( -// votes, -// xis, -// rp_zkp_randoms, -// cvp_zkp_random_ws1, -// cvp_zkp_random_rs1, -// cvp_zkp_random_ds1, -// cvp_zkp_random_ws2, -// cvp_zkp_random_rs2, -// cvp_zkp_random_ds2, -// ) -// } + assert_eq!(state.tally, count); + state.tally == count +} -// // #[concordium_test] -// #[test] -// fn test_full_z89() { -// QuickCheck::new() -// .tests(100) -// .quickcheck(randomized_full_test:: as fn() -> bool) -// } +#[cfg(test)] +fn randomized_full_test () -> bool where + G::Scalar: hacspec_concordium::Serial + hacspec_concordium::Deserial, +{ + use rand::random; + let mut votes: [bool; n] = [false; n]; + let mut xis: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut rp_zkp_randoms: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut cvp_zkp_random_ws1: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut cvp_zkp_random_rs1: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut cvp_zkp_random_ds1: [G::Scalar; n] = [G::Scalar::ZERO; n]; + + let mut cvp_zkp_random_ws2: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut cvp_zkp_random_rs2: [G::Scalar; n] = [G::Scalar::ZERO; n]; + let mut cvp_zkp_random_ds2: [G::Scalar; n] = [G::Scalar::ZERO; n]; + + for i in 0..n { + votes[i] = random(); + xis[i] = G::Scalar::random(rand::thread_rng()); + rp_zkp_randoms[i] = G::Scalar::random(rand::thread_rng()); + cvp_zkp_random_ws1[i] = G::Scalar::random(rand::thread_rng()); + cvp_zkp_random_rs1[i] = G::Scalar::random(rand::thread_rng()); + cvp_zkp_random_ds1[i] = G::Scalar::random(rand::thread_rng()); + cvp_zkp_random_ws2[i] = G::Scalar::random(rand::thread_rng()); + cvp_zkp_random_rs2[i] = G::Scalar::random(rand::thread_rng()); + cvp_zkp_random_ds2[i] = G::Scalar::random(rand::thread_rng()); + } -// // #[concordium_test] -// #[test] -// fn test_full_secp256k1() { -// QuickCheck::new() -// .tests(1) -// .quickcheck(randomized_full_test:: as fn() -> bool) -// } + test_correctness::( + votes, + xis, + rp_zkp_randoms, + cvp_zkp_random_ws1, + cvp_zkp_random_rs1, + cvp_zkp_random_ds1, + cvp_zkp_random_ws2, + cvp_zkp_random_rs2, + cvp_zkp_random_ds2, + ) +} + +// // // #[concordium_test] +// // #[test] +// // fn test_full_z89() { +// // QuickCheck::new() +// // .tests(100) +// // .quickcheck(randomized_full_test:: as fn() -> bool) +// // } + +// #[concordium_test] +#[test] +fn test_full_secp256k1() { + QuickCheck::new() + .tests(1) + .quickcheck(randomized_full_test:: as fn() -> bool) +}