use crate::{DecryptionKey, EncryptionKey};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{self, Display};
use unknown_order::BigNumber;
use zeroize::Zeroize;
#[derive(Clone, Debug, Zeroize)]
pub struct Group {
pub(crate) g: BigNumber,
pub(crate) h: BigNumber,
pub(crate) n: BigNumber,
pub(crate) nd4: BigNumber,
pub(crate) nn: BigNumber,
pub(crate) n2d2: BigNumber,
pub(crate) n2d4: BigNumber,
pub(crate) two_inv_two: BigNumber,
}
impl Display for Group {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Group {{ g: {}, h: {}, n: {}, nd4: {}, nn: {}, n2d2: {}, n2d4: {}, two_inv_two: {} }}",
self.g, self.h, self.n, self.nd4, self.nn, self.n2d2, self.n2d4, self.two_inv_two
)
}
}
impl Serialize for Group {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let serdes = GroupSerdes {
g: self.g.clone(),
n: self.n.clone(),
};
serdes.serialize(serializer)
}
}
impl<'a> Deserialize<'a> for Group {
fn deserialize<D>(deserializer: D) -> Result<Group, D::Error>
where
D: Deserializer<'a>,
{
let GroupSerdes { g, n } = GroupSerdes::deserialize(deserializer)?;
let nn = &n * &n;
BigNumber::from(2)
.invert(&n)
.map(|two_inv| {
let n2d2: BigNumber = &nn >> 1;
let n2d4: BigNumber = &n2d2 >> 1;
let nd4: BigNumber = &n >> 2;
let h = &n + BigNumber::from(1);
let two_inv_two: BigNumber = two_inv << 1;
Group {
g,
h,
n,
nn,
n2d2,
n2d4,
nd4,
two_inv_two,
}
})
.ok_or_else(|| D::Error::custom("Unable to deserialize"))
}
}
impl Group {
pub fn new_keys(&self, max_messages: usize) -> Option<(EncryptionKey, DecryptionKey)> {
DecryptionKey::random(max_messages, self).map(|dk| {
let ek = EncryptionKey::from(&dk);
(ek, dk)
})
}
pub fn random() -> Option<Self> {
let mut p = BigNumber::safe_prime(1024);
let mut q = BigNumber::safe_prime(1024);
let res = Self::with_safe_primes_unchecked(&p, &q);
p.zeroize();
q.zeroize();
res
}
pub fn with_safe_primes(p: &BigNumber, q: &BigNumber) -> Option<Self> {
if !p.is_prime() || !q.is_prime() {
return None;
}
Self::with_safe_primes_unchecked(p, q)
}
#[allow(clippy::many_single_char_names)]
pub fn with_safe_primes_unchecked(p: &BigNumber, q: &BigNumber) -> Option<Self> {
if p == q {
return None;
}
let n = p * q;
let nn = &n * &n;
let g_tick = BigNumber::random(&nn);
BigNumber::from(2).invert(&n).map(|two_inv| {
let two_n2: BigNumber = &nn << 1;
let n2d2: BigNumber = &nn >> 1;
let n2d4: BigNumber = &n2d2 >> 1;
let nd4: BigNumber = &n >> 2;
let h = &n + BigNumber::from(1);
let g = g_tick.modpow(&two_n2, &nn);
let two_inv_two: BigNumber = two_inv << 1;
Group {
g,
h,
n,
nn,
n2d2,
n2d4,
nd4,
two_inv_two,
}
})
}
pub fn abs(&self, a: &BigNumber) -> BigNumber {
let tv = a % &self.nn;
if tv > self.n2d2 {
&self.nn - tv
} else {
tv
}
}
pub fn random_for_encrypt(&self) -> BigNumber {
let mut r = BigNumber::random(&self.nd4);
while r.is_zero() {
r = BigNumber::random(&self.nd4);
}
r
}
pub fn random_value(&self) -> BigNumber {
let mut r = BigNumber::random(&self.n2d4);
while r.is_zero() {
r = BigNumber::random(&self.n2d4);
}
r
}
pub fn hash(&self, u: &BigNumber, e: &[BigNumber], domain: &[u8]) -> BigNumber {
let mut transcript = merlin::Transcript::new(b"encryption hash generation");
transcript.append_message(b"u", &u.to_bytes());
transcript.append_message(
b"e",
&e.iter()
.map(|ee| ee.to_bytes())
.flatten()
.collect::<Vec<u8>>(),
);
transcript.append_message(b"domain", domain);
let mut hash = [0u8; 64];
transcript.challenge_bytes(b"encryption hash output", &mut hash);
BigNumber::from_slice(&hash)
}
pub fn pow(&self, base: &BigNumber, exp: &BigNumber) -> BigNumber {
base.modpow(exp, &self.nn)
}
pub fn mul(&self, lhs: &BigNumber, rhs: &BigNumber) -> BigNumber {
lhs.modmul(rhs, &self.nn)
}
pub fn g_pow(&self, exp: &BigNumber) -> BigNumber {
self.g.modpow(exp, &self.nn)
}
pub fn h_pow(&self, exp: &BigNumber) -> BigNumber {
self.h.modpow(exp, &self.nn)
}
pub fn g(&self) -> &BigNumber {
&self.g
}
pub fn h(&self) -> &BigNumber {
&self.h
}
pub fn n(&self) -> &BigNumber {
&self.n
}
pub fn nn(&self) -> &BigNumber {
&self.nn
}
}
#[derive(Serialize, Deserialize)]
struct GroupSerdes {
g: BigNumber,
n: BigNumber,
}