Skip to content

VRF crate #1794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 88 commits into
base: master
Choose a base branch
from
Draft

VRF crate #1794

wants to merge 88 commits into from

Conversation

carloskiki
Copy link

Adding traits for Verifiable Random Functions. See #1728.

The vrf name on crates.io is taken. The current crate under this name seems unmaintained, the last commit being 3 years ago.

The exact structure of the traits is not defined yet, I'm mostly looking for some input until we resolve the crate name and have some confidence that we have a good interface.

@tarcieri
Copy link
Member

For a crate name, verifiable-random-function would fit our naming scheme

@newpavlov
Copy link
Member

We could ask in the vrf repo about potential crate ownership transfer. Another option is to use something like crypto-vrf.

@carloskiki
Copy link
Author

We could ask in the vrf repo about potential crate ownership transfer.

Yes, the maintainers seem active on github. If we decide to try getting the name vrf, let me know if I should be the one contacting them. I think if a maintainer of RustCrypto does then we have more credibility but I'm open to doing it.

@carloskiki
Copy link
Author

Otherwise, we could abuse the Signer and Verifier traits, and implement them with a type parameter that implements proof (this is very likely not a good idea). We wouldn't need the Prover and Verifier traits. Or maybe we just want the Prover trait and we reuse the Verifier trait from signature, because all vrfs that I know of are based on asymmetric signatures.

@@ -0,0 +1,26 @@
use digest::{Output, OutputSizeUser};

pub trait Proof<H>
Copy link
Member

@tarcieri tarcieri Mar 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is intended to be pi in RFC9381 parlance it would be nice to note that in the rustdoc and also, what about serializing/deserializing pi itself?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I did not write any doc comments yet, because I'm not sure about the design and I want my ideas to mature a bit. But indeed, this is pi, which means we should be able to serialize and deserialize it. This would be similar to SignatureEncoding in the signature crate.

Having both crates being so similar makes we wonder whether we really need a new crate for this. Using the Signer trait to serve as a Prover is an abuse of language, but both traits are the same semantically and the Verifier trait would be identical in both crates. SignatureEncoding also maps to vrfs because we need encoding/decoding for the proof. The only thing we are missing from the signature crate would be a way of hashing the proof (VRF_proof_to_hash in RFC9381).

@tarcieri
Copy link
Member

Yes, traits from the signature crate could be used instead if we want. If the only thing that's really needed is a trait for VRF_proof_to_hash, we could potentially just add that to signature.

The nice thing about a separate crate is it could have stricter bounds which would make things a bit easier to use. Instead of having to bound on Signature: SignatureEncoding + VrfProofToHash (or whatever), those bounds could simply be automatic (in addition to the trait names being more idiomatic for VRFs)

@carloskiki
Copy link
Author

carloskiki commented Apr 24, 2025

Yes, traits from the signature crate could be used instead if we want. If the only thing that's really needed is a trait for VRF_proof_to_hash, we could potentially just add that to signature.

The nice thing about a separate crate is it could have stricter bounds which would make things a bit easier to use. Instead of having to bound on Signature: SignatureEncoding + VrfProofToHash (or whatever), those bounds could simply be automatic (in addition to the trait names being more idiomatic for VRFs)

After some time off, I think what we should do is use the Verifier trait from the signature crate, and keep the Proof and Prover traits.

A question I would like answered: should we add VRFs as a module in signature (perhaps behind a feature) or should we keep it in a separate crate?

@tarcieri
Copy link
Member

Since signature is a post-1.0 crate I think it would be nice to prove it out in a separate crate. It could eventually be merged.

carloskiki and others added 16 commits April 24, 2025 19:48
This PR implements `Zeroize` for `NonIdentity` setting it to `G` to
prevent breaking any invariants.
This PR adds `NonIdentity::mul_by_generator()`, which is similar to the
`MulByGenerator` trait, but returns a `NonIdentity` instead of a
`ProjectivePoint`. This is quite useful for getting the public key from
a `NonZeroScalar` without having to go through the whole conversion
dance.
This PR adds a new trait called `CollisionResistance` which can be
applied to hashes and MACs to signify their collision resistance.
This is hopefully no longer relevant
Replaces `elliptic_curve::ops::Invert` which has an identical shape
…pto#1813)""

This reverts commit 2ab0f99.

Reverting the revert now that we can pin to the hash with the revert
…tCrypto#1827)" (RustCrypto#1840)

This reverts commit bf47748.

Per RustCrypto#1831 this change breaks inference when there is a single explicit
impl of the `Signer` trait.

It also wasn't possible to add corresponding blanket impls to the
`Async*` traits, e.g. `AsyncSigner` for `AsyncDigestSigner`, because of
the existing blanket impl of `AsyncSigner` for `Signer` which we
definitely want to preserve.

As a general rule of thumb, blanket impls only make sense if they work
100% of the time, which doesn't seem to be happening here.

Closes RustCrypto#1831
`signature_derive` was used to provide a `Signer` implementation from a
`DigestSigner` and `PrehashSignature` but it does not appears to be used
in any place I can see.

If this becomes to actually be used, we'll then provide a macro-based
implementation for it but I'll hold on to that until we find a consumer.
daxpedda and others added 30 commits June 2, 2025 16:06
…o#1880)

This PR adds new traits for multipart messages: `MultipartSigner`,
`RandomizedMultipartSigner`, `RandomizedMultipartSignerMut` and
`MultipartVerifier`.

The idea here is to allow non-contiguous bytes to be passed, which is
necessary when the message has to be constructed from multiple sources
without wanting to allocate memory for a contiguous message. E.g. for
`no_std` environments or when the message is rather big but pre-hashing
is not applicable, e.g. PureEdDSA, ML-DSA or SLH-DSA.

