1use 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#[allow(non_camel_case_types)]
38#[derive(Debug)]
39pub enum CipherSuite {
40 P256_SHA256_TAI,
42 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#[derive(Error, Debug)]
57pub enum Error {
58 #[error("Error with code: {code:?}")]
60 CodedError { code: c_ulong },
61 #[error("Hash to point function could not find a valid point")]
63 HashToPointError,
64 #[error("Proof(pi) length is invalid")]
66 InvalidPiLength,
67 #[error("Proof(pi) is invalid")]
69 InvalidProof,
70 #[error("Unknown error")]
72 Unknown,
73}
74
75impl From<ErrorStack> for Error {
76 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
85pub struct ECVRF {
87 bn_ctx: BigNumContext,
89 cipher_suite: CipherSuite,
91 hasher: Hasher,
93 group: EcGroup,
95 order: BigNum,
97 qlen: usize,
99 n: usize,
101 cofactor: u8,
103}
104
105impl ECVRF {
106 pub fn from_suite(
117 suite: CipherSuite
118 ) -> Result<Self, Error> {
119 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 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 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 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 match h {
187 Ok(hash_point) => Some(hash_point),
188 _ => None,
189 }
190 });
191 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 point.ok_or(Error::HashToPointError)
204 }
205
206 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 pub fn generate_nonce(
235 &mut self,
236 secret_key: &BigNum,
237 data: &[u8]
238 ) -> Result<BigNum, Error> {
239 self.hasher.update(data).unwrap();
241 let h1 = self.hasher.finish().unwrap().to_vec();
242
243 let mut v = [0x01; 32];
245 let mut k = [0x00; 32];
246
247 let padded_secret_key = append_zeroes(&secret_key.to_vec(), self.qlen);
250
251 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 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 {
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 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 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 point.mul_generator(&self.group, private_key, &self.bn_ctx)?;
348 Ok(point)
349 }
350
351 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 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 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 fn prove(
435 &mut self,
436 pkey: &[u8],
437 alpha_string: &[u8],
438 ) -> Result<Vec<u8>, Error> {
439 let private_key = BigNum::from_slice(pkey)?;
442 let public_key = self.derive_public_key_point(&private_key)?;
443
444 let h = self.hash_to_try_and_increment(&public_key, alpha_string)?;
446
447 let h_string = h.to_bytes(
449 &self.group,
450 PointConversionForm::COMPRESSED,
451 &mut self.bn_ctx,
452 )?;
453
454 let mut gamma = EcPoint::new(&self.group)?;
456 gamma.mul(&self.group, &h, &private_key, &self.bn_ctx)?;
457
458 let nonce = self.generate_nonce(&private_key, &h_string)?;
460
461 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 let s = &(&nonce + &(&c * &private_key)) % &self.order;
470
471 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 Ok(pi_string)
483 }
484
485 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 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 fn verify(
541 &mut self,
542 public_key: &[u8],
543 alpha_string: &[u8],
544 pi_string: &[u8]
545 ) -> Result<Vec<u8>, Error> {
546 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 let hash_point = self.hash_to_try_and_increment(
557 &public_key_point,
558 alpha_string,
559 )?;
560
561 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 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 let derived_c = self.hash_points(
610 &[
611 &hash_point,
612 &gamma,
613 &u_point,
614 &v_point,
615 ]
616 )?;
617
618 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]
635 fn test_hash_to_try_and_increment_1() {
636 let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
637
638 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]
662 fn test_hash_to_try_and_increment_2() {
663 let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
664
665 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]
689 fn test_hash_to_try_and_increment_3() {
690 let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
691
692 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]
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 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]
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 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]
762 fn test_hash_points() {
763 let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
764
765 let hash_hex = hex::decode("02e2e1ab1b9f5a8a68fa4aad597e7493095648d3473b213bba120fe42d1a595f3e").unwrap();
767 let pi_hex = hex::decode("029bdca4cc39e57d97e2f42f88bcf0ecb1120fb67eb408a856050dbfbcbf57c524347fc46ccd87843ec0a9fdc090a407c6fbae8ac1480e240c58854897eabbc3a7bb61b201059f89186e7175af796d65e7").unwrap();
768
769 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]
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 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]
820 fn test_prove_p256_sha256_tai() {
821 let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
822 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]
836 fn test_prove_secp256k1_sha256_tai() {
837 let mut ecvrf = ECVRF::from_suite(CipherSuite::SECP256k1_SHA256_TAI).unwrap();
838 let x = hex::decode("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").unwrap();
840 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]
854 fn test_verify_p256_sha256_tai() {
855 let mut ecvrf = ECVRF::from_suite(CipherSuite::P256_SHA256_TAI).unwrap();
856 let public_key = hex::decode("0360fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6").unwrap();
858 let alpha = hex::decode("73616d706c65").unwrap();
860 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]
872 fn test_verify_secp256k1_sha256_tai() {
873 let mut ecvrf = ECVRF::from_suite(CipherSuite::SECP256k1_SHA256_TAI).unwrap();
874 let public_key = hex::decode("032c8c31fc9f990c6b55e3865a184a4ce50e09481f2eaeb3e60ec1cea13a6ae645").unwrap();
876 let alpha = hex::decode("73616d706c65").unwrap();
878 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}