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 uint_ct_eq_zero,
19};
20use crate::keys::{
21 validate_key_u256,
22 validate_key_u512,
23};
24use crate::params::{
25 GoldPrfParams256,
26 GoldPrfParams512,
27};
28
29#[derive(Clone, Zeroize, ZeroizeOnDrop)]
36pub struct GoldKey256 {
37 k: U256,
38}
39
40#[derive(Clone, Zeroize, ZeroizeOnDrop)]
44pub struct GoldKey512 {
45 k: U512,
46}
47
48impl GoldKey256 {
49 pub fn from_uint(k: U256, params: &GoldPrfParams256) -> Result<Self, PrfError> {
50 validate_key_u256(&k, ¶ms.p)?;
51 Ok(Self { k })
52 }
53
54 pub fn derive_from_seed(seed: &[u8], params: &GoldPrfParams256) -> Result<Self, PrfError> {
55 let k = crate::shake::shake256_to_field_u256(seed, b"lib-q-prf/gold-k256/v1", ¶ms.p)?;
56 Self::from_uint(k, params)
57 }
58
59 #[inline]
61 #[must_use]
62 pub fn as_uint(&self) -> &U256 {
63 &self.k
64 }
65}
66
67impl GoldKey512 {
68 pub fn from_uint(k: U512, params: &GoldPrfParams512) -> Result<Self, PrfError> {
69 validate_key_u512(&k, ¶ms.p)?;
70 Ok(Self { k })
71 }
72
73 pub fn derive_from_seed(seed: &[u8], params: &GoldPrfParams512) -> Result<Self, PrfError> {
74 let k = crate::shake::shake256_to_field_u512(seed, b"lib-q-prf/gold-k512/v1", ¶ms.p)?;
75 Self::from_uint(k, params)
76 }
77
78 #[inline]
80 #[must_use]
81 pub fn as_uint(&self) -> &U512 {
82 &self.k
83 }
84}
85
86pub fn gold_prf_u256(
91 key: &GoldKey256,
92 x: &U256,
93 params: &GoldPrfParams256,
94) -> Result<[u8; 32], PrfError> {
95 let nz = NonZero::new(params.p)
96 .into_option()
97 .ok_or(PrfError::InvalidParam)?;
98 let xr = x.rem_vartime(&nz);
99 let xm = to_monty(&xr, ¶ms.monty);
100 let km = to_monty(&key.k, ¶ms.monty);
101 let sum = fp_add(xm, &km);
102 if bool::from(uint_ct_eq_zero(&sum.retrieve())) {
105 return Err(PrfError::ZeroInput);
106 }
107 let out_m = fp_pow(&sum, ¶ms.g);
108 Ok(out_m.retrieve().to_le_bytes().into())
109}
110
111pub fn gold_prf_u512(
115 key: &GoldKey512,
116 x: &U512,
117 params: &GoldPrfParams512,
118) -> Result<[u8; 64], PrfError> {
119 let nz = NonZero::new(params.p)
120 .into_option()
121 .ok_or(PrfError::InvalidParam)?;
122 let xr = x.rem_vartime(&nz);
123 let xm = to_monty(&xr, ¶ms.monty);
124 let km = to_monty(&key.k, ¶ms.monty);
125 let sum = fp_add(xm, &km);
126 if bool::from(uint_ct_eq_zero(&sum.retrieve())) {
128 return Err(PrfError::ZeroInput);
129 }
130 let out_m = fp_pow(&sum, ¶ms.g);
131 Ok(out_m.retrieve().to_le_bytes().into())
132}