c255b3 0.0.2

Schorr signatures based Curve25519 and Blake3
Documentation
# c255b3: schnorr signatures using curve25519 and blake3.

This crate provides [Schnorr signatures][Schnorr] based on [Curve25519] and [Blake3].

[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 an alpha version of a (slightly) novel cryptographic primitive.
It has not been audited and you may encounter breaking API and cryptographic changes until the first stable version!
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.