c255b3 0.0.3

Schorr signatures based Curve25519 and Blake3
Documentation
//! The c255b3 signature scheme: deterministic Schnorr signatures with Curve25519 and Blake3.
//!
//! # Example Usage
//!
//! ## Generating
//!
//! To sign a message you first need a [SecretKey].
//!
//! ```
//! # fn main() {
//! use c255b3::SecretKey;
//! use rand::{RngCore,rngs::OsRng};
//!
//! // Generate 256 random bits.
//! let mut csprng = OsRng;
//! let mut raw_key = [0u8; 32];
//! csprng.fill_bytes(&mut raw_key);
//!
//! // Create a secret key from those bits.
//! let secret_key = SecretKey::from_bits(&raw_key);
//! # }
//! ```
//!
//! ## Signing
//!
//! Once generated, the secret key can produce a [Signature] for a messages:
//!
//! ```
//! # fn main() {
//! # use c255b3::SecretKey;
//! # use rand::{RngCore,rngs::OsRng};
//! # let mut csprng = OsRng;
//! # let mut raw_key = [0u8; 32];
//! # csprng.fill_bytes(&mut raw_key);
//! # let secret_key = SecretKey::from_bits(&raw_key);
//! use c255b3::{Domain,Signature};
//!
//! let msg: &[u8] = b"Did gyre and gimble in the wabe:";
//! let domain = Domain(b"test domain for documentation...");
//! let sig: Signature = secret_key.sign_domain(domain, msg);
//! # }
//! ```
//!
//! ## Verifying
//!
//! Then we can derive the [PublicKey], and check the signature.
//!
//! ```
//! # fn main() {
//! # use c255b3::{SecretKey, Signature, Domain};
//! # use rand::{RngCore,rngs::OsRng};
//! # let mut csprng = OsRng;
//! # let mut raw_key = [0u8; 32];
//! # csprng.fill_bytes(&mut raw_key);
//! # let secret_key = SecretKey::from_bits(&raw_key);
//! # let msg: &[u8] = b"Did gyre and gimble in the wabe:";
//! # let domain = Domain(b"test domain for documentation...");
//! # let sig: Signature = secret_key.sign_domain(domain, msg);
//! use c255b3::PublicKey;
//!
//! let public_key: PublicKey = secret_key.derive_public();
//! assert!(public_key.verify_domain(domain, &sig, msg).is_ok());
//! # }
//! ```
mod domain;
mod keys;
mod public;
mod secret;
mod sig;

pub use domain::Domain;
pub use keys::Keys;
pub use public::PublicKey;
pub use secret::SecretKey;
pub use sig::Signature;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
/// The errors we can encounter while working with c255b3 keys and signatures.
pub enum Error {
    /// The secret key hasn't had its five fixed bits set correctly.
    InvalidSecretKey,
    /// Failed to decompress a compressed edwards point in the public key.
    FailedDecompression,
    /// The public key has low order.
    WeakPublicKey,
    /// A scalar in the signature is not in its cononical representation.
    NonCanonicalSignature,
    /// The reconstructed "e" value doesn't match the signature "e" value.
    SignatureMismatch,
}

#[cfg(test)]
const MSG0: &[u8] = b"'Twas brillig and the slithy toves";
#[cfg(test)]
const MSG1: &[u8] = b"All mimsy were the borogoves,";
#[cfg(test)]
const D0: Domain = Domain(b"test domain for running tests...");
#[cfg(test)]
const D1: Domain = Domain(b"test domain for documentation...");

#[test]
fn fail_to_verify_with_wrong_key() {
    use rand::{rngs::OsRng, RngCore};
    let mut csprng = OsRng;
    let mut raw_key = [0u8; 32];

    csprng.fill_bytes(&mut raw_key);
    let ska = SecretKey::from_bits(&raw_key);
    let pka = ska.derive_public();
    let sig = ska.sign(MSG0);

    csprng.fill_bytes(&mut raw_key);
    let skb = SecretKey::from_bits(&raw_key);
    let pkb = skb.derive_public();

    assert!(pka.verify(&sig, MSG0).is_ok());
    assert_eq!(pkb.verify(&sig, MSG0), Err(Error::SignatureMismatch));
}

#[test]
fn fail_to_verify_with_wrong_domain() {
    use rand::{rngs::OsRng, RngCore};
    let mut csprng = OsRng;
    let mut raw_key = [0u8; 32];

    csprng.fill_bytes(&mut raw_key);
    let ska = SecretKey::from_bits(&raw_key);
    let pka = ska.derive_public();
    let sig = ska.sign_domain(D0, MSG0);

    assert!(pka.verify_domain(D0, &sig, MSG0).is_ok());
    assert_eq!(
        pka.verify_domain(D1, &sig, MSG0),
        Err(Error::SignatureMismatch)
    );
}

#[test]
fn different_nonces_for_different_messages() {
    use rand::{rngs::OsRng, RngCore};
    let mut csprng = OsRng;
    let mut raw_key = [0u8; 32];

    csprng.fill_bytes(&mut raw_key);
    let ska = SecretKey::from_bits(&raw_key);
    let n0 = ska.derive_nonce(D0, MSG0);
    let n1 = ska.derive_nonce(D0, MSG1);

    assert!(n0 != n1);
}

#[test]
fn different_nonces_for_different_domains() {
    use rand::{rngs::OsRng, RngCore};
    let mut csprng = OsRng;
    let mut raw_key = [0u8; 32];

    csprng.fill_bytes(&mut raw_key);
    let ska = SecretKey::from_bits(&raw_key);
    let n0 = ska.derive_nonce(D0, MSG0);
    let n1 = ska.derive_nonce(D1, MSG0);

    assert!(n0 != n1);
}