use crate::{
hash::{HashInto, sha256::HashMatZq},
signature::SignatureScheme,
};
use qfall_math::{
integer::{MatZ, Z},
integer_mod_q::{MatZq, Modulus},
rational::{MatQ, Q},
};
use qfall_tools::{
primitive::psf::{PSF, PSFGPV},
sample::g_trapdoor::gadget_parameters::GadgetParameters,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize)]
pub struct FDHGPV {
pub psf: PSFGPV,
pub storage: HashMap<String, MatZ>,
pub hash: HashMatZq,
}
impl FDHGPV {
pub fn setup(n: impl Into<Z>, q: impl Into<Modulus>, s: impl Into<Q>) -> Self {
let (n, q, s) = (n.into(), q.into(), s.into());
let psf = PSFGPV {
gp: GadgetParameters::init_default(&n, &q),
s,
};
Self {
psf,
storage: HashMap::new(),
hash: HashMatZq {
modulus: q,
rows: i64::try_from(n).unwrap(),
cols: 1,
},
}
}
}
impl SignatureScheme for FDHGPV {
type SecretKey = (MatZ, MatQ);
type PublicKey = MatZq;
type Signature = MatZ;
fn key_gen(&mut self) -> (Self::PublicKey, Self::SecretKey) {
self.psf.trap_gen()
}
fn sign(&mut self, m: String, sk: &Self::SecretKey, pk: &Self::PublicKey) -> Self::Signature {
if let Some(sigma) = self.storage.get(&m) {
return sigma.clone();
}
let u = (self.hash).hash(&m);
let signature = self.psf.samp_p(pk, sk, &u);
self.storage.insert(m, signature.clone());
signature
}
fn vfy(&self, m: String, sigma: &Self::Signature, pk: &Self::PublicKey) -> bool {
if !self.psf.check_domain(sigma) {
return false;
}
let u = (self.hash).hash(&m);
self.psf.f_a(pk, sigma) == u
}
}
#[cfg(test)]
mod test_fdh {
use crate::signature::{SignatureScheme, fdh::gpv::FDHGPV};
use qfall_math::{integer::Z, rational::Q, traits::Pow};
#[test]
fn ensure_valid_signature_is_generated() {
let n = Z::from(4);
let k = Z::from(6);
let s: Q = ((&n * &k).sqrt() + 1) * Q::from(2) * (Z::from(2) * &n * &k).log(2).unwrap();
let q = Z::from(2).pow(&k).unwrap();
let mut fdh = FDHGPV::setup(n, &q, &s);
let (pk, sk) = fdh.key_gen();
for i in 0..10 {
let m = format!("Hello World! {i}");
let sigma = fdh.sign(m.to_owned(), &sk, &pk);
assert_eq!(&sigma, &fdh.sign(m.to_owned(), &sk, &pk));
assert!(fdh.vfy(m.to_owned(), &sigma, &pk))
}
}
#[test]
fn storage_filled() {
let mut fdh = FDHGPV::setup(5, 1024, 10);
let m = "Hello World!";
let (pk, sk) = fdh.key_gen();
let _ = fdh.sign(m.to_owned(), &sk, &pk);
assert!(fdh.storage.contains_key(m))
}
#[test]
fn reload_hashmap() {
let mut fdh = FDHGPV::setup(5, 1024, 10);
let m = "Hello World!";
let (pk, sk) = fdh.key_gen();
let _ = fdh.sign(m.to_owned(), &sk, &pk);
let fdh_string = serde_json::to_string(&fdh).expect("Unable to create a json object");
let fdh_2: FDHGPV = serde_json::from_str(&fdh_string).unwrap();
assert_eq!(fdh.storage, fdh_2.storage);
}
}