1use crypto_bigint::{
4 NonZero,
5 U256,
6 U512,
7};
8use zeroize::{
9 Zeroize,
10 ZeroizeOnDrop,
11};
12
13use crate::error::PrfError;
14use crate::field::{
15 fp_add,
16 fp_pow,
17 to_monty,
18};
19use crate::keys::{
20 validate_key_u256,
21 validate_key_u512,
22};
23use crate::params::{
24 GoldPrfParams256,
25 GoldPrfParams512,
26};
27
28#[derive(Clone, Zeroize, ZeroizeOnDrop)]
35pub struct GoldKey256 {
36 k: U256,
37}
38
39#[derive(Clone, Zeroize, ZeroizeOnDrop)]
43pub struct GoldKey512 {
44 k: U512,
45}
46
47impl GoldKey256 {
48 pub fn from_uint(k: U256, params: &GoldPrfParams256) -> Result<Self, PrfError> {
49 validate_key_u256(&k, ¶ms.p)?;
50 Ok(Self { k })
51 }
52
53 pub fn derive_from_seed(seed: &[u8], params: &GoldPrfParams256) -> Result<Self, PrfError> {
54 let k = crate::shake::shake256_to_field_u256(seed, b"lib-q-prf/gold-k256/v1", ¶ms.p)?;
55 Self::from_uint(k, params)
56 }
57
58 #[inline]
60 #[must_use]
61 pub fn as_uint(&self) -> &U256 {
62 &self.k
63 }
64}
65
66impl GoldKey512 {
67 pub fn from_uint(k: U512, params: &GoldPrfParams512) -> Result<Self, PrfError> {
68 validate_key_u512(&k, ¶ms.p)?;
69 Ok(Self { k })
70 }
71
72 pub fn derive_from_seed(seed: &[u8], params: &GoldPrfParams512) -> Result<Self, PrfError> {
73 let k = crate::shake::shake256_to_field_u512(seed, b"lib-q-prf/gold-k512/v1", ¶ms.p)?;
74 Self::from_uint(k, params)
75 }
76
77 #[inline]
79 #[must_use]
80 pub fn as_uint(&self) -> &U512 {
81 &self.k
82 }
83}
84
85pub fn gold_prf_u256(
90 key: &GoldKey256,
91 x: &U256,
92 params: &GoldPrfParams256,
93) -> Result<[u8; 32], PrfError> {
94 let nz = NonZero::new(params.p)
95 .into_option()
96 .ok_or(PrfError::InvalidParam)?;
97 let xr = x.rem_vartime(&nz);
98 let xm = to_monty(&xr, ¶ms.monty);
99 let km = to_monty(&key.k, ¶ms.monty);
100 let sum = fp_add(xm, &km);
101 let out_m = fp_pow(&sum, ¶ms.g);
102 Ok(out_m.retrieve().to_le_bytes().into())
103}
104
105pub fn gold_prf_u512(
109 key: &GoldKey512,
110 x: &U512,
111 params: &GoldPrfParams512,
112) -> Result<[u8; 64], PrfError> {
113 let nz = NonZero::new(params.p)
114 .into_option()
115 .ok_or(PrfError::InvalidParam)?;
116 let xr = x.rem_vartime(&nz);
117 let xm = to_monty(&xr, ¶ms.monty);
118 let km = to_monty(&key.k, ¶ms.monty);
119 let sum = fp_add(xm, &km);
120 let out_m = fp_pow(&sum, ¶ms.g);
121 Ok(out_m.retrieve().to_le_bytes().into())
122}