use crate::{
hash::{HashInto, sha256::HashMatZq},
signature::SignatureScheme,
};
use qfall_math::{
integer::{MatZ, Z},
integer_mod_q::{MatZq, Modulus},
rational::{MatQ, Q},
traits::Pow,
};
use qfall_tools::{
primitive::psf::{PSF, PSFGPV},
sample::g_trapdoor::gadget_parameters::GadgetParameters,
};
pub struct PFDHGPV {
pub psf: PSFGPV,
pub hash: HashMatZq,
pub randomness_length: Z,
}
impl PFDHGPV {
pub fn setup(
n: impl Into<Z>,
q: impl Into<Modulus>,
s: impl Into<Q>,
randomness_length: impl Into<Z>,
) -> Self {
let (n, q, s, randomness_length) = (n.into(), q.into(), s.into(), randomness_length.into());
let psf = PSFGPV {
gp: GadgetParameters::init_default(&n, &q),
s,
};
let n = i64::try_from(&n).unwrap();
Self {
psf,
hash: HashMatZq {
modulus: q,
rows: n,
cols: 1,
},
randomness_length,
}
}
}
impl SignatureScheme for PFDHGPV {
type SecretKey = (MatZ, MatQ);
type PublicKey = MatZq;
type Signature = (MatZ, Z);
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 {
let randomness =
Z::sample_uniform(0, Z::from(2).pow(&self.randomness_length).unwrap()).unwrap();
let u = (self.hash).hash(&format!("{m} {randomness} {}", &self.randomness_length));
let signature_part1 = self.psf.samp_p(pk, sk, &u);
(signature_part1, randomness)
}
fn vfy(&self, m: String, sigma: &Self::Signature, pk: &Self::PublicKey) -> bool {
if !self.psf.check_domain(&sigma.0) {
return false;
}
let u = (self.hash).hash(&format!("{m} {} {}", sigma.1, &self.randomness_length));
self.psf.f_a(pk, &sigma.0) == u
}
}
#[cfg(test)]
mod test_pfdh {
use crate::signature::{SignatureScheme, pfdh::gpv::PFDHGPV};
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 pfdh = PFDHGPV::setup(n, &q, &s, 128);
let (pk, sk) = pfdh.key_gen();
for i in 0..10 {
let m = format!("Hello World! {i}");
let sigma = pfdh.sign(m.to_owned(), &sk, &pk);
assert!(pfdh.vfy(m.to_owned(), &sigma, &pk))
}
}
}