vrf_mod/ecvrf/
mod.rs

1//! Module using the OpenSSL library to offer Elliptical Curve Verfiable Random Function (ECVRF) functionality
2//!
3//! ## References
4//!
5//! * [RFC6969](https://www.rfc-editor.org/rfc/rfc6979)
6//! * [VRF-draft-05](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
7//!
8//! ECVRF is a VRF that satisfies the trusted uniqueness, trusted collision resistance and full pseudorandomness
9//!
10//! ## Features
11//!
12//! * Compute VRF proof
13//! * Verify VRF proof
14//!
15use openssl::{
16    bn::{BigNum, BigNumContext},
17    error::ErrorStack,
18    ec::{EcGroup, EcPoint, PointConversionForm},
19    nid::Nid,
20    hash::{Hasher, MessageDigest},
21};
22use thiserror::Error;
23use std::{
24    os::raw::c_ulong,
25};
26use hmac_sha256::HMAC;
27use crate::ECVRF as ECVRF_trait;
28
29pub mod primitives;
30use primitives::{
31    bits2ints,
32    bits2octets,
33    append_zeroes,
34};
35
36// Cipher suite types for different curves
37#[allow(non_camel_case_types)]
38#[derive(Debug)]
39pub enum CipherSuite {
40    // `NIST P-256` with `SHA256`
41    P256_SHA256_TAI,
42    // `SECP256k1` with `SHA256`
43    SECP256k1_SHA256_TAI,
44}
45
46impl CipherSuite {
47    fn suite_string(&self) -> u8 {
48        match *self {
49            CipherSuite::P256_SHA256_TAI => 0x01,
50            CipherSuite::SECP256k1_SHA256_TAI => 0xFE,
51        }
52    }
53}
54
55/// Error types that can be raised
56#[derive(Error, Debug)]
57pub enum Error {
58    /// Error raised from `openssl::error::ErrorStack` with a specific code
59    #[error("Error with code: {code:?}")]
60    CodedError { code: c_ulong },
61    /// `hash_to_point()` function could not find a valid point
62    #[error("Hash to point function could not find a valid point")]
63    HashToPointError,
64    /// Invalid pi length
65    #[error("Proof(pi) length is invalid")]
66    InvalidPiLength,
67    /// Invalid proof
68    #[error("Proof(pi) is invalid")]
69    InvalidProof,
70    /// Unknown error
71    #[error("Unknown error")]
72    Unknown,
73}
74
75impl From<ErrorStack> for Error {
76    /// Transform error from `openssl::error::ErrorStack` to `Error::CodedError` or `Error::Unknown`
77    fn from(error: ErrorStack) -> Self {
78        match error.errors().get(0).map(openssl::error::Error::code) {
79            Some(code) => Error::CodedError { code },
80            _ => Error::Unknown {},
81        }
82    }
83}
84
85// Elliptical Curve VRF
86pub struct ECVRF {
87    // BigNum arithmetic context
88    bn_ctx: BigNumContext,
89    // Ciphersuite identity
90    cipher_suite: CipherSuite,
91    // Hasher structure
92    hasher: Hasher, 
93    // Elliptical Curve group
94    group: EcGroup,
95    // Prime order of `group`
96    order: BigNum,
97    // Length of `order` in octets i.e smallest integer such that 2^(8*qlen)>order
98    qlen: usize,
99    // 2n - length in octets of a field element in bits, rounded up to the nearest even integer
100    n: usize,
101    // Number of points on the elliptical curve divided by `order`
102    cofactor: u8,
103}
104
105impl ECVRF {
106    /// Associated function to initialize a ECVRF structure with an initialized context for the given cipher suite.
107    ///
108    /// # Arguments:
109    ///
110    /// *    `suite`: Identifying ciphersuite
111    ///
112    /// # Returns:
113    ///
114    /// *    a ECVRF struct if successful
115    ///
116    pub fn from_suite(
117        suite: CipherSuite
118    ) -> Result<Self, Error> {
119        // Context for BigNum algebra
120        let mut bn_ctx = BigNumContext::new()?;
121
122        let (group, cofactor) = match suite {
123            CipherSuite::P256_SHA256_TAI => (EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?, 0x01),
124            CipherSuite::SECP256k1_SHA256_TAI => (EcGroup::from_curve_name(Nid::SECP256K1)?, 0x01),
125        };
126
127        let mut p = BigNum::new()?;
128        let mut a = BigNum::new()?;
129        let mut b = BigNum::new()?;
130        group.components_gfp(&mut p, &mut a, &mut b, &mut bn_ctx)?;
131
132        let mut order = BigNum::new()?;
133        group.order(&mut order, &mut bn_ctx)?;
134
135        let n = ((p.num_bits() + (p.num_bits() % 2)) / 2) as usize;
136        let qlen = order.num_bits() as usize;
137
138        // Digest type - `sha256`
139        let hasher = Hasher::new(MessageDigest::sha256())?;
140
141        Ok(
142            ECVRF {
143                bn_ctx,
144                cipher_suite: suite,
145                hasher,
146                group,
147                order,
148                qlen,
149                n,
150                cofactor,
151            }
152        )
153    }
154
155    /// ECVRF_hash_to_curve implementation as specified in [Section 5.4.1.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
156    /// 
157    /// # Arguments
158    ///
159    /// * `public_key`: an Elliptical Curve point
160    /// * `alpha_string`: value to be hashed, an octet string
161    ///
162    /// # Returns:
163    ///
164    /// * a finite EC point in G
165    ///
166    pub fn hash_to_try_and_increment(
167        &mut self,
168        public_key: &EcPoint,
169        alpha_string: &[u8],
170    ) -> Result<EcPoint, Error> {
171        let mut counter = 0..255;
172        let pk_string = public_key.to_bytes(
173            &self.group,
174            PointConversionForm::COMPRESSED,
175            &mut self.bn_ctx,
176        )?;
177        // Hash(suite_string || one_string || pk_string || alpha_string || ctr_string)
178        let mut cipher = [&[self.cipher_suite.suite_string()], &[0x01], pk_string.as_slice(), alpha_string, &[0x00]].concat();
179        let last = cipher.len() - 1;
180        let mut point = counter.find_map(|ctr| {
181            cipher[last] = ctr;
182            self.hasher.update(&cipher).unwrap();
183            let hash_attempt = self.hasher.finish().unwrap().to_vec();
184            let h = self.arbitrary_string_to_point(&hash_attempt);
185            // Check the validity of 'H'
186            match h {
187                Ok(hash_point) => Some(hash_point),
188                _ => None,
189            }
190        });
191        // Set H = cofactor * H
192        if let Some(pt) = point.as_mut() {
193            let mut new_point = EcPoint::new(&self.group)?;
194            new_point.mul(
195                &self.group,
196                pt,
197                BigNum::from_slice(&[self.cofactor])?.as_ref(),
198                &self.bn_ctx,
199            )?;
200            *pt = new_point;
201        };
202        // Convert point or error if no valid point found
203        point.ok_or(Error::HashToPointError)
204    }
205
206    /// Converts an arbitrary string to a point in the curve as specified in [Section 5.5 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
207    /// 
208    /// # Arguments
209    /// 
210    /// * `data`: a 32 octet string to be converted to a point
211    ///
212    /// # returns an `EcPoint` representing the converted point if successful
213    ///
214    pub fn arbitrary_string_to_point(
215        &mut self,
216        data: &[u8],
217    ) -> Result<EcPoint, Error> {
218        let v = [&[0x02], data].concat();
219        let point = EcPoint::from_bytes(&self.group, &v, &mut self.bn_ctx)?;
220        Ok(point)
221    }
222
223    /// Generates a nonce deterministically from the algorithm specified in [Section 3.2 RFC6979](https://tools.ietf.org/html/rfc6979)
224    ///
225    /// # Arguments
226    ///
227    /// * `secret key`: a BigNum representing the secret key.
228    /// * `data`: a slice of octets representing the message
229    ///
230    /// # Returns:
231    ///
232    /// * a `BigNum` representing the nonce.
233    ///
234    pub fn generate_nonce(
235        &mut self,
236        secret_key: &BigNum,
237        data: &[u8]
238    ) -> Result<BigNum, Error> {
239        // h1 = H(m)
240        self.hasher.update(data).unwrap();
241        let h1 = self.hasher.finish().unwrap().to_vec();
242
243        // Initialize `V` and `K`
244        let mut v = [0x01; 32];
245        let mut k = [0x00; 32];
246
247        // private key in the [1, qlen -1] range, should be a multiple of 8; left pad with zeroes (if neccessary)
248        // ints2octets(private_key)
249        let padded_secret_key = append_zeroes(&secret_key.to_vec(), self.qlen);
250
251        // bits2octets(h1)
252        let data = bits2octets(
253            &h1, self.qlen, &self.order, &mut self.bn_ctx,
254        )?;
255        let padded_data = append_zeroes(&data, self.qlen);
256
257        // 2 rounds of hashing as specified
258        for prefix in 0..2u8 {
259            k = HMAC::mac(
260                [
261                    &v[..],
262                    &[prefix],
263                    &padded_secret_key.as_slice(),
264                    &padded_data.as_slice(),
265                ]
266                .concat(),
267                &k,
268            );
269            v = HMAC::mac(&v, &k);
270        }
271
272        // Loop until a valid `BigNum` nonce is found in `V`
273        loop {
274            v = HMAC::mac(&v, &k);
275
276            let nonce = bits2ints(&v, self.qlen)?;
277
278            if nonce > BigNum::from_u32(0)? && nonce < self.order {
279                return Ok(nonce);
280            }
281
282            k = HMAC::mac(
283                [
284                    &v[..],
285                    &[0x00],
286                ]
287                .concat(),
288                &k,
289            );
290            v = HMAC::mac(&v, &k);
291        }
292    }
293
294    /// Hashes a slice of EC points to a `BigNum` integer as specified in [Section 5.4.3 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
295    ///
296    /// # Arguments
297    ///
298    /// * `points`: a slice of points that need to be hashed
299    ///
300    /// # Returns:
301    ///
302    /// * a `BigNum` integer (0 < x < 2^(8n) - 1) representing the hash of points truncated to length `n`, if successful.
303    ///
304    pub fn hash_points(
305        &mut self,
306        points: &[&EcPoint],
307    ) -> Result<BigNum, Error> {
308        let concatenate_points: Result<Vec<u8>, Error> = points.iter().try_fold(
309            vec![self.cipher_suite.suite_string(), 0x02],
310            |mut acc, point| {
311                let sequence: Vec<u8> = point.to_bytes(
312                    &self.group,
313                    PointConversionForm::COMPRESSED,
314                    &mut self.bn_ctx,
315                )?;
316
317                acc.extend(sequence);
318                Ok(acc)
319            }
320        );
321
322        self.hasher.update(&concatenate_points?.as_slice()).unwrap();
323        let mut hash_string = self.hasher.finish().unwrap().to_vec();
324        hash_string.truncate(self.n / 8);
325
326        let result = BigNum::from_slice(hash_string.as_slice())?;
327
328        Ok(result)
329    }
330
331    /// Function to derive public key point given a private key.
332    ///
333    /// # Arguments
334    ///
335    /// * `private_key`: a `BigNum` representing the private key
336    ///
337    /// # Returns:
338    ///
339    /// * an `EcPoint` representing the public key, if successful
340    ///
341    pub fn derive_public_key_point(
342        &mut self, 
343        private_key: &BigNum
344    ) -> Result<EcPoint, Error> {
345        let mut point = EcPoint::new(&self.group)?;
346        // public_key = private_key * generator
347        point.mul_generator(&self.group, private_key, &self.bn_ctx)?;
348        Ok(point)
349    }
350
351    /// Function to derive public key given a private key.
352    ///
353    /// # Arguments
354    ///
355    /// * `private_key`: a slice of octets representing the private key
356    ///
357    /// # Returns:
358    ///
359    /// * an slice of octets representing the public key, if successful
360    ///
361    pub fn derive_public_key(
362        &mut self, 
363        private_key: &[u8]
364    ) -> Result<Vec<u8>, Error> {
365        let private_key_bn = BigNum::from_slice(private_key)?;
366        let point = self.derive_public_key_point(&private_key_bn)?;
367        let public_key_bytes = point.to_bytes(
368            &self.group,
369            PointConversionForm::COMPRESSED,
370            &mut self.bn_ctx,
371        )?;
372        Ok(public_key_bytes)
373    }
374
375    /// Function to decode a proof `pi_string` produced by `EC_prove`, to (`gamma`, `c`, `s`) as specified in
376    /// [Section 5.4.4 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
377    ///
378    /// # Arguments
379    ///
380    /// * `pi_string`: a slice of octets representing the generated proof
381    ///
382    /// # Returns 
383    ///
384    /// * `gamma`: an `EcPoint`
385    /// * `c`: integer between 0 and 2 ^ (8n) - 1
386    /// * `s`: integer between 0 and 2 ^ (8qlen) - 1
387    ///
388    pub fn decode_proof(
389        &mut self,
390        pi_string: &[u8],
391    ) -> Result<(EcPoint, BigNum, BigNum), Error> {
392        let pt_len = if self.qlen % 8 > 0 {
393            self.qlen / 8 + 2
394        } else {
395            self.qlen / 8 + 1
396        };
397        let c_len = if self.n % 8 > 0 {
398            self.n / 8 + 1
399        } else {
400            self.n / 8
401        };
402
403        // Expected length of proof: len(pi_string) == len(gamma) + len(c) + len(s)
404        // len(s) == 2 * len(c), so len(pi) == len(gamma) + len(c) * 3
405        if pi_string.len() != pt_len + c_len * 3 {
406            return Err(Error::InvalidPiLength);
407        }
408
409        let gamma = EcPoint::from_bytes(
410            &self.group,
411            &pi_string[0..pt_len],
412            &mut self.bn_ctx,
413        )?;
414        let c = BigNum::from_slice(&pi_string[pt_len..pt_len + c_len])?;
415        let s = BigNum::from_slice(&pi_string[pt_len + c_len..])?;
416        Ok((gamma, c, s))
417    }
418}
419
420impl ECVRF_trait<&[u8], &[u8]> for ECVRF {
421    type Error = Error;
422
423    /// Generates proof from a private key and a message as specified in [Section 5.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05) 
424    ///
425    /// # Arguments:
426    ///
427    /// *    `pkey`: a private key
428    /// *    `alpha_string`: octet string message represented by a slice
429    ///
430    /// # Returns:
431    ///
432    /// *    if successful, a vector of octets representing the proof `pi_string`
433    ///
434    fn prove(
435        &mut self, 
436        pkey: &[u8], 
437        alpha_string: &[u8],
438    ) -> Result<Vec<u8>, Error> {
439        // 1. Derive public key Y
440        // Y = x * B
441        let private_key = BigNum::from_slice(pkey)?;
442        let public_key = self.derive_public_key_point(&private_key)?;
443
444        // 2. H = hash_to_curve(suite_string, public_key, alpha_string)
445        let h = self.hash_to_try_and_increment(&public_key, alpha_string)?;
446
447        // 3. h_string = point_to_string(H)
448        let h_string = h.to_bytes(
449            &self.group,
450            PointConversionForm::COMPRESSED,
451            &mut self.bn_ctx,
452        )?;
453
454        // 4. Gamma = x * H
455        let mut gamma = EcPoint::new(&self.group)?;
456        gamma.mul(&self.group, &h, &private_key, &self.bn_ctx)?;
457
458        // 5. nonce_generation(private_key, h_string)
459        let nonce = self.generate_nonce(&private_key, &h_string)?;
460
461        // 6. c = hash_points(H, Gamma, k*B, k*H)
462        let mut kb = EcPoint::new(&self.group)?;
463        kb.mul_generator(&self.group, &nonce, &self.bn_ctx)?;
464        let mut kh = EcPoint::new(&self.group)?;
465        kh.mul(&self.group, &h, &nonce, &self.bn_ctx)?;
466        let c = self.hash_points(&[&h, &gamma, &kb, &kh])?;
467
468        // 7. s = (k + c*x) mod q
469        let s = &(&nonce + &(&c * &private_key)) % &self.order;
470
471        // 8. pi_string = point_to_string(gamma) || int_to_string(c, n) || int_to_string(s, qlen)
472        let gamma_string = gamma.to_bytes(
473            &self.group,
474            PointConversionForm::COMPRESSED,
475            &mut self.bn_ctx,
476        )?;
477        let c_string = append_zeroes(&c.to_vec(), self.n);
478        let s_string = append_zeroes(&s.to_vec(), self.qlen);
479        let pi_string = [&gamma_string.as_slice(), c_string.as_slice(), s_string.as_slice()].concat();
480
481        // 9. Output pi_string
482        Ok(pi_string)
483    }
484
485    /// Generates ECVRF hash output from the provided proof
486    ///
487    /// # Arguments:
488    ///
489    /// *    `pi_string`: generated ECVRF proof
490    ///
491    /// # Returns 
492    ///
493    /// * `beta_string`: the ECVRF hash output
494    ///
495    fn proof_to_hash(
496        &mut self, 
497        pi_string: &[u8]
498    ) -> Result<Vec<u8>, Error> {
499        let (gamma, _, _) = self.decode_proof(pi_string)?;
500
501        // cofactor * Gamma
502        let mut gamma_ = EcPoint::new(&self.group)?;
503        gamma_.mul(
504            &self.group,
505            &gamma,
506            BigNum::from_slice(&[self.cofactor])?.as_ref(),
507            &self.bn_ctx,
508        )?;
509
510        let gamma_bytes = gamma_.to_bytes(
511            &self.group,
512            PointConversionForm::COMPRESSED,
513            &mut self.bn_ctx,
514        )?;
515
516        let cipher = [
517            &[self.cipher_suite.suite_string()],
518            &[0x03],
519            gamma_bytes.as_slice(),
520        ].concat();
521
522        self.hasher.update(&cipher).unwrap();
523        let beta_string = self.hasher.finish().unwrap().to_vec();
524
525        Ok(beta_string)
526    }
527
528    /// Verifies the provided VRF proof and computes the VRF hash output
529    ///
530    /// # Arguments:
531    ///
532    /// *    `public_key`: a slice representing the public key in octets
533    /// *    `alpha_string`: VRF hash input, an octet string
534    /// *    `pi_string`: proof to be verified, an octet string
535    /// 
536    /// # Returns:
537    ///
538    /// *    if successful, a vector of octets with the VRF hash output
539    ///
540    fn verify(
541        &mut self, 
542        public_key: &[u8], 
543        alpha_string: &[u8], 
544        pi_string: &[u8]
545    ) -> Result<Vec<u8>, Error> {
546        // 1. Decode proof
547        let (gamma, c, s) = self.decode_proof(pi_string)?;
548
549        let public_key_point = EcPoint::from_bytes(
550            &self.group,
551            public_key,
552            &mut self.bn_ctx,
553        )?;
554
555        // 2. ECVRF_hash_to_curve(suite_string, y, alpha_string)
556        let hash_point = self.hash_to_try_and_increment(
557            &public_key_point,
558            alpha_string,
559        )?;
560
561        // 3. U = s*B - c*Y
562        let mut sb = EcPoint::new(&self.group)?;
563        sb.mul_generator(
564            &self.group,
565            &s,
566            &self.bn_ctx,
567        )?;
568        let mut cy = EcPoint::new(&self.group)?;
569        cy.mul(
570            &self.group,
571            &public_key_point,
572            &c,
573            &self.bn_ctx,
574        )?;
575        cy.invert(&self.group, &self.bn_ctx)?;
576        let mut u_point = EcPoint::new(&self.group)?;
577        u_point.add(
578            &self.group,
579            &sb,
580            &cy,
581            &mut self.bn_ctx,
582        )?;
583
584        // 4. V = s*H - c*Gamma
585        let mut sh = EcPoint::new(&self.group)?;
586        sh.mul(
587            &self.group,
588            &hash_point,
589            &s,
590            &self.bn_ctx,
591        )?;
592        let mut c_gamma = EcPoint::new(&self.group)?;
593        c_gamma.mul(
594            &self.group,
595            &gamma,
596            &c,
597            &self.bn_ctx,
598        )?;
599        c_gamma.invert(&self.group, &self.bn_ctx)?;
600        let mut v_point = EcPoint::new(&self.group)?;
601        v_point.add(
602            &self.group,
603            &sh,
604            &c_gamma,
605            &mut self.bn_ctx,
606        )?;
607
608        // 5. c' = ECVRF_hash_points(H, Gamma, U, V)
609        let derived_c = self.hash_points(
610            &[
611                &hash_point, 
612                &gamma, 
613                &u_point, 
614                &v_point,
615            ]
616        )?;
617
618        // 6. Validity check
619        if c == derived_c {
620            Ok(self.proof_to_hash(pi_string)?)
621        } else {
622            return Err(Error::InvalidProof);
623        }
624    }
625}
626
627#[cfg(test)]
628mod tests {
629    use super::*;
630
631    /// Test vector for `P256-SHA256-TAI` cipher suite as specified in
632    /// [Section A.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
633    ///
634    #[test]
635    fn test_hash_to_try_and_increment_1() {
636        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
637
638        // hex encoded -> 'sample'
639        let alpha = hex::decode("73616d706c65").unwrap();
640
641        let hex_public_key = hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6").unwrap();
642        let public_key = EcPoint::from_bytes(
643            &ecvrf.group, &hex_public_key, &mut ecvrf.bn_ctx
644        ).unwrap();
645
646        let result = ecvrf.hash_to_try_and_increment(&public_key, &alpha).unwrap();
647        let result_bytes = result.to_bytes(
648            &ecvrf.group,
649            PointConversionForm::COMPRESSED,
650            &mut ecvrf.bn_ctx,
651        ).unwrap();
652
653        let expected_result = hex::decode("02e2e1ab1b9f5a8a68fa4aad597e7493095648d3473b213bba120fe42d1a595f3e").unwrap();
654
655        assert_eq!(result_bytes, expected_result);
656    }
657
658    /// Test vector for `P256-SHA256-TAI` cipher suite as specified in
659    /// [Section A.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
660    ///
661    #[test]
662    fn test_hash_to_try_and_increment_2() {
663        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
664
665        // hex encoded -> 'test'
666        let alpha = hex::decode("74657374").unwrap();
667
668        let hex_public_key = hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6").unwrap();
669        let public_key = EcPoint::from_bytes(
670            &ecvrf.group, &hex_public_key, &mut ecvrf.bn_ctx
671        ).unwrap();
672
673        let result = ecvrf.hash_to_try_and_increment(&public_key, &alpha).unwrap();
674        let result_bytes = result.to_bytes(
675            &ecvrf.group,
676            PointConversionForm::COMPRESSED,
677            &mut ecvrf.bn_ctx,
678        ).unwrap();
679
680        let expected_result = hex::decode("02ca565721155f9fd596f1c529c7af15dad671ab30c76713889e3d45b767ff6433").unwrap();
681
682        assert_eq!(result_bytes, expected_result);
683    }
684
685    /// Test vector for `P256-SHA256-TAI` cipher suite as specified in
686    /// [Section A.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
687    ///
688    #[test]
689    fn test_hash_to_try_and_increment_3() {
690        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
691
692        // hex encoded -> 'Example of ECDSA with ansip256r1 and SHA-256'
693        let alpha = hex::decode("4578616d706c65206f66204543445341207769746820616e736970323536723120616e64205348412d323536").unwrap();
694
695        let hex_public_key = hex::decode("03596375e6ce57e0f20294fc46bdfcfd19a39f8161b58695b3ec5b3d16427c274d").unwrap();
696        let public_key = EcPoint::from_bytes(
697            &ecvrf.group, &hex_public_key, &mut ecvrf.bn_ctx
698        ).unwrap();
699
700        let result = ecvrf.hash_to_try_and_increment(&public_key, &alpha).unwrap();
701        let result_bytes = result.to_bytes(
702            &ecvrf.group,
703            PointConversionForm::COMPRESSED,
704            &mut ecvrf.bn_ctx,
705        ).unwrap();
706
707        let expected_result = hex::decode("02141e41d4d55802b0e3adaba114c81137d95fd3869b6b385d4487b1130126648d").unwrap();
708
709        assert_eq!(result_bytes, expected_result);
710    }
711
712    /// Test vector for `P-256` curve with `SHA-256` as specified in
713    /// [Section A.2.5 \[RFC6979\]](https://tools.ietf.org/html/rfc6979)
714    ///
715    #[test]
716    fn test_generate_nonce_p256_1() {
717        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
718
719        let mut ord = BigNum::new().unwrap();
720        ecvrf.group.order(&mut ord, &mut ecvrf.bn_ctx).unwrap();
721
722        let hex_private_key = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap();
723        let private_key = BigNum::from_slice(&hex_private_key).unwrap();
724
725        // hex encoded -> 'sample'
726        let alpha = hex::decode("73616d706c65").unwrap();
727
728        let result_nonce = ecvrf.generate_nonce(&private_key, &alpha).unwrap();
729
730        let expected_result = hex::decode("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60").unwrap();
731        
732        assert_eq!(result_nonce.to_vec(), expected_result);
733    }
734
735    /// Test vector for `P-256` curve with `SHA-256` as specified in
736    /// [Section A.2.5 \[RFC6979\]](https://tools.ietf.org/html/rfc6979)
737    ///
738    #[test]
739    fn test_generate_nonce_p256_2() {
740        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
741
742        let mut ord = BigNum::new().unwrap();
743        ecvrf.group.order(&mut ord, &mut ecvrf.bn_ctx).unwrap();
744
745        let hex_private_key = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap();
746        let private_key = BigNum::from_slice(&hex_private_key).unwrap();
747
748        // hex encoded -> 'test'
749        let alpha = hex::decode("74657374").unwrap();
750
751        let result_nonce = ecvrf.generate_nonce(&private_key, &alpha).unwrap();
752
753        let expected_result = hex::decode("D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0").unwrap();
754        
755        assert_eq!(result_nonce.to_vec(), expected_result);
756    }
757
758    /// Test vector for hash points with `P256-SHA256-TAI` cipher suite
759    /// [Section A.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
760    ///
761    #[test]
762    fn test_hash_points() {
763        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
764
765        // Test data
766        let hash_hex = hex::decode("02e2e1ab1b9f5a8a68fa4aad597e7493095648d3473b213bba120fe42d1a595f3e").unwrap();
767        let pi_hex = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap();
768        
769        // Compute all required points (gamma, u, v)
770        let hash_point = EcPoint::from_bytes(&ecvrf.group, &hash_hex, &mut ecvrf.bn_ctx).unwrap();
771        let mut gamma_hex = pi_hex.clone();
772        let c_s_hex = gamma_hex.split_off(33);
773        let gamma_point = EcPoint::from_bytes(&ecvrf.group, &gamma_hex, &mut ecvrf.bn_ctx).unwrap();
774        let u_hex = hex::decode("030286d82c95d54feef4d39c000f8659a5ce00a5f71d3a888bd1b8e8bf07449a50").unwrap();
775        let u_point = EcPoint::from_bytes(&ecvrf.group, &u_hex, &mut ecvrf.bn_ctx).unwrap();
776        let v_hex = hex::decode("03e4258b4a5f772ed29830050712fa09ea8840715493f78e5aaaf7b27248efc216").unwrap();
777        let v_point = EcPoint::from_bytes(&ecvrf.group, &v_hex, &mut ecvrf.bn_ctx).unwrap();
778
779        let computed_c = ecvrf.hash_points(
780            &[
781                &hash_point, 
782                &gamma_point, 
783                &u_point, 
784                &v_point
785            ]
786        ).unwrap();
787
788        let mut expected_c = c_s_hex.clone();
789        
790        expected_c.truncate(16);
791        
792        assert_eq!(computed_c.to_vec(), expected_c);
793    }
794
795    /// Test decode_proof vector for `P256-SHA256-TAI` cipher suite as specified in
796    /// [Section A.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
797    ///
798    #[test]
799    fn test_decode_proof() {
800        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
801
802        let pi_hex = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap();
803        let (derived_gamma, derived_c, _) = ecvrf.decode_proof(&pi_hex).unwrap();
804
805        // Expected values
806        let mut gamma_hex = pi_hex.clone();
807        let c_s_hex = gamma_hex.split_off(33);
808        let mut c_hex = c_s_hex.clone();
809        c_hex.truncate(16);
810        let expected_gamma = EcPoint::from_bytes(&ecvrf.group, &gamma_hex, &mut ecvrf.bn_ctx).unwrap();
811        let expected_c = BigNum::from_slice(c_hex.as_slice()).unwrap();
812
813        assert!(derived_c.eq(&expected_c));
814        assert!(expected_gamma.eq(&ecvrf.group, &derived_gamma, &mut ecvrf.bn_ctx).unwrap());
815    }
816
817    /// Test prove for `P256-SHA256-TAI` cipher suite
818    /// 
819    #[test]
820    fn test_prove_p256_sha256_tai() {
821        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
822        // private key
823        let x = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap();
824        
825        let alpha = hex::decode("73616d706c65").unwrap();
826
827        let pi = ecvrf.prove(&x, &alpha).unwrap();
828        let expected_pi = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap();
829        
830        assert_eq!(pi, expected_pi);
831    }
832
833    /// Test prove for `SECP256K1-SHA256-TAI` cipher suite
834    /// 
835    #[test]
836    fn test_prove_secp256k1_sha256_tai() {
837        let mut ecvrf = ECVRF::from_suite(CipherSuite::SECP256k1_SHA256_TAI).unwrap();
838        // private key
839        let x = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap();
840        // hex -> 'sample'
841        let alpha = hex::decode("73616d706c65").unwrap();
842
843        let pi = ecvrf.prove(&x, &alpha).unwrap();
844        
845        let expected_pi = hex::decode("031f4dbca087a1972d04a07a779b7df1caa99e0f5db2aa21f3aecc4f9e10e85d08748c9fbe6b95d17359707bfb8e8ab0c93ba0c515333adcb8b64f372c535e115ccf66ebf5abe6fadb01b5efb37c0a0ec9").unwrap();
846        
847        assert_eq!(pi, expected_pi);
848    }
849
850    /// Test verify for `P256-SHA256-TAI` cipher suite as specified in
851    /// [Section A.1 \[VRF-draft-05\]](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-05)
852    /// 
853    #[test]
854    fn test_verify_p256_sha256_tai() {
855        let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
856        // Public Key
857        let public_key = hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6").unwrap();
858        // hex -> 'sample'
859        let alpha = hex::decode("73616d706c65").unwrap();
860        // ecvrf proof
861        let pi = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap();
862
863        let beta = ecvrf.verify(&public_key, &alpha, &pi).unwrap();
864        let expected_beta = hex::decode("59ca3801ad3e981a88e36880a3aee1df38a0472d5be52d6e39663ea0314e594c").unwrap();
865        
866        assert_eq!(beta, expected_beta);
867    }
868
869    /// Test verify for `SECP256K1-SHA256-TAI` cipher suite
870    /// 
871    #[test]
872    fn test_verify_secp256k1_sha256_tai() {
873        let mut ecvrf = ECVRF::from_suite(CipherSuite::SECP256k1_SHA256_TAI).unwrap();
874        // Public Key
875        let public_key = hex::decode("032c8c31fc9f990c6b55e3865a184a4ce50e09481f2eaeb3e60ec1cea13a6ae645").unwrap();
876        // hex -> 'sample'
877        let alpha = hex::decode("73616d706c65").unwrap();
878        // ecvrf proof
879        let pi = hex::decode("031f4dbca087a1972d04a07a779b7df1caa99e0f5db2aa21f3aecc4f9e10e85d0814faa89697b482daa377fb6b4a8b0191a65d34a6d90a8a2461e5db9205d4cf0bb4b2c31b5ef6997a585a9f1a72517b6f").unwrap();
880
881        let beta = ecvrf.verify(&public_key, &alpha, &pi).unwrap();
882        let expected_beta = hex::decode("612065e309e937ef46c2ef04d5886b9c6efd2991ac484ec64a9b014366fc5d81").unwrap();
883        
884        assert_eq!(beta, expected_beta);
885    }
886}