use crate::elgamal::arithmetic::scalars::{ScalarNonZero, ScalarTraits};
use crate::keys::*;
use rand_core::{CryptoRng, Rng};
#[derive(Copy, Clone, Debug)]
pub struct BlindingFactor(pub(crate) ScalarNonZero);
impl BlindingFactor {
pub fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
loop {
let scalar = ScalarNonZero::random(rng);
if scalar != ScalarNonZero::one() {
return Self(scalar);
}
}
}
pub fn from_scalar(scalar: ScalarNonZero) -> Self {
Self(scalar)
}
pub fn value(&self) -> &ScalarNonZero {
&self.0
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn to_hex(&self) -> String {
self.0.to_hex()
}
pub fn from_bytes(bytes: &[u8; 32]) -> Option<Self> {
ScalarNonZero::from_bytes(bytes).map(Self)
}
pub fn from_slice(slice: &[u8]) -> Option<Self> {
ScalarNonZero::from_slice(slice).map(Self)
}
pub fn from_hex(s: &str) -> Option<Self> {
ScalarNonZero::from_hex(s).map(Self)
}
}
pub trait BlindedGlobalSecretKey: Sized {
fn value(&self) -> &ScalarNonZero;
fn from_scalar(scalar: ScalarNonZero) -> Self;
fn to_bytes(&self) -> [u8; 32] {
self.value().to_bytes()
}
fn to_hex(&self) -> String {
self.value().to_hex()
}
fn from_bytes(bytes: &[u8; 32]) -> Option<Self> {
ScalarNonZero::from_bytes(bytes).map(Self::from_scalar)
}
fn from_slice(slice: &[u8]) -> Option<Self> {
ScalarNonZero::from_slice(slice).map(Self::from_scalar)
}
fn from_hex(s: &str) -> Option<Self> {
ScalarNonZero::from_hex(s).map(Self::from_scalar)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct BlindedPseudonymGlobalSecretKey(pub(crate) ScalarNonZero);
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct BlindedAttributeGlobalSecretKey(pub(crate) ScalarNonZero);
macro_rules! impl_blinded_global_secret_key {
($($t:ty),+ $(,)?) => {$(
impl BlindedGlobalSecretKey for $t {
fn value(&self) -> &ScalarNonZero {
&self.0
}
fn from_scalar(scalar: ScalarNonZero) -> Self {
Self(scalar)
}
}
)+};
}
impl_blinded_global_secret_key!(
BlindedPseudonymGlobalSecretKey,
BlindedAttributeGlobalSecretKey
);
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BlindedGlobalSecretKeys {
pub pseudonym: BlindedPseudonymGlobalSecretKey,
pub attribute: BlindedAttributeGlobalSecretKey,
}
fn compute_blinding_multiplier(blinding_factors: &[BlindingFactor]) -> Option<ScalarNonZero> {
let k = blinding_factors
.iter()
.fold(ScalarNonZero::one(), |acc, x| acc * x.0.invert());
if k == ScalarNonZero::one() {
return None;
}
Some(k)
}
pub trait BlindableGlobalSecretKey: SecretKey {
type BlindedType: BlindedGlobalSecretKey;
fn blind(&self, blinding_factors: &[BlindingFactor]) -> Option<Self::BlindedType> {
compute_blinding_multiplier(blinding_factors)
.map(|k| Self::BlindedType::from_scalar(*self.value() * k))
}
}
impl BlindableGlobalSecretKey for PseudonymGlobalSecretKey {
type BlindedType = BlindedPseudonymGlobalSecretKey;
}
impl BlindableGlobalSecretKey for AttributeGlobalSecretKey {
type BlindedType = BlindedAttributeGlobalSecretKey;
}
pub fn make_blinded_global_key<K>(
global_secret_key: &K,
blinding_factors: &[BlindingFactor],
) -> Option<K::BlindedType>
where
K: BlindableGlobalSecretKey,
{
global_secret_key.blind(blinding_factors)
}
pub fn make_blinded_pseudonym_global_secret_key(
global_secret_key: &PseudonymGlobalSecretKey,
blinding_factors: &[BlindingFactor],
) -> Option<BlindedPseudonymGlobalSecretKey> {
make_blinded_global_key(global_secret_key, blinding_factors)
}
pub fn make_blinded_attribute_global_secret_key(
global_secret_key: &AttributeGlobalSecretKey,
blinding_factors: &[BlindingFactor],
) -> Option<BlindedAttributeGlobalSecretKey> {
make_blinded_global_key(global_secret_key, blinding_factors)
}
pub fn make_blinded_global_keys(
pseudonym_global_secret_key: &PseudonymGlobalSecretKey,
attribute_global_secret_key: &AttributeGlobalSecretKey,
blinding_factors: &[BlindingFactor],
) -> Option<BlindedGlobalSecretKeys> {
let pseudonym = make_blinded_global_key(pseudonym_global_secret_key, blinding_factors)?;
let attribute = make_blinded_global_key(attribute_global_secret_key, blinding_factors)?;
Some(BlindedGlobalSecretKeys {
pseudonym,
attribute,
})
}