1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
1819//! <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-04#section-5>
20#![allow(non_snake_case)]
2122#[cfg(feature = "async")]
23use darkfi_serial::async_trait;
24use darkfi_serial::{SerialDecodable, SerialEncodable};
25use halo2_gadgets::ecc::chip::FixedPoint;
26use pasta_curves::{
27 arithmetic::CurveExt,
28 group::{
29 ff::{FromUniformBytes, PrimeField},
30 GroupEncoding,
31 },
32 pallas,
33};
3435use super::{
36 constants::NullifierK,
37 util::{fp_mod_fv, hash_to_scalar},
38 PublicKey, SecretKey,
39};
4041/// Prefix domain used for `hash_to_curve` calls
42const VRF_DOMAIN: &str = "DarkFi_ECVRF";
4344/// VRF Proof
45#[derive(Copy, Clone, Debug, SerialEncodable, SerialDecodable)]
46pub struct VrfProof {
47 gamma: pallas::Point,
48 c: blake3::Hash,
49 s: pallas::Scalar,
50}
5152impl VrfProof {
53/// Execute the VRF function and create a proof given a `SecretKey`
54 /// and a seed input `alpha_string`.
55pub fn prove(x: SecretKey, alpha_string: &[u8]) -> Self {
56let Y = PublicKey::from_secret(x);
5758let mut message = vec![];
59 message.extend_from_slice(&Y.to_bytes());
60 message.extend_from_slice(alpha_string);
61let H = pallas::Point::hash_to_curve(VRF_DOMAIN)(&message);
6263let gamma = H * fp_mod_fv(x.inner());
6465// Generate a determinnistic nonce
66let k = hash_to_scalar(VRF_DOMAIN.as_bytes(), &[&x.inner().to_repr(), &H.to_bytes()]);
6768let mut hasher = blake3::Hasher::new();
69 hasher.update(&H.to_bytes());
70 hasher.update(&gamma.to_bytes());
71// The paper's B generator we use is NullifierK as that's used for
72 // SecretKey -> PublicKey derivation.
73hasher.update(&(NullifierK.generator() * k).to_bytes());
74 hasher.update(&(H * k).to_bytes());
75let c = hasher.finalize();
7677let mut c_scalar = [0u8; 64];
78 c_scalar[..blake3::OUT_LEN].copy_from_slice(c.as_bytes());
79let c_scalar = pallas::Scalar::from_uniform_bytes(&c_scalar);
8081let s = k + c_scalar * fp_mod_fv(x.inner());
8283Self { gamma, c, s }
84 }
8586/// Verify a `VrfProof` given a `Publickey` and a seed input `alpha_string`.
87pub fn verify(&self, Y: PublicKey, alpha_string: &[u8]) -> bool {
88let mut message = vec![];
89 message.extend_from_slice(&Y.to_bytes());
90 message.extend_from_slice(alpha_string);
91let H = pallas::Point::hash_to_curve(VRF_DOMAIN)(&message);
9293let mut c = [0u8; 64];
94 c[..blake3::OUT_LEN].copy_from_slice(self.c.as_bytes());
95let c_scalar = pallas::Scalar::from_uniform_bytes(&c);
9697let U = NullifierK.generator() * self.s - Y.inner() * c_scalar;
98let V = H * self.s - self.gamma * c_scalar;
99100let mut hasher = blake3::Hasher::new();
101 hasher.update(&H.to_bytes());
102 hasher.update(&self.gamma.to_bytes());
103 hasher.update(&U.to_bytes());
104 hasher.update(&V.to_bytes());
105106 hasher.finalize() == self.c
107 }
108109/// Returns the VRF output.
110 /// **It is necessary** to do `VrfProof::verify` first in order to trust this function's output.
111 /// TODO: FIXME: We should enforce verification before getting the output.
112pub fn hash_output(&self) -> blake3::Hash {
113let mut hasher = blake3::Hasher::new();
114 hasher.update(VRF_DOMAIN.as_bytes());
115 hasher.update(&[0x03]);
116 hasher.update(&self.gamma.to_bytes());
117 hasher.finalize()
118 }
119}
120121#[cfg(test)]
122mod tests {
123use super::*;
124use rand::rngs::OsRng;
125126#[test]
127fn ecvrf() {
128// VRF secret key
129let secret_key = SecretKey::random(&mut OsRng);
130// VRF public key
131let public_key = PublicKey::from_secret(secret_key);
132// VRF input
133let input = [0xde, 0xad, 0xbe, 0xef];
134135let proof = VrfProof::prove(secret_key, &input);
136assert!(proof.verify(public_key, &input));
137138// Forged public key
139let forged_public_key = PublicKey::from_secret(SecretKey::random(&mut OsRng));
140assert!(!proof.verify(forged_public_key, &input));
141142// Forged input
143let forged_input = [0xde, 0xad, 0xba, 0xbe];
144assert!(!proof.verify(public_key, &forged_input));
145 }
146}