#![forbid(unsafe_code)]
use curve25519_dalek::{EdwardsPoint, Scalar};
use ed25519_dalek::{Signature as Ed25519Signature, VerifyingKey as Ed25519VerifyingKey};
use oxicrypto_core::CryptoError;
use super::round1::SigningCommitments;
use super::round2::SignatureShare;
use super::{
compute_binding_factors, compute_challenge, compute_group_commitment, deserialize_element,
deserialize_scalar, scalar_base_mult, serialize_element, serialize_scalar, ELEMENT_LEN,
SIGNATURE_LEN,
};
#[derive(Clone, Copy, Debug)]
pub struct Signature {
r: EdwardsPoint,
z: Scalar,
}
impl Signature {
#[must_use]
pub fn new(r: EdwardsPoint, z: Scalar) -> Self {
Self { r, z }
}
#[must_use]
pub fn r(&self) -> EdwardsPoint {
self.r
}
#[must_use]
pub fn z(&self) -> Scalar {
self.z
}
#[must_use = "result must be checked"]
pub fn to_bytes(&self) -> Result<[u8; SIGNATURE_LEN], CryptoError> {
let r_enc = serialize_element(&self.r)?;
let z_enc = serialize_scalar(&self.z);
let mut out = [0u8; SIGNATURE_LEN];
out[..ELEMENT_LEN].copy_from_slice(&r_enc);
out[ELEMENT_LEN..].copy_from_slice(&z_enc);
Ok(out)
}
#[must_use = "result must be checked"]
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
if bytes.len() != SIGNATURE_LEN {
return Err(CryptoError::InvalidTag);
}
let r = deserialize_element(&bytes[..ELEMENT_LEN]).map_err(|_| CryptoError::InvalidTag)?;
let z = deserialize_scalar(&bytes[ELEMENT_LEN..]).map_err(|_| CryptoError::InvalidTag)?;
Ok(Self { r, z })
}
}
#[must_use = "the aggregated signature must be used"]
pub fn aggregate(
commitment_list: &[SigningCommitments],
msg: &[u8],
group_public_key: &EdwardsPoint,
sig_shares: &[SignatureShare],
) -> Result<Signature, CryptoError> {
let binding_factor_list = compute_binding_factors(group_public_key, commitment_list, msg)?;
let group_commitment = compute_group_commitment(commitment_list, &binding_factor_list)?;
let mut z = Scalar::ZERO;
for share in sig_shares {
z += share.value();
}
Ok(Signature::new(group_commitment, z))
}
#[must_use = "verification result must be checked"]
pub fn verify_signature(
signature: &Signature,
msg: &[u8],
group_public_key: &EdwardsPoint,
) -> Result<(), CryptoError> {
let challenge = compute_challenge(&signature.r(), group_public_key, msg)?;
let lhs = scalar_base_mult(&signature.z());
let rhs = signature.r() + (*group_public_key * challenge);
if lhs != rhs {
return Err(CryptoError::Sign);
}
verify_ed25519(signature, msg, group_public_key)
}
fn verify_ed25519(
signature: &Signature,
msg: &[u8],
group_public_key: &EdwardsPoint,
) -> Result<(), CryptoError> {
let pk_bytes = serialize_element(group_public_key)?;
let verifying_key =
Ed25519VerifyingKey::from_bytes(&pk_bytes).map_err(|_| CryptoError::InvalidKey)?;
let sig_bytes = signature.to_bytes()?;
let ed_sig = Ed25519Signature::from_bytes(&sig_bytes);
verifying_key
.verify_strict(msg, &ed_sig)
.map_err(|_| CryptoError::Sign)
}