libecvrf/
ecvrf.rs

1use crate::{
2    error,
3    hash::{hash_points, hash_to_curve},
4};
5use k256::{
6    elliptic_curve::{
7        rand_core::OsRng,
8        sec1::{FromEncodedPoint, ToEncodedPoint},
9        subtle::ConditionallyNegatable,
10        Field, PrimeField,
11    },
12    AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, PublicKey, Scalar, SecretKey,
13};
14use serde::{Deserialize, Serialize};
15use tiny_keccak::{Hasher, Keccak};
16
17/// EC-VRF proof
18#[derive(Clone)]
19#[derive(Debug)]
20#[derive(Eq, PartialEq)]
21#[derive(Serialize, Deserialize)]
22pub struct ECVRFProof {
23    /// gamma
24    pub gamma: AffinePoint,
25    /// c
26    pub c: Scalar,
27    /// s
28    pub s: Scalar,
29    /// y is the result
30    pub y: Scalar,
31    /// Public key
32    pub pk: PublicKey,
33}
34
35/// ECVRF
36pub struct ECVRF {
37    secret_key: SecretKey,
38    public_key: PublicKey,
39}
40
41impl ECVRF {
42    /// Create new instance of ECVRF from a secret key
43    pub fn new(secret_key: SecretKey) -> Self {
44        let public_key = PublicKey::from_secret_scalar(&secret_key.to_nonzero_scalar());
45        ECVRF {
46            secret_key,
47            public_key,
48        }
49    }
50
51    /// Ordinary prover
52    pub fn prove(&self, alpha: &[u8]) -> Result<ECVRFProof, error::Error> {
53        let alpha = Self::generate_alpha(alpha);
54
55        let pub_affine: AffinePoint = self.public_key.into();
56        let secret_key: Scalar = *self.secret_key.to_nonzero_scalar();
57
58        // Hash to a point on curve
59        let h = hash_to_curve(&alpha, Some(&pub_affine));
60
61        // gamma = H * secret_key
62        let gamma = h * secret_key;
63
64        // k = random()
65        // We need to make sure that k < GROUP_ORDER
66        let k = Scalar::random(&mut OsRng);
67
68        // Calculate k * G <=> u
69        let kg = ProjectivePoint::GENERATOR * k;
70
71        // Calculate k * H <=> v
72        let kh = h * k;
73
74        // c = ECVRF_hash_points(G, H, public_key, gamma, k * G, k * H)
75        let c = hash_points(
76            &AffinePoint::GENERATOR,
77            &h,
78            &pub_affine,
79            &gamma.to_affine(),
80            &kg.to_affine(),
81            &kh.to_affine(),
82        );
83
84        // s = (k - c * secret_key) mod p
85        let mut neg_c = c;
86        neg_c.conditional_negate(1.into());
87        let s = k + neg_c * secret_key;
88
89        // y = keccak256(gama.encode())
90        let mut output = [0u8; 32];
91        let mut hasher = Keccak::v256();
92        hasher.update(gamma.to_encoded_point(true).as_bytes());
93        hasher.finalize(&mut output);
94        let bytes = FieldBytes::from_slice(&output);
95        let y = Scalar::from_repr(*bytes).unwrap();
96
97        Ok(ECVRFProof {
98            gamma: gamma.to_affine(),
99            c,
100            s,
101            y,
102            pk: self.public_key,
103        })
104    }
105
106    /// Verify proof
107    pub fn verify(alpha: &[u8], vrf_proof: &ECVRFProof, public_key: &[u8]) -> bool {
108        let alpha = Self::generate_alpha(alpha);
109        let pub_encoded = EncodedPoint::from_bytes(public_key).unwrap();
110        let pub_point = ProjectivePoint::from_encoded_point(&pub_encoded).unwrap();
111        let u = pub_point * vrf_proof.c + ProjectivePoint::GENERATOR * vrf_proof.s;
112
113        let h = hash_to_curve(&alpha, Some(&pub_point.to_affine()));
114
115        // Gamma witness: c * gamma
116        let witness_gamma = ProjectivePoint::from(vrf_proof.gamma) * vrf_proof.c;
117
118        // Hash witness: s * H
119        let witness_hash = ProjectivePoint::from(h) * vrf_proof.s;
120
121        // V = c * gamma + s * H
122        let v = witness_gamma + witness_hash;
123
124        // c_prime = ECVRF_hash_points(G, H, pk, gamma, U, V)
125        let computed_c = hash_points(
126            &AffinePoint::GENERATOR,
127            &h,
128            &pub_point.to_affine(),
129            &vrf_proof.gamma,
130            &u.to_affine(),
131            &v.to_affine(),
132        );
133
134        // y = keccak256(gamma.encode())
135        let mut output = [0u8; 32];
136        let mut hasher = Keccak::v256();
137        hasher.update(vrf_proof.gamma.to_encoded_point(true).as_bytes());
138        hasher.finalize(&mut output);
139
140        let bytes = FieldBytes::from_slice(&output);
141        let computed_y = Scalar::from_repr(*bytes).unwrap();
142
143        computed_c == vrf_proof.c && computed_y == vrf_proof.y
144    }
145
146    fn generate_alpha(alpha: &[u8]) -> Scalar {
147        let mut output = [0u8; 32];
148        let mut hasher = Keccak::v256();
149        hasher.update(alpha);
150        hasher.finalize(&mut output);
151
152        let bytes = FieldBytes::from_slice(&output);
153        Scalar::from_repr(*bytes).unwrap()
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use k256::{
160        elliptic_curve::{rand_core::OsRng, sec1::ToEncodedPoint},
161        PublicKey, SecretKey,
162    };
163
164    use crate::ECVRF;
165
166    const TEST_ALPHA: &[u8] = b"test alphaddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
167
168    #[test]
169    fn success_proof_and_verify() {
170        let secret_key = SecretKey::random(&mut OsRng);
171        let public_key = PublicKey::from_secret_scalar(&secret_key.to_nonzero_scalar());
172
173        let ecvrf = ECVRF::new(secret_key);
174        let proof = ecvrf.prove(TEST_ALPHA).unwrap();
175        assert_eq!(proof.pk, public_key);
176
177        let result = ECVRF::verify(
178            TEST_ALPHA,
179            &proof,
180            public_key.to_encoded_point(true).as_bytes(),
181        );
182        assert!(result);
183    }
184}