#![allow(unused_assignments)]
use alloc::{
collections::BTreeMap,
fmt::{self, Debug},
string::ToString,
vec::Vec,
};
use derive_getters::Getters;
#[cfg(any(test, feature = "test-impl"))]
use hex::FromHex;
use rand_core::{CryptoRng, RngCore};
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::{
serialization::{SerializableElement, SerializableScalar},
Ciphersuite, Element, Error, Field, Group, Header,
};
#[cfg(feature = "serialization")]
use crate::serialization::{Deserialize, Serialize};
use super::{keys::SigningShare, Identifier};
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct Nonce<C: Ciphersuite>(pub(super) SerializableScalar<C>);
impl<C> Nonce<C>
where
C: Ciphersuite,
{
pub fn new<R>(secret: &SigningShare<C>, rng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
let mut random_bytes = [0; 32];
rng.fill_bytes(&mut random_bytes[..]);
Self::nonce_generate_from_random_bytes(secret, random_bytes)
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
fn from_scalar(scalar: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar) -> Self {
Self(SerializableScalar(scalar))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn to_scalar(
self,
) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
self.0 .0
}
pub(crate) fn nonce_generate_from_random_bytes(
secret: &SigningShare<C>,
random_bytes: [u8; 32],
) -> Self {
let secret_enc = secret.0.serialize();
let input: Vec<u8> = random_bytes
.iter()
.chain(secret_enc.iter())
.cloned()
.collect();
Self::from_scalar(C::H3(input.as_slice()))
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableScalar::deserialize(bytes)?))
}
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize()
}
}
impl<C> Zeroize for Nonce<C>
where
C: Ciphersuite,
{
fn zeroize(&mut self) {
*self = Nonce::from_scalar(<<C::Group as Group>::Field>::zero());
}
}
#[cfg(any(test, feature = "test-impl"))]
impl<C> FromHex for Nonce<C>
where
C: Ciphersuite,
{
type Error = &'static str;
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
Self::deserialize(&v).map_err(|_| "malformed nonce encoding")
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
pub struct NonceCommitment<C: Ciphersuite>(pub(super) SerializableElement<C>);
impl<C> NonceCommitment<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new(value: Element<C>) -> Self {
Self(SerializableElement(value))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn value(&self) -> Element<C> {
self.0 .0
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableElement::deserialize(bytes)?))
}
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
self.0.serialize()
}
}
impl<C> Debug for NonceCommitment<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("NonceCommitment")
.field(
&self
.serialize()
.map(hex::encode)
.unwrap_or("<invalid>".to_string()),
)
.finish()
}
}
impl<C> From<Nonce<C>> for NonceCommitment<C>
where
C: Ciphersuite,
{
fn from(nonce: Nonce<C>) -> Self {
From::from(&nonce)
}
}
impl<C> From<&Nonce<C>> for NonceCommitment<C>
where
C: Ciphersuite,
{
fn from(nonce: &Nonce<C>) -> Self {
Self::new(<C::Group>::generator() * nonce.to_scalar())
}
}
#[cfg(any(test, feature = "test-impl"))]
impl<C> FromHex for NonceCommitment<C>
where
C: Ciphersuite,
{
type Error = &'static str;
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
Self::deserialize(&v).map_err(|_| "malformed nonce commitment encoding")
}
}
#[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq, Eq, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SigningNonces<C: Ciphersuite> {
#[getter(skip)]
pub(crate) header: Header<C>,
pub(crate) hiding: Nonce<C>,
pub(crate) binding: Nonce<C>,
#[zeroize(skip)]
pub(crate) commitments: SigningCommitments<C>,
}
impl<C> SigningNonces<C>
where
C: Ciphersuite,
{
pub fn new<R>(secret: &SigningShare<C>, rng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
let hiding = Nonce::<C>::new(secret, rng);
let binding = Nonce::<C>::new(secret, rng);
Self::from_nonces(hiding, binding)
}
pub fn from_nonces(hiding: Nonce<C>, binding: Nonce<C>) -> Self {
let hiding_commitment = (&hiding).into();
let binding_commitment = (&binding).into();
let commitments = SigningCommitments::new(hiding_commitment, binding_commitment);
Self {
header: Header::default(),
hiding,
binding,
commitments,
}
}
}
impl<C> Debug for SigningNonces<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SigningNonces")
.field("hiding", &"<redacted>")
.field("binding", &"<redacted>")
.finish()
}
}
#[cfg(feature = "serialization")]
impl<C> SigningNonces<C>
where
C: Ciphersuite,
{
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SigningCommitments<C: Ciphersuite> {
#[getter(skip)]
pub(crate) header: Header<C>,
pub(crate) hiding: NonceCommitment<C>,
pub(crate) binding: NonceCommitment<C>,
}
impl<C> SigningCommitments<C>
where
C: Ciphersuite,
{
pub fn new(hiding: NonceCommitment<C>, binding: NonceCommitment<C>) -> Self {
Self {
header: Header::default(),
hiding,
binding,
}
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(super) fn to_group_commitment_share(
self,
binding_factor: &crate::BindingFactor<C>,
) -> GroupCommitmentShare<C> {
GroupCommitmentShare::<C>(self.hiding.value() + (self.binding.value() * binding_factor.0))
}
}
#[cfg(feature = "serialization")]
impl<C> SigningCommitments<C>
where
C: Ciphersuite,
{
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}
impl<C> From<&SigningNonces<C>> for SigningCommitments<C>
where
C: Ciphersuite,
{
fn from(nonces: &SigningNonces<C>) -> Self {
nonces.commitments
}
}
#[derive(Clone, Copy, PartialEq)]
pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
impl<C: Ciphersuite> GroupCommitmentShare<C> {
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[allow(unused)]
pub(crate) fn from_element(element: Element<C>) -> Self {
Self(element)
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn to_element(self) -> Element<C> {
self.0
}
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(super) fn encode_group_commitments<C: Ciphersuite>(
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Result<Vec<u8>, Error<C>> {
let mut bytes = vec![];
for (item_identifier, item) in signing_commitments {
bytes.extend_from_slice(item_identifier.serialize().as_ref());
bytes.extend_from_slice(<C::Group>::serialize(&item.hiding.value())?.as_ref());
bytes.extend_from_slice(<C::Group>::serialize(&item.binding.value())?.as_ref());
}
Ok(bytes)
}
pub fn preprocess<C, R>(
num_nonces: u8,
secret: &SigningShare<C>,
rng: &mut R,
) -> (Vec<SigningNonces<C>>, Vec<SigningCommitments<C>>)
where
C: Ciphersuite,
R: CryptoRng + RngCore,
{
let mut signing_nonces: Vec<SigningNonces<C>> = Vec::with_capacity(num_nonces as usize);
let mut signing_commitments: Vec<SigningCommitments<C>> =
Vec::with_capacity(num_nonces as usize);
for _ in 0..num_nonces {
let nonces = SigningNonces::new(secret, rng);
signing_commitments.push(SigningCommitments::from(&nonces));
signing_nonces.push(nonces);
}
(signing_nonces, signing_commitments)
}
pub fn commit<C, R>(
secret: &SigningShare<C>,
rng: &mut R,
) -> (SigningNonces<C>, SigningCommitments<C>)
where
C: Ciphersuite,
R: CryptoRng + RngCore,
{
let (mut vec_signing_nonces, mut vec_signing_commitments) = preprocess(1, secret, rng);
(
vec_signing_nonces.pop().expect("must have 1 element"),
vec_signing_commitments.pop().expect("must have 1 element"),
)
}