# c255b3: schnorr signatures using curve25519 and blake3. This crate provides [Schnorr signatures][Schnorr] based on [Curve25519] and [Blake3]. Please note that this particular formulation is deprecated. It lives on as [r255b3], based on ristretto255 and blake3 instead, for a cleaner definition and faster public key parsing. [r255b3]: https://crates.io/crates/r255b3 [Schnorr]: https://en.wikipedia.org/wiki/Schnorr_signature [Curve25519]: https://en.wikipedia.org/wiki/Curve25519 [Blake3]: https://github.com/BLAKE3-team/BLAKE3 Note: This is not [Ed25519], if you want Ed25519, please use the excellent [ed25519-dalek] crate. [Ed25519]: https://en.wikipedia.org/wiki/Ed25519 [ed25519-dalek]: https://crates.io/crates/ed25519-dalek Warning! This is a deprecated cryptographic primitive. It has not been audited. Use at your own risk! ## Why? The initial motivation was preparing for embedded versions of [converge]. We already use the Blake3 hash function for bulk data, and adding SHA512 just for Ed25519 signatures just isn't necessary. That said, there are other benefits: - proper application-specific domain separation for signatures - support for non-deterministic signatures with application-supplied nonces - well specified secret and public keys - a [*much* faster][Blake3] hash function [converge]: https://adpt.dev/tools/converge ## How? For the most part the parameterization is straight-forward. However there are two minor deviations: - The keyed version of Blake3 is used to provide domain separation. - The nonce `k` is deterministic by default, a Blake3 hash of the private key and message keyed with the domain. ### Key Generation c255b3 uses 255-bit (less 19 values) secret keys. Contrary to Ed25519 it does not require [clamping][ed25519-clamping], though to reuse the keys with X25519 the low three bits must be cleared. The secret key `sk` may simply be generated as 256 random bits and reduced modulo the order of the base point (slightly more than 2²⁵²). [ed25519-clamping]: https://www.jcraige.com/an-explainer-on-ed25519-clamping ### Signing The first step is to generate the scalar nonce `k`. This can be done with a random number generator, or by taking the Blake3 hash (keyed with the domain) of the secret key concatinated with the message. ``` k = Blake3(domain, sk | message) ``` Now `k` multiplies the base point to get the point `r`, which we will recover later while verifying. `r` is compressed, concatinated with the message, and fed to Blake2 to used to derive the scalar `e`. ``` r = k*B e = Blake3(domain, r | message) ``` Finally, we multiply `e` and the secret key, and subtract their product from `k`, yielding the scalar `s`. This produces our signature, which is the tuple of `e` and `s`. ``` s = k - sk * e sig = (e, s) ``` ![](doc/c255b3.svg) ### Verifying For verification we need the public key, this is found by multiplying the base point by the private key. ``` pk = sk*B ``` Then we take our signature and reconstruct `r`, calling it `rᵥ`: ``` rᵥ = s*B + e*pk = (k - sk*e)*B + (e*sk*B) = k*B - sk*e*B + e*sk*B = k*B ``` Now that we have `rᵥ`, we hash the message with Blake3 exactly as was done during signing. This yields another copy of `e`, which we call `eᵥ`. ``` eᵥ = Blake3(domain, rᵥ | message) ``` Finally we can compare `eᵥ` with the `e` from the signature, and if they match we have a valid signature. ## License This project is dedicated to the public domain, see the [UNLICENSE](./UNLICENSE) for details.