use super::ErrorReason;
use crate::bn_to_gen;
use crate::isprime;
use crate::pari_init;
use crate::primitives::is_prime;
use crate::primitives::numerical_log;
use crate::primitives::prng;
use crate::BinaryQF;
use curv::arithmetic::traits::*;
use curv::cryptographic_primitives::hashing::{Digest, DigestExt};
use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar};
use curv::BigInt;
use sha2::Sha256;
use std::os::raw::c_int;
const SECURITY_PARAMETER: usize = 128;
const C: usize = 10;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PK {
pub q: BigInt,
pub delta_k: BigInt,
pub delta_q: BigInt,
pub gq: BinaryQF,
pub h: BinaryQF,
pub stilde: BigInt,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Ciphertext {
pub c1: BinaryQF,
pub c2: BinaryQF,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HSMCL {
pub sk: BigInt,
pub pk: PK,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CLDLProof {
pub pk: PK,
pub ciphertext: Ciphertext,
q: Point<Secp256k1>,
t_vec: Vec<TTriplets>,
u_vec: Vec<U1U2>,
}
pub struct Witness {
pub r: BigInt,
pub x: BigInt,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TTriplets {
pub t1: BinaryQF,
pub t2: BinaryQF,
pub T: Point<Secp256k1>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct U1U2 {
pub u1: BigInt,
pub u2: BigInt,
}
#[derive(Debug)]
pub struct ProofError;
impl HSMCL {
pub fn keygen(q: &BigInt, lam: &usize) -> Self {
unsafe { pari_init(10000000, 2) };
let mu = q.bit_length();
assert!(lam > &(mu + 2));
let k = lam - mu;
let two = BigInt::from(2);
let mut r = BigInt::sample_range(
&two.pow((k - 1) as u32),
&(two.pow(k as u32) - BigInt::one()),
);
let mut qtilde = next_probable_prime(&r);
while (q * &qtilde).mod_floor(&BigInt::from(4)) != BigInt::from(3)
|| jacobi(q, &qtilde).unwrap() != -1
{
r = BigInt::sample_range(
&two.pow((k - 1) as u32),
&(two.pow(k as u32) - BigInt::one()),
);
qtilde = next_probable_prime(&r);
}
assert!(BigInt::from(4) * q < qtilde);
let delta_k = -q * &qtilde;
let delta_q = &delta_k * q.pow(2);
let delta_k_abs: BigInt = -(&delta_k);
let log_delta_k_abs = numerical_log(&delta_k_abs);
let delta_k_abs_sqrt = delta_k_abs.sqrt();
let stilde = log_delta_k_abs * delta_k_abs_sqrt;
let mut r = BigInt::from(3);
while jacobi(&delta_k, &r).unwrap() != 1 {
r = next_probable_prime(&r)
}
let rgoth = BinaryQF::primeform(&delta_k, &r);
let rgoth_square = rgoth.compose(&rgoth).reduce();
let gq_tmp = rgoth_square.phi_q_to_the_minus_1(q).reduce();
let gq = gq_tmp.exp(q);
let x = BigInt::sample_below(&(&stilde * BigInt::from(2).pow(40)));
let h = gq.exp(&x);
let pk = PK {
q: q.clone(),
delta_k,
delta_q,
gq,
h,
stilde,
};
HSMCL { sk: x, pk }
}
pub fn keygen_with_setup(q: &BigInt, lam: &usize, seed: &BigInt) -> Self {
unsafe { pari_init(100000000, 2) };
let mu = q.bit_length();
assert!(lam > &(mu + 2));
let k = lam - mu;
let two = BigInt::from(2);
let mut r = BigInt::sample_range(
&two.pow((k - 1) as u32),
&(two.pow(k as u32) - BigInt::one()),
);
let mut qtilde = next_probable_prime(&r);
while (q * &qtilde).mod_floor(&BigInt::from(4)) != BigInt::from(3)
|| jacobi(q, &qtilde).unwrap() != -1
{
r = BigInt::sample_range(
&two.pow((k - 1) as u32),
&(two.pow(k as u32) - BigInt::one()),
);
qtilde = next_probable_prime(&r);
}
assert!(BigInt::from(4) * q < qtilde);
let delta_k = -q * &qtilde;
let delta_q = &delta_k * q.pow(2);
let delta_k_abs: BigInt = -(&delta_k);
let log_delta_k_abs = numerical_log(&delta_k_abs);
let delta_k_abs_sqrt = delta_k_abs.sqrt();
let stilde = log_delta_k_abs * delta_k_abs_sqrt;
let mut prime_forms_vec: Vec<BinaryQF> = Vec::new();
let mut r = BigInt::from(3);
let ln_delta_k = numerical_log(&(-&delta_k));
let num_of_prime_forms = ln_delta_k.div_floor(&numerical_log(&ln_delta_k));
let mut i = BigInt::zero();
while i < num_of_prime_forms {
while jacobi(&delta_k, &r).unwrap() != 1 {
r = next_probable_small_prime(&r)
}
prime_forms_vec.push(BinaryQF::primeform(&delta_k, &r));
r = next_probable_small_prime(&r);
i += 1;
}
let mut rgoth = BinaryQF::binary_quadratic_form_principal(&delta_k);
let mut i = 0;
let mut rand_bits_i: BigInt;
let mut prod_exponent = BigInt::one();
while i < prime_forms_vec.len() {
rand_bits_i = prng(seed, i, 15);
while rand_bits_i.gcd(&prod_exponent) != BigInt::one() {
rand_bits_i += 1;
}
rgoth = rgoth
.compose(&prime_forms_vec[i].exp(&rand_bits_i))
.reduce();
prod_exponent *= &rand_bits_i;
i += 1;
}
let rgoth_square = rgoth.compose(&rgoth).reduce();
let gq_tmp = rgoth_square.phi_q_to_the_minus_1(q).reduce();
let gq = gq_tmp.exp(q);
let x = BigInt::sample_below(&(&stilde * BigInt::from(2).pow(40)));
let h = gq.exp(&x);
let pk = PK {
q: q.clone(),
delta_k,
delta_q,
gq,
h,
stilde,
};
HSMCL { sk: x, pk }
}
pub fn setup_verify(pk: &PK, seed: &BigInt) -> Result<(), ErrorReason> {
unsafe { pari_init(100000000, 2) };
let mut prime_forms_vec: Vec<BinaryQF> = Vec::new();
let ln_delta_k = numerical_log(&(-&pk.delta_k));
let num_of_prime_forms = ln_delta_k.div_floor(&numerical_log(&ln_delta_k));
let mut r = BigInt::from(3);
let mut i = BigInt::zero();
while i < num_of_prime_forms {
while jacobi(&pk.delta_k, &r).unwrap() != 1 {
r = next_probable_small_prime(&r)
}
prime_forms_vec.push(BinaryQF::primeform(&pk.delta_k, &r));
r = next_probable_small_prime(&r);
i += 1;
}
let mut rgoth = BinaryQF::binary_quadratic_form_principal(&pk.delta_k);
let mut i = 0;
let mut rand_bits_i: BigInt;
let mut prod_exponent = BigInt::one();
while i < prime_forms_vec.len() {
rand_bits_i = prng(seed, i, 15);
while rand_bits_i.gcd(&prod_exponent) != BigInt::one() {
rand_bits_i += 1;
}
rgoth = rgoth
.compose(&prime_forms_vec[i].exp(&rand_bits_i))
.reduce();
prod_exponent *= &rand_bits_i;
i += 1;
}
let rgoth_square = rgoth.compose(&rgoth).reduce();
let gq_tmp = rgoth_square.phi_q_to_the_minus_1(&pk.q).reduce();
let gq = gq_tmp.exp(&pk.q);
match gq == pk.gq {
true => Ok(()),
false => Err(ErrorReason::SetupError),
}
}
pub fn encrypt(pk: &PK, m: &BigInt) -> Ciphertext {
unsafe { pari_init(10000000, 2) };
assert!(m < &pk.q);
let r = BigInt::sample_below(&(&pk.stilde * BigInt::from(2).pow(40)));
let exp_f = BinaryQF::expo_f(&pk.q, &pk.delta_q, m);
let h_exp_r = pk.h.exp(&r);
Ciphertext {
c1: pk.gq.exp(&r),
c2: h_exp_r.compose(&exp_f).reduce(),
}
}
pub fn encrypt_predefined_randomness(pk: &PK, m: &BigInt, r: &BigInt) -> Ciphertext {
unsafe { pari_init(10000000, 2) };
assert!(m < &pk.q);
let exp_f = BinaryQF::expo_f(&pk.q, &pk.delta_q, m);
let h_exp_r = pk.h.exp(r);
Ciphertext {
c1: pk.gq.exp(r),
c2: h_exp_r.compose(&exp_f).reduce(),
}
}
pub fn decrypt(&self, c: &Ciphertext) -> BigInt {
unsafe { pari_init(10000000, 2) };
let c1_x = c.c1.exp(&self.sk);
let c1_x_inv = c1_x.inverse();
let tmp = c.c2.compose(&c1_x_inv).reduce();
BinaryQF::discrete_log_f(&self.pk.q, &self.pk.delta_q, &tmp)
}
pub fn eval_scal(c: &Ciphertext, val: &BigInt) -> Ciphertext {
unsafe { pari_init(10000000, 2) };
Ciphertext {
c1: c.c1.exp(val),
c2: c.c2.exp(val),
}
}
pub fn eval_sum(c1: &Ciphertext, c2: &Ciphertext) -> Ciphertext {
unsafe { pari_init(10000000, 2) };
Ciphertext {
c1: c1.c1.compose(&c2.c1).reduce(),
c2: c1.c2.compose(&c2.c2).reduce(),
}
}
}
pub fn next_probable_prime(r: &BigInt) -> BigInt {
let one = BigInt::from(1);
let mut qtilde = r + &one;
while !is_prime(&qtilde) {
qtilde += &one;
}
qtilde
}
pub fn next_probable_small_prime(r: &BigInt) -> BigInt {
let one = BigInt::from(1);
let mut qtilde = r + &one;
let mut qtilde_gen = bn_to_gen(&(r + &one));
unsafe {
while isprime(qtilde_gen) as c_int != 1 {
qtilde += &one;
qtilde_gen = bn_to_gen(&qtilde);
}
}
qtilde
}
impl CLDLProof {
pub fn prove(w: Witness, pk: PK, ciphertext: Ciphertext, q: Point<Secp256k1>) -> Self {
unsafe { pari_init(10000000, 2) };
let repeat = SECURITY_PARAMETER / C + 1;
let triplets_and_fs_and_r_vec = (0..repeat)
.map(|_| {
let r1 = BigInt::sample_below(
&(&pk.stilde
* BigInt::from(2).pow(40)
* BigInt::from(2).pow(C as u32)
* BigInt::from(2).pow(40)),
);
let r2_fe = Scalar::<Secp256k1>::random();
let r2 = r2_fe.to_bigint();
let fr2 = BinaryQF::expo_f(&pk.q, &pk.delta_q, &r2);
let pkr1 = pk.h.exp(&r1);
let t2 = fr2.compose(&pkr1).reduce();
let T = Point::<Secp256k1>::generator() * r2_fe;
let t1 = pk.gq.exp(&r1);
let fs = Sha256::new()
.chain(t1.to_bytes())
.chain(t2.to_bytes())
.chain_point(&T)
.result_bigint();
(TTriplets { t1, t2, T }, fs, r1, r2)
})
.collect::<Vec<(TTriplets, BigInt, BigInt, BigInt)>>();
let triplets_vec = (0..repeat)
.map(|i| triplets_and_fs_and_r_vec[i].0.clone())
.collect::<Vec<TTriplets>>();
let fiat_shamir_vec = (0..repeat)
.map(|i| &triplets_and_fs_and_r_vec[i].1)
.collect::<Vec<&BigInt>>();
let r1_vec = (0..repeat)
.map(|i| triplets_and_fs_and_r_vec[i].2.clone())
.collect::<Vec<BigInt>>();
let r2_vec = (0..repeat)
.map(|i| triplets_and_fs_and_r_vec[i].3.clone())
.collect::<Vec<BigInt>>();
let k = fiat_shamir_vec
.iter()
.fold(Sha256::new(), |hash, i| hash.chain_bigint(i))
.result_bigint();
let ten = BigInt::from(C as u32);
let u1u2_vec = (0..repeat)
.map(|i| {
let k_slice_i = (&k >> (i * C)) & &ten;
let u1 = &r1_vec[i] + &k_slice_i * &w.r;
let u2 = BigInt::mod_add(
&r2_vec[i],
&(&k_slice_i * &w.x),
Scalar::<Secp256k1>::group_order(),
);
U1U2 { u1, u2 }
})
.collect::<Vec<U1U2>>();
CLDLProof {
pk,
ciphertext,
q,
t_vec: triplets_vec,
u_vec: u1u2_vec,
}
}
pub fn verify(&self) -> Result<(), ProofError> {
unsafe { pari_init(10000000, 2) };
let repeat = SECURITY_PARAMETER / C + 1;
let fs_vec = (0..repeat)
.map(|i| {
Sha256::new()
.chain(self.t_vec[i].t1.to_bytes())
.chain(self.t_vec[i].t2.to_bytes())
.chain_point(&self.t_vec[i].T)
.result_bigint()
})
.collect::<Vec<BigInt>>();
let fs_t_vec = (0..repeat).map(|i| &fs_vec[i]).collect::<Vec<&BigInt>>();
let mut flag = true;
let k = fs_t_vec
.iter()
.fold(Sha256::new(), |hash, i| hash.chain_bigint(i))
.result_bigint();
let ten = BigInt::from(C as u32);
let sample_size = &self.pk.stilde
* (BigInt::from(2).pow(40))
* BigInt::from(2).pow(C as u32)
* (BigInt::from(2).pow(40) + BigInt::one());
for i in 0..repeat {
let k_slice_i = (&k >> (i * C)) & &ten;
if self.u_vec[i].u1 > sample_size || self.u_vec[i].u1 < BigInt::zero() {
flag = false;
}
if &self.u_vec[i].u2 > Scalar::<Secp256k1>::group_order()
|| self.u_vec[i].u2 < BigInt::zero()
{
flag = false;
}
let c1k = self.ciphertext.c1.exp(&k_slice_i);
let t1c1k = self.t_vec[i].t1.compose(&c1k).reduce();
let gqu1 = self.pk.gq.exp(&self.u_vec[i].u1);
if t1c1k != gqu1 {
flag = false;
};
let k_slice_i_bias_fe: Scalar<Secp256k1> =
Scalar::<Secp256k1>::from(&(&k_slice_i + BigInt::one()));
let g = Point::<Secp256k1>::generator();
let t2kq = (&self.t_vec[i].T + &self.q * k_slice_i_bias_fe) - &self.q;
let u2p = g * Scalar::<Secp256k1>::from(&self.u_vec[i].u2);
if t2kq != u2p {
flag = false;
}
let pku1 = self.pk.h.exp(&self.u_vec[i].u1);
let fu2 = BinaryQF::expo_f(&self.pk.q, &self.pk.delta_q, &self.u_vec[i].u2);
let c2k = self.ciphertext.c2.exp(&k_slice_i);
let t2c2k = self.t_vec[i].t2.compose(&c2k).reduce();
let pku1fu2 = pku1.compose(&fu2).reduce();
if t2c2k != pku1fu2 {
flag = false;
}
}
match flag {
true => Ok(()),
false => Err(ProofError),
}
}
}
pub fn jacobi(a: &BigInt, n: &BigInt) -> Option<i8> {
let zero = BigInt::zero();
if n.mod_floor(&BigInt::from(2)) == zero || n <= &BigInt::zero() {
return None;
}
let mut acc = 1;
let mut num = a.mod_floor(n);
let mut den = n.clone();
loop {
num = num.mod_floor(&den);
if num == zero {
return Some(0);
}
while num.mod_floor(&BigInt::from(2)) == zero {
acc *= two_over(&den);
num = num.div_floor(&BigInt::from(2));
}
if num == BigInt::one() {
return Some(acc);
}
if num.gcd(&den) > BigInt::one() {
return Some(0);
}
acc *= reciprocity(&num, &den);
let tmp = num;
num = den.clone();
den = tmp;
}
}
fn two_over(n: &BigInt) -> i8 {
if n.mod_floor(&BigInt::from(8)) == BigInt::one()
|| n.mod_floor(&BigInt::from(8)) == BigInt::from(7)
{
1
} else {
-1
}
}
fn reciprocity(num: &BigInt, den: &BigInt) -> i8 {
if num.mod_floor(&BigInt::from(4)) == BigInt::from(3)
&& den.mod_floor(&BigInt::from(4)) == BigInt::from(3)
{
-1
} else {
1
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encryption_p256() {
let q = BigInt::from_str_radix(
"115792089210356248762697446949407573529996955224135760342422259061068512044369",
10,
)
.unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(1000);
let ciphertext = HSMCL::encrypt(&hsmcl.pk, &m);
let m_tag = hsmcl.decrypt(&ciphertext);
assert_eq!(m, m_tag);
}
#[test]
fn test_encryption_secp256k1() {
let q = BigInt::from_str_radix(
"115792089237316195423570985008687907852837564279074904382605163141518161494337",
10,
)
.unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(1000);
let ciphertext = HSMCL::encrypt(&hsmcl.pk, &m);
let m_tag = hsmcl.decrypt(&ciphertext);
assert_eq!(m, m_tag);
}
#[test]
fn test_encryption_mul_by_scalar_secp256k1_lcm() {
let q: BigInt = BigInt::from_str_radix(
"115792089237316195423570985008687907852837564279074904382605163141518161494337",
10,
)
.unwrap();
let y_lcm_2_10 : BigInt = BigInt::from_str_radix(
"15161806181366890704755537519628428221282838501257142250824360639698299050776571382489681778825684381429314058890905101687022024744606800532531764952734582389201393752832486383043169059475949454418063248428056646723694341952991408637386677631205400831455008554143754794994126167401137152222379676492247471515691285702536834646805381995650206229354446213284302569283840180834930263739794772017863585682362821412785936104792844891075228278568320000",
10,
).unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(1000);
let ciphertext = HSMCL::encrypt(&hsmcl.pk, &m);
let c_y = HSMCL::eval_scal(&ciphertext, &y_lcm_2_10);
let m_tag = hsmcl.decrypt(&c_y);
let m_y = BigInt::mod_mul(&m, &y_lcm_2_10, &q);
assert_eq!(m_y, m_tag);
}
#[test]
fn test_zk_cl_dl() {
let q = BigInt::from_str_radix(
"115792089237316195423570985008687907852837564279074904382605163141518161494337",
10,
)
.unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(1000);
let r = BigInt::sample_below(&(&hsmcl.pk.stilde * BigInt::from(2).pow(40)));
let ciphertext = HSMCL::encrypt_predefined_randomness(&hsmcl.pk, &m, &r);
let witness = Witness { x: m.clone(), r };
let m_fe = Scalar::<Secp256k1>::from(&m);
let q = Point::<Secp256k1>::generator() * m_fe;
let proof = CLDLProof::prove(witness, hsmcl.pk, ciphertext, q);
assert!(proof.verify().is_ok())
}
#[test]
#[should_panic]
fn test_bad_q_zk_cl_dl() {
let q = BigInt::from_str_radix(
"115792089237316195423570985008687907852837564279074904382605163141518161494337",
10,
)
.unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(1000);
let r = BigInt::sample_below(&(&hsmcl.pk.stilde * BigInt::from(2).pow(40)));
let ciphertext = HSMCL::encrypt_predefined_randomness(&hsmcl.pk, &m, &r);
let witness = Witness { x: m.clone(), r };
let m_fe: Scalar<Secp256k1> = Scalar::<Secp256k1>::from(&(&m + &BigInt::one()));
let q = Point::<Secp256k1>::generator() * m_fe;
let proof = CLDLProof::prove(witness, hsmcl.pk, ciphertext, q);
assert!(proof.verify().is_ok())
}
#[test]
#[should_panic]
fn test_bad_witness_zk_cl_dl() {
let q = BigInt::from_str_radix(
"115792089237316195423570985008687907852837564279074904382605163141518161494337",
10,
)
.unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(1000);
let r = BigInt::sample_below(&(&hsmcl.pk.stilde * BigInt::from(2).pow(40)));
let ciphertext = HSMCL::encrypt_predefined_randomness(&hsmcl.pk, &m, &r);
let witness = Witness {
x: &m + BigInt::one(),
r,
};
let m_fe = Scalar::<Secp256k1>::from(&(&m + &BigInt::one()));
let q = Point::<Secp256k1>::generator() * m_fe;
let proof = CLDLProof::prove(witness, hsmcl.pk, ciphertext, q);
assert!(proof.verify().is_ok())
}
#[test]
fn test_log_dlog() {
let q = BigInt::from_str_radix(
"115792089210356248762697446949407573529996955224135760342422259061068512044369",
10,
)
.unwrap();
let hsmcl = HSMCL::keygen(&q, &1600);
let m = BigInt::from(10000);
let exp_f = BinaryQF::expo_f(&hsmcl.pk.q, &hsmcl.pk.delta_q, &m);
let m_tag = BinaryQF::discrete_log_f(&hsmcl.pk.q, &hsmcl.pk.delta_q, &exp_f);
assert_eq!(m, m_tag);
}
#[test]
fn test_setup() {
let q = BigInt::from_str_radix(
"115792089237316195423570985008687907852837564279074904382605163141518161494337",
10,
)
.unwrap();
let seed = BigInt::from_str_radix(
"314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848"
, 10).unwrap();
let hsmcl = HSMCL::keygen_with_setup(&q, &1600, &seed);
assert!(HSMCL::setup_verify(&hsmcl.pk, &seed).is_ok());
}
}