mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 22:57:59 -05:00
refactor(zk): factorize test params generation between proofs
This commit is contained in:
committed by
Nicolas Sarlin
parent
ad1c1852e4
commit
beb3f790c8
@@ -146,3 +146,217 @@ pub mod pke;
|
||||
pub mod pke_v2;
|
||||
pub mod range;
|
||||
pub mod rlwe;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#![allow(non_snake_case)]
|
||||
use std::fmt::Display;
|
||||
|
||||
use bincode::ErrorKind;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::curve_api::Compressible;
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
pub(super) const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
pub(super) enum Compress {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
pub(super) fn serialize_then_deserialize<
|
||||
Params: Compressible + Serialize + for<'de> Deserialize<'de>,
|
||||
>(
|
||||
public_params: &Params,
|
||||
compress: Compress,
|
||||
) -> bincode::Result<Params>
|
||||
where
|
||||
<Params as Compressible>::Compressed: Serialize + for<'de> Deserialize<'de>,
|
||||
<Params as Compressible>::UncompressError: Display,
|
||||
{
|
||||
match compress {
|
||||
Compress::Yes => Params::uncompress(bincode::deserialize(&bincode::serialize(
|
||||
&public_params.compress(),
|
||||
)?)?)
|
||||
.map_err(|e| Box::new(ErrorKind::Custom(format!("Failed to uncompress: {}", e)))),
|
||||
Compress::No => bincode::deserialize(&bincode::serialize(&public_params)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn polymul_rev(a: &[i64], b: &[i64]) -> Vec<i64> {
|
||||
assert_eq!(a.len(), b.len());
|
||||
let d = a.len();
|
||||
let mut c = vec![0i64; d];
|
||||
|
||||
for i in 0..d {
|
||||
for j in 0..d {
|
||||
if i + j < d {
|
||||
c[i + j] = c[i + j].wrapping_add(a[i].wrapping_mul(b[d - j - 1]));
|
||||
} else {
|
||||
c[i + j - d] = c[i + j - d].wrapping_sub(a[i].wrapping_mul(b[d - j - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
/// Parameters needed for a PKE zk proof test
|
||||
#[derive(Copy, Clone)]
|
||||
pub(super) struct PkeTestParameters {
|
||||
pub(super) d: usize,
|
||||
pub(super) k: usize,
|
||||
pub(super) B: u64,
|
||||
pub(super) q: u64,
|
||||
pub(super) t: u64,
|
||||
pub(super) msbs_zero_padding_bit_count: u64,
|
||||
}
|
||||
|
||||
/// An encrypted PKE ciphertext
|
||||
pub struct PkeTestCiphertext {
|
||||
pub(super) c1: Vec<i64>,
|
||||
pub(super) c2: Vec<i64>,
|
||||
}
|
||||
|
||||
/// A randomly generated testcase of pke encryption
|
||||
pub(super) struct PkeTestcase {
|
||||
pub(super) a: Vec<i64>,
|
||||
pub(super) e1: Vec<i64>,
|
||||
pub(super) e2: Vec<i64>,
|
||||
pub(super) r: Vec<i64>,
|
||||
pub(super) m: Vec<i64>,
|
||||
pub(super) b: Vec<i64>,
|
||||
pub(super) metadata: [u8; METADATA_LEN],
|
||||
s: Vec<i64>,
|
||||
}
|
||||
|
||||
impl PkeTestcase {
|
||||
pub(super) fn gen(rng: &mut StdRng, params: PkeTestParameters) -> Self {
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q: _q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = params;
|
||||
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
Self {
|
||||
a,
|
||||
e1,
|
||||
e2,
|
||||
r,
|
||||
m,
|
||||
b,
|
||||
metadata,
|
||||
s,
|
||||
}
|
||||
}
|
||||
|
||||
/// Encrypt using compact pke
|
||||
pub(super) fn encrypt(&self, params: PkeTestParameters) -> PkeTestCiphertext {
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B: _B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count: _msbs_zero_padding_bit_count,
|
||||
} = params;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
// delta takes the encoding with the padding bit
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
|
||||
let c1 = polymul_rev(&self.a, &self.r)
|
||||
.into_iter()
|
||||
.zip(self.e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for (i, c2) in c2.iter_mut().enumerate() {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
self.b[d - j - i - 1]
|
||||
} else {
|
||||
self.b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(self.r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
*c2 = dot
|
||||
.wrapping_add(self.e2[i])
|
||||
.wrapping_add((delta * self.m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// Check decryption
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += self.s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(params.t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
|
||||
assert_eq!(self.m, m_roundtrip);
|
||||
|
||||
PkeTestCiphertext { c1, c2 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,165 +1220,69 @@ pub fn verify<G: Curve>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::test::*;
|
||||
use super::*;
|
||||
use bincode::ErrorKind;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
/// Compact key params used with pkev1
|
||||
pub(super) const PKEV1_TEST_PARAMS: PkeTestParameters = PkeTestParameters {
|
||||
d: 1024,
|
||||
k: 320,
|
||||
B: 4398046511104, // 2**42
|
||||
q: 0,
|
||||
t: 32, // 2b msg, 2b carry, 1b padding
|
||||
msbs_zero_padding_bit_count: 1,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_pke() {
|
||||
let d = 2048;
|
||||
let k = 320;
|
||||
let b_i = 512;
|
||||
let q = 0;
|
||||
let t = 1024;
|
||||
let msbs_zero_padding_bit_count = 1;
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = PKEV1_TEST_PARAMS;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
// delta takes the encoding with the padding bit
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let rng = &mut StdRng::seed_from_u64(0);
|
||||
|
||||
let polymul_rev = |a: &[i64], b: &[i64]| -> Vec<i64> {
|
||||
assert_eq!(a.len(), b.len());
|
||||
let d = a.len();
|
||||
let mut c = vec![0i64; d];
|
||||
let testcase = PkeTestcase::gen(rng, PKEV1_TEST_PARAMS);
|
||||
|
||||
for i in 0..d {
|
||||
for j in 0..d {
|
||||
if i + j < d {
|
||||
c[i + j] = c[i + j].wrapping_add(a[i].wrapping_mul(b[d - j - 1]));
|
||||
} else {
|
||||
c[i + j - d] = c[i + j - d].wrapping_sub(a[i].wrapping_mul(b[d - j - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
let ct = testcase.encrypt(PKEV1_TEST_PARAMS);
|
||||
|
||||
c
|
||||
};
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
let c1 = polymul_rev(&a, &r)
|
||||
.into_iter()
|
||||
.zip(e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for i in 0..k {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
b[d - j - i - 1]
|
||||
} else {
|
||||
b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
c2[i] = dot
|
||||
.wrapping_add(e2[i])
|
||||
.wrapping_add((delta * m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut fake_metadata = [255u8; METADATA_LEN];
|
||||
fake_metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(effective_cleartext_t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
|
||||
type Curve = crate::curve_api::Bls12_446;
|
||||
|
||||
let serialize_then_deserialize = |public_param: &PublicParams<Curve>,
|
||||
compress: bool|
|
||||
-> bincode::Result<PublicParams<Curve>> {
|
||||
match compress {
|
||||
true => PublicParams::uncompress(bincode::deserialize(&bincode::serialize(
|
||||
&public_param.clone().compress(),
|
||||
)?)?)
|
||||
.map_err(|e| Box::new(ErrorKind::Custom(format!("Failed to uncompress: {}", e)))),
|
||||
false => bincode::deserialize(&bincode::serialize(&public_param)?),
|
||||
}
|
||||
};
|
||||
|
||||
// To check management of bigger k_max from CRS during test
|
||||
let crs_k = k + 1 + (rng.gen::<usize>() % (d - k));
|
||||
|
||||
let original_public_param =
|
||||
crs_gen::<Curve>(d, crs_k, b_i, q, t, msbs_zero_padding_bit_count, rng);
|
||||
crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
|
||||
let public_param_that_was_compressed =
|
||||
serialize_then_deserialize(&original_public_param, true).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::Yes).unwrap();
|
||||
let public_param_that_was_not_compressed =
|
||||
serialize_then_deserialize(&original_public_param, false).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::No).unwrap();
|
||||
|
||||
for (
|
||||
public_param,
|
||||
@@ -1400,29 +1304,29 @@ mod tests {
|
||||
[false, true]
|
||||
) {
|
||||
let (public_commit, private_commit) = commit(
|
||||
a.clone(),
|
||||
b.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
testcase.a.clone(),
|
||||
testcase.b.clone(),
|
||||
ct.c1.clone(),
|
||||
ct.c2.clone(),
|
||||
if use_fake_r {
|
||||
fake_r.clone()
|
||||
} else {
|
||||
r.clone()
|
||||
testcase.r.clone()
|
||||
},
|
||||
if use_fake_e1 {
|
||||
fake_e1.clone()
|
||||
} else {
|
||||
e1.clone()
|
||||
testcase.e1.clone()
|
||||
},
|
||||
if use_fake_m {
|
||||
fake_m.clone()
|
||||
} else {
|
||||
m.clone()
|
||||
testcase.m.clone()
|
||||
},
|
||||
if use_fake_e2 {
|
||||
fake_e2.clone()
|
||||
} else {
|
||||
e2.clone()
|
||||
testcase.e2.clone()
|
||||
},
|
||||
&public_param,
|
||||
rng,
|
||||
@@ -1432,7 +1336,7 @@ mod tests {
|
||||
let proof = prove(
|
||||
(&public_param, &public_commit),
|
||||
&private_commit,
|
||||
&metadata,
|
||||
&testcase.metadata,
|
||||
load,
|
||||
rng,
|
||||
);
|
||||
@@ -1440,7 +1344,7 @@ mod tests {
|
||||
let verify_metadata = if use_fake_metadata_verify {
|
||||
&fake_metadata
|
||||
} else {
|
||||
&metadata
|
||||
&testcase.metadata
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
@@ -1457,59 +1361,23 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_pke_w_padding_fail_verify() {
|
||||
let d = 2048;
|
||||
let k = 320;
|
||||
let b_i = 512;
|
||||
let q = 0;
|
||||
let t = 1024;
|
||||
let msbs_zero_padding_bit_count = 1;
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = PKEV1_TEST_PARAMS;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let rng = &mut StdRng::seed_from_u64(0);
|
||||
|
||||
let polymul_rev = |a: &[i64], b: &[i64]| -> Vec<i64> {
|
||||
assert_eq!(a.len(), b.len());
|
||||
let d = a.len();
|
||||
let mut c = vec![0i64; d];
|
||||
|
||||
for i in 0..d {
|
||||
for j in 0..d {
|
||||
if i + j < d {
|
||||
c[i + j] = c[i + j].wrapping_add(a[i].wrapping_mul(b[d - j - 1]));
|
||||
} else {
|
||||
c[i + j - d] = c[i + j - d].wrapping_sub(a[i].wrapping_mul(b[d - j - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c
|
||||
};
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * b_i)) as i64 - b_i as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let mut testcase = PkeTestcase::gen(rng, PKEV1_TEST_PARAMS);
|
||||
|
||||
// Generate messages with padding set to fail verification
|
||||
let m = {
|
||||
testcase.m = {
|
||||
let mut tmp = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
@@ -1520,87 +1388,18 @@ mod tests {
|
||||
tmp
|
||||
};
|
||||
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
let c1 = polymul_rev(&a, &r)
|
||||
.into_iter()
|
||||
.zip(e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for i in 0..k {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
b[d - j - i - 1]
|
||||
} else {
|
||||
b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
c2[i] = dot
|
||||
.wrapping_add(e2[i])
|
||||
.wrapping_add((delta * m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(effective_cleartext_t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
|
||||
let ct = testcase.encrypt(PKEV1_TEST_PARAMS);
|
||||
type Curve = crate::curve_api::Bls12_446;
|
||||
|
||||
let serialize_then_deserialize = |public_param: &PublicParams<Curve>,
|
||||
compress: bool|
|
||||
-> bincode::Result<PublicParams<Curve>> {
|
||||
match compress {
|
||||
true => PublicParams::uncompress(bincode::deserialize(&bincode::serialize(
|
||||
&public_param.clone().compress(),
|
||||
)?)?)
|
||||
.map_err(|e| Box::new(ErrorKind::Custom(format!("Failed to uncompress: {}", e)))),
|
||||
false => bincode::deserialize(&bincode::serialize(&public_param)?),
|
||||
}
|
||||
};
|
||||
|
||||
// To check management of bigger k_max from CRS during test
|
||||
let crs_k = k + 1 + (rng.gen::<usize>() % (d - k));
|
||||
|
||||
let original_public_param =
|
||||
crs_gen::<Curve>(d, crs_k, b_i, q, t, msbs_zero_padding_bit_count, rng);
|
||||
crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
|
||||
let public_param_that_was_compressed =
|
||||
serialize_then_deserialize(&original_public_param, true).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::Yes).unwrap();
|
||||
let public_param_that_was_not_compressed =
|
||||
serialize_then_deserialize(&original_public_param, false).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::No).unwrap();
|
||||
|
||||
for public_param in [
|
||||
original_public_param,
|
||||
@@ -1608,14 +1407,14 @@ mod tests {
|
||||
public_param_that_was_not_compressed,
|
||||
] {
|
||||
let (public_commit, private_commit) = commit(
|
||||
a.clone(),
|
||||
b.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
r.clone(),
|
||||
e1.clone(),
|
||||
m.clone(),
|
||||
e2.clone(),
|
||||
testcase.a.clone(),
|
||||
testcase.b.clone(),
|
||||
ct.c1.clone(),
|
||||
ct.c2.clone(),
|
||||
testcase.r.clone(),
|
||||
testcase.e1.clone(),
|
||||
testcase.m.clone(),
|
||||
testcase.e2.clone(),
|
||||
&public_param,
|
||||
rng,
|
||||
);
|
||||
@@ -1624,147 +1423,49 @@ mod tests {
|
||||
let proof = prove(
|
||||
(&public_param, &public_commit),
|
||||
&private_commit,
|
||||
&metadata,
|
||||
&testcase.metadata,
|
||||
load,
|
||||
rng,
|
||||
);
|
||||
|
||||
assert!(verify(&proof, (&public_param, &public_commit), &metadata).is_err());
|
||||
assert!(
|
||||
verify(&proof, (&public_param, &public_commit), &testcase.metadata).is_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proof_compression() {
|
||||
let d = 2048;
|
||||
let k = 320;
|
||||
let big_b = 1048576;
|
||||
let q = 0;
|
||||
let t = 1024;
|
||||
let msbs_zero_padding_bit_count = 1;
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = PKEV1_TEST_PARAMS;
|
||||
|
||||
let rng = &mut StdRng::seed_from_u64(0);
|
||||
|
||||
let polymul_rev = |a: &[i64], b: &[i64]| -> Vec<i64> {
|
||||
assert_eq!(a.len(), b.len());
|
||||
let d = a.len();
|
||||
let mut c = vec![0i64; d];
|
||||
|
||||
for i in 0..d {
|
||||
for j in 0..d {
|
||||
if i + j < d {
|
||||
c[i + j] = c[i + j].wrapping_add(a[i].wrapping_mul(b[d - j - 1]));
|
||||
} else {
|
||||
c[i + j - d] = c[i + j - d].wrapping_sub(a[i].wrapping_mul(b[d - j - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c
|
||||
};
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * big_b)) as i64 - big_b as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * big_b)) as i64 - big_b as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * big_b)) as i64 - big_b as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
let c1 = polymul_rev(&a, &r)
|
||||
.into_iter()
|
||||
.zip(e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for i in 0..k {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
b[d - j - i - 1]
|
||||
} else {
|
||||
b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
c2[i] = dot
|
||||
.wrapping_add(e2[i])
|
||||
.wrapping_add((delta * m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(effective_cleartext_t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
let testcase = PkeTestcase::gen(rng, PKEV1_TEST_PARAMS);
|
||||
let ct = testcase.encrypt(PKEV1_TEST_PARAMS);
|
||||
|
||||
type Curve = crate::curve_api::Bls12_446;
|
||||
|
||||
let crs_k = k + 1 + (rng.gen::<usize>() % (d - k));
|
||||
|
||||
let public_param =
|
||||
crs_gen::<Curve>(d, crs_k, big_b, q, t, msbs_zero_padding_bit_count, rng);
|
||||
let public_param = crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
|
||||
|
||||
let (public_commit, private_commit) = commit(
|
||||
a.clone(),
|
||||
b.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
r.clone(),
|
||||
e1.clone(),
|
||||
m.clone(),
|
||||
e2.clone(),
|
||||
testcase.a.clone(),
|
||||
testcase.b.clone(),
|
||||
ct.c1.clone(),
|
||||
ct.c2.clone(),
|
||||
testcase.r.clone(),
|
||||
testcase.e1.clone(),
|
||||
testcase.m.clone(),
|
||||
testcase.e2.clone(),
|
||||
&public_param,
|
||||
rng,
|
||||
);
|
||||
@@ -1773,7 +1474,7 @@ mod tests {
|
||||
let proof = prove(
|
||||
(&public_param, &public_commit),
|
||||
&private_commit,
|
||||
&metadata,
|
||||
&testcase.metadata,
|
||||
load,
|
||||
rng,
|
||||
);
|
||||
@@ -1782,7 +1483,7 @@ mod tests {
|
||||
let proof =
|
||||
Proof::uncompress(bincode::deserialize(&compressed_proof).unwrap()).unwrap();
|
||||
|
||||
verify(&proof, (&public_param, &public_commit), &metadata).unwrap()
|
||||
verify(&proof, (&public_param, &public_commit), &testcase.metadata).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,13 +355,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the public part of the commitment. `a` and `b` are the mask and body of the public key,
|
||||
/// `c1` and `c2` are the mask and body of the ciphertext.
|
||||
/// This is the public part of the commitment.
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PublicCommit<G: Curve> {
|
||||
/// Mask of the public key
|
||||
a: Vec<i64>,
|
||||
/// Body of the public key
|
||||
b: Vec<i64>,
|
||||
/// Mask of the ciphertexts
|
||||
c1: Vec<i64>,
|
||||
/// Bodies of the ciphertexts
|
||||
c2: Vec<i64>,
|
||||
__marker: PhantomData<G>,
|
||||
}
|
||||
@@ -380,9 +383,13 @@ impl<G: Curve> PublicCommit<G> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PrivateCommit<G: Curve> {
|
||||
/// Public key sampling vector
|
||||
r: Vec<i64>,
|
||||
/// Error vector associated with the masks
|
||||
e1: Vec<i64>,
|
||||
/// Input messages
|
||||
m: Vec<i64>,
|
||||
/// Error vector associated with the bodies
|
||||
e2: Vec<i64>,
|
||||
__marker: PhantomData<G>,
|
||||
}
|
||||
@@ -2308,165 +2315,68 @@ pub fn verify<G: Curve>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::test::*;
|
||||
use super::*;
|
||||
use bincode::ErrorKind;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
fn polymul_rev(a: &[i64], b: &[i64]) -> Vec<i64> {
|
||||
assert_eq!(a.len(), b.len());
|
||||
let d = a.len();
|
||||
let mut c = vec![0i64; d];
|
||||
|
||||
for i in 0..d {
|
||||
for j in 0..d {
|
||||
if i + j < d {
|
||||
c[i + j] = c[i + j].wrapping_add(a[i].wrapping_mul(b[d - j - 1]));
|
||||
} else {
|
||||
c[i + j - d] = c[i + j - d].wrapping_sub(a[i].wrapping_mul(b[d - j - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c
|
||||
}
|
||||
/// Compact key params used with pkev2
|
||||
pub(super) const PKEV2_TEST_PARAMS: PkeTestParameters = PkeTestParameters {
|
||||
d: 2048,
|
||||
k: 320,
|
||||
B: 131072, // 2**17
|
||||
q: 0,
|
||||
t: 32, // 2b msg, 2b carry, 1b padding
|
||||
msbs_zero_padding_bit_count: 1,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_pke() {
|
||||
let d = 2048;
|
||||
let k = 320;
|
||||
let B = 1048576;
|
||||
let q = 0;
|
||||
let t = 1024;
|
||||
let msbs_zero_padding_bit_count = 1;
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = PKEV2_TEST_PARAMS;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
// delta takes the encoding with the padding bit
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let rng = &mut StdRng::seed_from_u64(0);
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let testcase = PkeTestcase::gen(rng, PKEV2_TEST_PARAMS);
|
||||
let ct = testcase.encrypt(PKEV2_TEST_PARAMS);
|
||||
|
||||
let fake_e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let fake_m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
let c1 = polymul_rev(&a, &r)
|
||||
.into_iter()
|
||||
.zip(e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for i in 0..k {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
b[d - j - i - 1]
|
||||
} else {
|
||||
b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
c2[i] = dot
|
||||
.wrapping_add(e2[i])
|
||||
.wrapping_add((delta * m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut fake_metadata = [255u8; METADATA_LEN];
|
||||
fake_metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(effective_cleartext_t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
|
||||
type Curve = crate::curve_api::Bls12_446;
|
||||
|
||||
let serialize_then_deserialize = |public_param: &PublicParams<Curve>,
|
||||
compress: bool|
|
||||
-> bincode::Result<PublicParams<Curve>> {
|
||||
match compress {
|
||||
true => PublicParams::uncompress(bincode::deserialize(&bincode::serialize(
|
||||
&public_param.clone().compress(),
|
||||
)?)?)
|
||||
.map_err(|e| Box::new(ErrorKind::Custom(format!("Failed to uncompress: {}", e)))),
|
||||
false => bincode::deserialize(&bincode::serialize(&public_param)?),
|
||||
}
|
||||
};
|
||||
|
||||
// To check management of bigger k_max from CRS during test
|
||||
let crs_k = k + 1 + (rng.gen::<usize>() % (d - k));
|
||||
|
||||
let original_public_param =
|
||||
crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
|
||||
let public_param_that_was_compressed =
|
||||
serialize_then_deserialize(&original_public_param, true).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::Yes).unwrap();
|
||||
let public_param_that_was_not_compressed =
|
||||
serialize_then_deserialize(&original_public_param, false).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::No).unwrap();
|
||||
|
||||
for (
|
||||
public_param,
|
||||
@@ -2488,29 +2398,29 @@ mod tests {
|
||||
[false, true]
|
||||
) {
|
||||
let (public_commit, private_commit) = commit(
|
||||
a.clone(),
|
||||
b.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
testcase.a.clone(),
|
||||
testcase.b.clone(),
|
||||
ct.c1.clone(),
|
||||
ct.c2.clone(),
|
||||
if use_fake_r {
|
||||
fake_r.clone()
|
||||
} else {
|
||||
r.clone()
|
||||
testcase.r.clone()
|
||||
},
|
||||
if use_fake_e1 {
|
||||
fake_e1.clone()
|
||||
} else {
|
||||
e1.clone()
|
||||
testcase.e1.clone()
|
||||
},
|
||||
if use_fake_m {
|
||||
fake_m.clone()
|
||||
} else {
|
||||
m.clone()
|
||||
testcase.m.clone()
|
||||
},
|
||||
if use_fake_e2 {
|
||||
fake_e2.clone()
|
||||
} else {
|
||||
e2.clone()
|
||||
testcase.e2.clone()
|
||||
},
|
||||
&public_param,
|
||||
rng,
|
||||
@@ -2520,7 +2430,7 @@ mod tests {
|
||||
let proof = prove(
|
||||
(&public_param, &public_commit),
|
||||
&private_commit,
|
||||
&metadata,
|
||||
&testcase.metadata,
|
||||
load,
|
||||
rng,
|
||||
);
|
||||
@@ -2528,7 +2438,7 @@ mod tests {
|
||||
let verify_metadata = if use_fake_metadata_verify {
|
||||
&fake_metadata
|
||||
} else {
|
||||
&metadata
|
||||
&testcase.metadata
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
@@ -2545,44 +2455,22 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_pke_w_padding_fail_verify() {
|
||||
let d = 2048;
|
||||
let k = 320;
|
||||
let B = 1048576;
|
||||
let q = 0;
|
||||
let t = 1024;
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = PKEV2_TEST_PARAMS;
|
||||
|
||||
let msbs_zero_padding_bit_count = 1;
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
// delta takes the encoding with the padding bit
|
||||
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
|
||||
let rng = &mut StdRng::seed_from_u64(0);
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut testcase = PkeTestcase::gen(rng, PKEV2_TEST_PARAMS);
|
||||
// Generate messages with padding set to fail verification
|
||||
let m = {
|
||||
testcase.m = {
|
||||
let mut tmp = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
@@ -2593,87 +2481,19 @@ mod tests {
|
||||
tmp
|
||||
};
|
||||
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
let c1 = polymul_rev(&a, &r)
|
||||
.into_iter()
|
||||
.zip(e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for i in 0..k {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
b[d - j - i - 1]
|
||||
} else {
|
||||
b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
c2[i] = dot
|
||||
.wrapping_add(e2[i])
|
||||
.wrapping_add((delta * m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(effective_cleartext_t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
let ct = testcase.encrypt(PKEV2_TEST_PARAMS);
|
||||
|
||||
type Curve = crate::curve_api::Bls12_446;
|
||||
|
||||
let serialize_then_deserialize = |public_param: &PublicParams<Curve>,
|
||||
compress: bool|
|
||||
-> bincode::Result<PublicParams<Curve>> {
|
||||
match compress {
|
||||
true => PublicParams::uncompress(bincode::deserialize(&bincode::serialize(
|
||||
&public_param.clone().compress(),
|
||||
)?)?)
|
||||
.map_err(|e| Box::new(ErrorKind::Custom(format!("Failed to uncompress: {}", e)))),
|
||||
false => bincode::deserialize(&bincode::serialize(&public_param)?),
|
||||
}
|
||||
};
|
||||
|
||||
// To check management of bigger k_max from CRS during test
|
||||
let crs_k = k + 1 + (rng.gen::<usize>() % (d - k));
|
||||
|
||||
let original_public_param =
|
||||
crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
|
||||
let public_param_that_was_compressed =
|
||||
serialize_then_deserialize(&original_public_param, true).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::Yes).unwrap();
|
||||
let public_param_that_was_not_compressed =
|
||||
serialize_then_deserialize(&original_public_param, false).unwrap();
|
||||
serialize_then_deserialize(&original_public_param, Compress::No).unwrap();
|
||||
|
||||
for public_param in [
|
||||
original_public_param,
|
||||
@@ -2681,14 +2501,14 @@ mod tests {
|
||||
public_param_that_was_not_compressed,
|
||||
] {
|
||||
let (public_commit, private_commit) = commit(
|
||||
a.clone(),
|
||||
b.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
r.clone(),
|
||||
e1.clone(),
|
||||
m.clone(),
|
||||
e2.clone(),
|
||||
testcase.a.clone(),
|
||||
testcase.b.clone(),
|
||||
ct.c1.clone(),
|
||||
ct.c2.clone(),
|
||||
testcase.r.clone(),
|
||||
testcase.e1.clone(),
|
||||
testcase.m.clone(),
|
||||
testcase.e2.clone(),
|
||||
&public_param,
|
||||
rng,
|
||||
);
|
||||
@@ -2697,131 +2517,33 @@ mod tests {
|
||||
let proof = prove(
|
||||
(&public_param, &public_commit),
|
||||
&private_commit,
|
||||
&metadata,
|
||||
&testcase.metadata,
|
||||
load,
|
||||
rng,
|
||||
);
|
||||
|
||||
assert!(verify(&proof, (&public_param, &public_commit), &metadata).is_err());
|
||||
assert!(
|
||||
verify(&proof, (&public_param, &public_commit), &testcase.metadata).is_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proof_compression() {
|
||||
let d = 2048;
|
||||
let k = 320;
|
||||
let B = 1048576;
|
||||
let q = 0;
|
||||
let t = 1024;
|
||||
|
||||
let msbs_zero_padding_bit_count = 1;
|
||||
let effective_cleartext_t = t >> msbs_zero_padding_bit_count;
|
||||
|
||||
let delta = {
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
(q / t as i128) as u64
|
||||
};
|
||||
let PkeTestParameters {
|
||||
d,
|
||||
k,
|
||||
B,
|
||||
q,
|
||||
t,
|
||||
msbs_zero_padding_bit_count,
|
||||
} = PKEV2_TEST_PARAMS;
|
||||
|
||||
let rng = &mut StdRng::seed_from_u64(0);
|
||||
|
||||
let polymul_rev = |a: &[i64], b: &[i64]| -> Vec<i64> {
|
||||
assert_eq!(a.len(), b.len());
|
||||
let d = a.len();
|
||||
let mut c = vec![0i64; d];
|
||||
|
||||
for i in 0..d {
|
||||
for j in 0..d {
|
||||
if i + j < d {
|
||||
c[i + j] = c[i + j].wrapping_add(a[i].wrapping_mul(b[d - j - 1]));
|
||||
} else {
|
||||
c[i + j - d] = c[i + j - d].wrapping_sub(a[i].wrapping_mul(b[d - j - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c
|
||||
};
|
||||
|
||||
let a = (0..d).map(|_| rng.gen::<i64>()).collect::<Vec<_>>();
|
||||
let s = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e1 = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
let e2 = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % (2 * B)) as i64 - B as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let r = (0..d)
|
||||
.map(|_| (rng.gen::<u64>() % 2) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let m = (0..k)
|
||||
.map(|_| (rng.gen::<u64>() % effective_cleartext_t) as i64)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let b = polymul_rev(&a, &s)
|
||||
.into_iter()
|
||||
.zip(e.iter())
|
||||
.map(|(x, e)| x.wrapping_add(*e))
|
||||
.collect::<Vec<_>>();
|
||||
let c1 = polymul_rev(&a, &r)
|
||||
.into_iter()
|
||||
.zip(e1.iter())
|
||||
.map(|(x, e1)| x.wrapping_add(*e1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut c2 = vec![0i64; k];
|
||||
|
||||
for i in 0..k {
|
||||
let mut dot = 0i64;
|
||||
for j in 0..d {
|
||||
let b = if i + j < d {
|
||||
b[d - j - i - 1]
|
||||
} else {
|
||||
b[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot = dot.wrapping_add(r[d - j - 1].wrapping_mul(b));
|
||||
}
|
||||
|
||||
c2[i] = dot
|
||||
.wrapping_add(e2[i])
|
||||
.wrapping_add((delta * m[i] as u64) as i64);
|
||||
}
|
||||
|
||||
// One of our usecases uses 320 bits of additional metadata
|
||||
const METADATA_LEN: usize = (320 / u8::BITS) as usize;
|
||||
|
||||
let mut metadata = [0u8; METADATA_LEN];
|
||||
metadata.fill_with(|| rng.gen::<u8>());
|
||||
|
||||
let mut m_roundtrip = vec![0i64; k];
|
||||
for i in 0..k {
|
||||
let mut dot = 0i128;
|
||||
for j in 0..d {
|
||||
let c = if i + j < d {
|
||||
c1[d - j - i - 1]
|
||||
} else {
|
||||
c1[2 * d - j - i - 1].wrapping_neg()
|
||||
};
|
||||
|
||||
dot += s[d - j - 1] as i128 * c as i128;
|
||||
}
|
||||
|
||||
let q = if q == 0 { 1i128 << 64 } else { q as i128 };
|
||||
let val = ((c2[i] as i128).wrapping_sub(dot)) * t as i128;
|
||||
let div = val.div_euclid(q);
|
||||
let rem = val.rem_euclid(q);
|
||||
let result = div as i64 + (rem > (q / 2)) as i64;
|
||||
let result = result.rem_euclid(effective_cleartext_t as i64);
|
||||
m_roundtrip[i] = result;
|
||||
}
|
||||
let testcase = PkeTestcase::gen(rng, PKEV2_TEST_PARAMS);
|
||||
let ct = testcase.encrypt(PKEV2_TEST_PARAMS);
|
||||
|
||||
type Curve = crate::curve_api::Bls12_446;
|
||||
|
||||
@@ -2830,14 +2552,14 @@ mod tests {
|
||||
let public_param = crs_gen::<Curve>(d, crs_k, B, q, t, msbs_zero_padding_bit_count, rng);
|
||||
|
||||
let (public_commit, private_commit) = commit(
|
||||
a.clone(),
|
||||
b.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
r.clone(),
|
||||
e1.clone(),
|
||||
m.clone(),
|
||||
e2.clone(),
|
||||
testcase.a.clone(),
|
||||
testcase.b.clone(),
|
||||
ct.c1.clone(),
|
||||
ct.c2.clone(),
|
||||
testcase.r.clone(),
|
||||
testcase.e1.clone(),
|
||||
testcase.m.clone(),
|
||||
testcase.e2.clone(),
|
||||
&public_param,
|
||||
rng,
|
||||
);
|
||||
@@ -2846,7 +2568,7 @@ mod tests {
|
||||
let proof = prove(
|
||||
(&public_param, &public_commit),
|
||||
&private_commit,
|
||||
&metadata,
|
||||
&testcase.metadata,
|
||||
load,
|
||||
rng,
|
||||
);
|
||||
@@ -2855,7 +2577,7 @@ mod tests {
|
||||
let proof =
|
||||
Proof::uncompress(bincode::deserialize(&compressed_proof).unwrap()).unwrap();
|
||||
|
||||
verify(&proof, (&public_param, &public_commit), &metadata).unwrap()
|
||||
verify(&proof, (&public_param, &public_commit), &testcase.metadata).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user