I know this is a rather big breaking change, so let me know what you
think!

These new traits can be implemented by a bunch of crates:
- [x] `ecdsa`: RustCrypto/signatures#982
- [x] `ml-dsa`: RustCrypto/signatures#982
- [x]  `slh-dsa`: RustCrypto/signatures#982
- [x] `bign256`: RustCrypto/elliptic-curves#1221
- [x] `sm2`: RustCrypto/elliptic-curves#1221
- [x] `k256`: RustCrypto/elliptic-curves#1221
- [x] `dsa`: RustCrypto/signatures#982
- [x] `lms`: RustCrypto/signatures#982
- [x] `rsa`: RustCrypto/RSA#525
- [ ] `ed25519-dalek`

Resolves RustCrypto/signatures#959.
We've merged the relevant functionality into the `signature` crate
proper
Includes `MultipartSigner`/`MultipartVerifier`
In the past we've deliberately avoided exposing the y-coordinate to
prevent the possibility of things like invalid curve attacks, although
with time we have exposed more and more to support things like
alternative point compression formats. See RustCrypto#1237 for some history.

We're now trying to use these traits with Edwards curves like Curve25519
(in `curve25519-dalek`) and Ed448-Goldilocks, which use compressed
Edwards y-coordinates as their compressed point format. That requires
y-coordinate access.

As such, this changes the previous `y_is_odd` method, which was used to
implement SEC1-like compressed points, to a full `fn y` which returns a
serialized field element for the y-coordinate.

Closes RustCrypto#1019
This implements `BatchInvert` for `NonZeroScalar`.

To accomplish this, I did the following notable things:
- Remove all trait bounds on `BatchInvert` itself.
- Remove `CtOption` from `BatchInvert::batch_invert`s return type.
- Expose `invert_batch_internal()` internally, which now takes an
`invert` function instead of requiring `trait Invert`.
- Implement `MulAssign` for `NonZeroScalar`.

Things that could still be added:
- Mirror all `BatchInvert` implementations on `Scalar`, I left the ones
taking a reference to a slice out.
- Implement `MulAssign` for `NonZeroScalar` on more combinations.

It might be a tiny bit simpler if I implemented `Default` on
`NonZeroScalar`, but that seemed like a footgun to me.
…o#1893)

Also changes its arg type to accept an `impl Into<ScalarPrimitive<C>>`
)

Extracts macros for writing `From` and `Mul` impls for scalar types.

It would be nice to use these with `ed448-goldilocks` which isn't a
prime order curve, and really these macros work for any elliptic curve,
not just prime order curves (`primeorder` was previously just a
convenient place to put them).

cc @baloo
)

As discussed in RustCrypto#1889. I will add some tests in `elliptic-curves` as
well.

Resolves RustCrypto#1889.

Companion PR: RustCrypto/elliptic-curves#1248.
…ypto#1901)

This PR introduces two changes:
- Remove requirements that were only relevant for oversized `DST`s. Now
these requirements are checked on runtime. While this is unfortunate,
the currently limitations simply was that usage with regular sized
`DST`s incurred limitations that were not necessary.
- Change `len_in_bytes` from `NonZero<usize>` to `NonZero<u16>`. This
isn't a big improvement because the error is just moved from
`expand_msg()` to the various `GroupDigest` methods.

Companion PR: RustCrypto/elliptic-curves#1256.

---
I know I have been refactoring this API over and over again, but I
actually think this is the last of it (apart from
RustCrypto#872 with
`generic_const_exprs`).

But for completions sake I want to mention the following [from the
spec](https://www.rfc-editor.org/rfc/rfc9380.html#section-5.3.1-8):
> It is possible, however, to entirely avoid this overhead by taking
advantage of the fact that Z_pad depends only on H, and not on the
arguments to expand_message_xmd. To do so, first precompute and save the
internal state of H after ingesting Z_pad. Then, when computing b_0,
initialize H using the saved state. Further details are implementation
dependent and are beyond the scope of this document.

In summary, we could cache this part:
```rust
let mut b_0 = HashT::default();
b_0.update(&Array::<u8, HashT::BlockSize>::default());
```
Doing this requires passing `ExpandMsg` state, which would change the
entire API having to add a parameter to every function.

However, as the spec mentions, the cost of not caching it is most likely
negligible. We will see in the future if this shows up in benchmarks and
if it does we can re-evaluate. I don't believe this will be the case
though.

Alternatively, we could add a trait to `digest` which allows users to
construct a hash prefixed with a `BlockSize` full of zeros that has been
computed at compile-time. Which would also require no changes to the API
except binding to this trait.
…1902)

This crate also defines a `Curve` trait, and while that trait is used to
describe an elliptic curve, `group::Curve` is a `Group`, i.e. the
elliptic curve group for a particular curve.

See also: zkcrypto/group#51

To prevent this name clash, this commit re-exports `group::Curve` as
`CurveGroup`.

cc @daxpedda
…RustCrypto#1903)

These methods encapsulate safely casting references for arrays and
slices of `NonIdentity<P>` to array/slice references to the inner `P`
type, and the same for `NonZeroScalar` and its inner `Scalar<C>` type.

Note the choice of method names follows similar ones in `hybrid-array`:

https://docs.rs/hybrid-array/latest/hybrid_array/struct.Array.html#method.cast_slice_to_core
Where these missed in RustCrypto#1902?
If not feel free to close.
Replaced the outdated SIGMA protocol reference link in the ECDH module
documentation with the official IACR archive PDF. The new link points to
the full text of "SIGMA: the 'SIGn-and-MAc' Approach to Authenticated
Diffie-Hellman and its Use in the IKE Protocols" by Hugo Krawczyk
(CRYPTO 2003), ensuring long-term accessibility and citation accuracy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants