#![forbid(unsafe_code)]
use curve25519_dalek::{EdwardsPoint, Scalar};
use oxicrypto_core::CryptoError;
use zeroize::{Zeroize, ZeroizeOnDrop};
use super::{
deserialize_element, h3, scalar_base_mult, serialize_element, serialize_scalar, Identifier,
ELEMENT_LEN,
};
#[derive(Clone)]
pub struct SigningNonces {
identifier: Identifier,
hiding_nonce: Scalar,
binding_nonce: Scalar,
}
impl SigningNonces {
#[must_use]
pub fn identifier(&self) -> Identifier {
self.identifier
}
#[must_use]
pub fn hiding_nonce(&self) -> Scalar {
self.hiding_nonce
}
#[must_use]
pub fn binding_nonce(&self) -> Scalar {
self.binding_nonce
}
#[must_use]
pub fn commitments(&self) -> SigningCommitments {
SigningCommitments {
identifier: self.identifier,
hiding: scalar_base_mult(&self.hiding_nonce),
binding: scalar_base_mult(&self.binding_nonce),
}
}
}
impl Drop for SigningNonces {
fn drop(&mut self) {
self.hiding_nonce.zeroize();
self.binding_nonce.zeroize();
}
}
impl ZeroizeOnDrop for SigningNonces {}
#[derive(Clone, Copy, Debug)]
pub struct SigningCommitments {
identifier: Identifier,
hiding: EdwardsPoint,
binding: EdwardsPoint,
}
impl SigningCommitments {
#[must_use]
pub fn new(identifier: Identifier, hiding: EdwardsPoint, binding: EdwardsPoint) -> Self {
Self {
identifier,
hiding,
binding,
}
}
#[must_use = "result must be checked"]
pub fn from_bytes(
identifier: Identifier,
hiding_bytes: &[u8],
binding_bytes: &[u8],
) -> Result<Self, CryptoError> {
Ok(Self {
identifier,
hiding: deserialize_element(hiding_bytes)?,
binding: deserialize_element(binding_bytes)?,
})
}
#[must_use]
pub fn identifier(&self) -> Identifier {
self.identifier
}
#[must_use]
pub fn hiding(&self) -> EdwardsPoint {
self.hiding
}
#[must_use]
pub fn binding(&self) -> EdwardsPoint {
self.binding
}
#[must_use = "result must be checked"]
pub fn hiding_bytes(&self) -> Result<[u8; ELEMENT_LEN], CryptoError> {
serialize_element(&self.hiding)
}
#[must_use = "result must be checked"]
pub fn binding_bytes(&self) -> Result<[u8; ELEMENT_LEN], CryptoError> {
serialize_element(&self.binding)
}
}
#[must_use]
fn nonce_generate(random_bytes: &[u8; 32], secret: &Scalar) -> Scalar {
let secret_enc = serialize_scalar(secret);
let mut input = [0u8; 64];
input[..32].copy_from_slice(random_bytes);
input[32..].copy_from_slice(&secret_enc);
let nonce = h3(&input);
input.zeroize();
nonce
}
#[must_use = "signing nonces must be retained for round two"]
pub(crate) fn commit_with_randomness(
identifier: Identifier,
secret: &Scalar,
hiding_randomness: &[u8; 32],
binding_randomness: &[u8; 32],
) -> SigningNonces {
SigningNonces {
identifier,
hiding_nonce: nonce_generate(hiding_randomness, secret),
binding_nonce: nonce_generate(binding_randomness, secret),
}
}
#[must_use = "signing nonces must be retained for round two"]
pub fn commit<R: rand_core::TryCryptoRng + ?Sized>(
rng: &mut R,
identifier: Identifier,
secret: &Scalar,
) -> Result<SigningNonces, CryptoError> {
let mut hiding_randomness = [0u8; 32];
let mut binding_randomness = [0u8; 32];
rng.try_fill_bytes(&mut hiding_randomness)
.map_err(|_| CryptoError::Rng)?;
rng.try_fill_bytes(&mut binding_randomness)
.map_err(|_| CryptoError::Rng)?;
let nonces =
commit_with_randomness(identifier, secret, &hiding_randomness, &binding_randomness);
hiding_randomness.zeroize();
binding_randomness.zeroize();
Ok(nonces)
}