use crate::{common::*, curve_arithmetic::*};
use rand::*;
use std::ops::Deref;
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, SerdeBase16Serialize)]
pub struct Cipher<C: Curve>(pub C, pub C);
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
#[repr(transparent)]
pub struct Randomness<C: Curve> {
pub randomness: Rc<Secret<C::Scalar>>,
}
impl<C: Curve> AsRef<C::Scalar> for Randomness<C> {
fn as_ref(&self) -> &C::Scalar {
&self.randomness
}
}
impl<C: Curve> Deref for Randomness<C> {
type Target = C::Scalar;
fn deref(&self) -> &C::Scalar {
&self.randomness
}
}
impl<C: Curve> Randomness<C> {
pub fn new(v: C::Scalar) -> Self {
Randomness {
randomness: Rc::new(Secret::new(v)),
}
}
pub fn to_value(&self) -> Value<C> {
Value {
value: self.randomness.clone(),
}
}
pub fn generate<T>(csprng: &mut T) -> Self
where
T: Rng,
{
Randomness::new(C::generate_non_zero_scalar(csprng))
}
}
impl<C: Curve> Cipher<C> {
#[inline]
pub fn from_bytes<R: ReadBytesExt>(bytes: &mut R) -> anyhow::Result<Cipher<C>> {
let g = C::deserial(bytes)?;
let h = C::deserial(bytes)?;
Ok(Cipher(g, h))
}
pub fn generate<T>(csprng: &mut T) -> Self
where
T: Rng,
{
Cipher(C::generate(csprng), C::generate(csprng))
}
pub fn combine(&self, other: &Self) -> Self {
Self(self.0.plus_point(&other.0), self.1.plus_point(&other.1))
}
pub fn scale(&self, e: &C::Scalar) -> Self {
Self(self.0.mul_by_scalar(e), self.1.mul_by_scalar(e))
}
pub fn scale_u64(&self, e: u64) -> Self {
self.scale(&C::scalar_from_u64(e))
}
}
pub fn multicombine<C: Curve>(ciphers: &[Cipher<C>], scalars: &[C::Scalar]) -> Cipher<C> {
assert_eq!(
ciphers.len(),
scalars.len(),
"multicombine precondition violation: input slices have different length."
);
let (ciphers_0, ciphers_1): (Vec<_>, Vec<_>) = ciphers.iter().map(|x| (x.0, x.1)).unzip();
Cipher(multiexp(&ciphers_0, scalars), multiexp(&ciphers_1, scalars))
}
#[cfg(test)]
mod tests {
use crate::curve_arithmetic::arkworks_instances::ArkGroup;
use super::*;
use ark_bls12_381::{G1Projective, G2Projective};
macro_rules! macro_test_cipher_to_byte_conversion {
($function_name:ident, $curve_type:path) => {
#[test]
pub fn $function_name() {
let mut csprng = thread_rng();
for _i in 1..100 {
let c: Cipher<$curve_type> = Cipher::generate(&mut csprng);
let s = serialize_deserialize(&c);
assert!(s.is_ok());
assert_eq!(c, s.unwrap());
}
}
};
}
macro_test_cipher_to_byte_conversion!(key_to_cipher_conversion_g1, ArkGroup<G1Projective>);
macro_test_cipher_to_byte_conversion!(key_to_cipher_conversion_g2, ArkGroup<G2Projective>);
}