c255b3 0.0.3

Schorr signatures based Curve25519 and Blake3
Documentation
use crate::{Domain, Error, Keys, PublicKey, Signature};
use curve25519_dalek::{EdwardsPoint, Scalar};
use subtle::ConstantTimeEq;
use zeroize::Zeroize;

/// A c255b3 secret key to sign messages with.
///
/// It has slightly more than 252 bits of entropy.
#[derive(Clone, Eq, Hash)]
pub struct SecretKey(pub(crate) Scalar);

impl core::fmt::LowerHex for SecretKey {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for x in self.0.to_bytes() {
            write!(f, "{:02x}", x)?;
        }
        Ok(())
    }
}

impl core::fmt::Debug for SecretKey {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "SecretKey {:x}", *self)
    }
}

/// This is constant time.
impl PartialEq for SecretKey {
    fn eq(&self, other: &Self) -> bool {
        self.ct_eq(other).into()
    }
}

impl ConstantTimeEq for SecretKey {
    fn ct_eq(&self, other: &Self) -> subtle::Choice {
        self.0.ct_eq(&other.0)
    }
}

/// Zeros memory before freeing.
impl Drop for SecretKey {
    fn drop(&mut self) {
        self.0.zeroize();
    }
}

impl From<Scalar> for SecretKey {
    fn from(value: Scalar) -> Self {
        SecretKey(value)
    }
}

impl SecretKey {
    /// Parse a secret key from an externally provided byte array,
    /// ensuring that it is a valid key.
    ///
    /// Use [from_bits][SecretKey::from_bits] if you are generating keys.
    pub fn parse_bits(bits: &[u8; 32]) -> Result<SecretKey, Error> {
        let sk = SecretKey::from_bits(bits);
        if sk.to_bits() == *bits {
            Ok(sk)
        } else {
            Err(Error::InvalidSecretKey)
        }
    }

    /// Render the secret key into a byte array for external use.
    pub fn to_bits(&self) -> [u8; 32] {
        self.0.to_bytes()
    }

    /// Construct a secret key from 256 arbitrary bits,
    ///
    /// Use [parse_bits][SecretKey::parse_bits] if you are reading this key from storage or anything like that.
    pub fn from_bits(value: &[u8; 32]) -> SecretKey {
        SecretKey(Scalar::from_bytes_mod_order(*value))
    }

    /// Sign a message, in a particular domain, with a derived nonce.
    ///
    /// This is the primary signing method.
    pub fn sign_domain(&self, domain: Domain, msg: &[u8]) -> Signature {
        let nonce = self.derive_nonce(domain, msg);
        self.sign_nonce(domain, &nonce, msg)
    }

    /// Sign a message, in the default domain, with the derived nonce.
    ///
    /// This method can be used for general purpose signatures.
    /// If your signatures are application-specific please use [sign_domain][SecretKey::sign_domain]!
    pub fn sign(&self, msg: &[u8]) -> Signature {
        self.sign_domain(Domain::default(), msg)
    }

    /// Sign a message, in a particular domain, with the supplied secret nonce.
    ///
    /// If you really want randomized signatures, this is the function to use.
    /// Make sure you have a really solid random number generator making these nonces!
    pub fn sign_nonce(&self, domain: Domain, nonce: &[u8; 32], msg: &[u8]) -> Signature {
        // Note that, for a uniform nonce, this introduces a bias of ~1/126.6 bits.
        // Increasing the nonce to 512 bits (what Ed25519 does) would decrease this to ~1/261.5 bits of bias.
        // If there does emerge an attack that can combine bias from multiple signatures,
        // this would mean that a c255b3 secret key wears out after about half as many signatures as a Ed25519 secret key.
        let k = Scalar::from_bytes_mod_order(*nonce);
        let r = EdwardsPoint::mul_base(&k);
        let e = domain.hash_to_scalar(&r, msg);
        let s = k - (e * self.0);
        Signature { e, s }
    }

    /// Derive the public key from the secret key.
    ///
    /// (Scales the base point by the secret key.)
    pub fn derive_public(&self) -> PublicKey {
        let point = EdwardsPoint::mul_base(&self.0);
        let compressed = point.compress();
        PublicKey { compressed, point }
    }

    /// Derive a complete signing key from the secret key.
    pub fn derive_keys(&self) -> Keys {
        let pk = self.derive_public();
        let sk = SecretKey(self.0);
        Keys { pk, sk }
    }

    /// Generate 256 "random" bits, deterministicly derived from the message, domain, and this key.
    pub(crate) fn derive_nonce(&self, domain: Domain, msg: &[u8]) -> [u8; 32] {
        domain.hash(&self.0.as_bytes(), msg)
    }
}