From 6cd56c1aa41f6710936bb2d0a34ad44c5fbd0742 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Fri, 27 Feb 2026 19:55:40 +0100 Subject: [PATCH] Add advisory for `vrf_fun` --- crates/vrf_fun/RUSTSEC-0000-0000.md | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 crates/vrf_fun/RUSTSEC-0000-0000.md diff --git a/crates/vrf_fun/RUSTSEC-0000-0000.md b/crates/vrf_fun/RUSTSEC-0000-0000.md new file mode 100644 index 0000000000..d22f131e7d --- /dev/null +++ b/crates/vrf_fun/RUSTSEC-0000-0000.md @@ -0,0 +1,43 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "vrf_fun" +date = "2026-02-27" +url = "https://github.com/LLFourn/secp256kfun/pull/244" +categories = ["crypto-failure"] +keywords = ["nonce-reuse", "key-recovery", "vrf"] +license = "CC-BY-4.0" + +[affected.functions] +"vrf_fun::Vrf::prove" = ["= 0.12.0"] +"vrf_fun::rfc9381::tai::prove" = ["= 0.12.0"] +"vrf_fun::rfc9381::sswu::prove" = ["= 0.12.0"] +"vrf_fun::rfc9381::Rfc9381Transcript::gen_rng" = ["= 0.12.0"] + +[versions] +patched = [] +``` + +# RFC 9381 VRF nonce reuse allows secret key recovery + +The `ProverTranscript` implementation for `Rfc9381Transcript` computed the +nonce seed from a fresh hasher rather than the transcript state. The nonce +depended only on a fixed domain separator and the secret key, not on the VRF +input: + +``` +nonce = H("vrf-nonce-gen" || secret_key) +``` + +Because the nonce was identical across all proofs made with the same key, +any two VRF proofs on different inputs leaked the secret key via: + +``` +x = (s1 - s2) / (c1 - c2) +``` + +where `(c1, s1)` and `(c2, s2)` are the challenge-response pairs from the +two proofs. + +The fix incorporates the transcript state (which includes the public key, +hash-to-curve point, and gamma) into the nonce derivation.