coconut_crypto/setup/keypair/
secret.rs

1use alloc::vec::Vec;
2
3use ark_ff::{
4    field_hashers::{DefaultFieldHasher, HashToField},
5    PrimeField,
6};
7use ark_serialize::*;
8use ark_std::rand::RngCore;
9use serde::{Deserialize, Serialize};
10use serde_with::serde_as;
11use utils::{misc::le_bytes_iter, serde_utils::ArkObjectBytes};
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14#[cfg(feature = "parallel")]
15use rayon::prelude::*;
16
17use crate::helpers::{n_rand, rand, FullDigest};
18use utils::{aliases::SyncIfParallel, concat_slices, join};
19
20/// `SecretKey` used in the modified Pointcheval-Sanders signature scheme.
21#[serde_as]
22#[derive(
23    Clone,
24    Debug,
25    PartialEq,
26    Eq,
27    Serialize,
28    Deserialize,
29    CanonicalSerialize,
30    CanonicalDeserialize,
31    Zeroize,
32    ZeroizeOnDrop,
33)]
34pub struct SecretKey<F: PrimeField> {
35    #[serde_as(as = "ArkObjectBytes")]
36    pub x: F,
37    #[serde_as(as = "Vec<ArkObjectBytes>")]
38    pub y: Vec<F>,
39}
40
41impl<F: PrimeField> SecretKey<F> {
42    pub const X_SALT: &'static [u8] = b"PS-SIG-X-KEYGEN-SALT";
43    pub const Y_SALT: &'static [u8] = b"PS-SIG-Y-KEYGEN-SALT";
44
45    /// Generates random secret key compatible with `message_count` messages.
46    pub fn rand<R: RngCore>(rng: &mut R, message_count: u32) -> Self {
47        let x = rand(rng);
48        let y = n_rand(rng, message_count as usize).collect();
49
50        Self { x, y }
51    }
52
53    /// Generates secret key compatible with `message_count` messages from supplied seed.
54    pub fn from_seed<D>(seed: &[u8], message_count: u32) -> Self
55    where
56        D: FullDigest + SyncIfParallel,
57    {
58        let new_hasher = <DefaultFieldHasher<D> as HashToField<F>>::new;
59
60        let (x, y) = join!(
61            new_hasher(Self::X_SALT)
62                .hash_to_field(seed, 1)
63                .pop()
64                .unwrap(),
65            {
66                let hasher = new_hasher(Self::Y_SALT);
67
68                le_bytes_iter(message_count)
69                    .map(|ctr| concat_slices!(seed, ctr))
70                    .map(|seed| hasher.hash_to_field(&seed, 1).pop().unwrap())
71                    .collect()
72            }
73        );
74
75        Self { x, y }
76    }
77
78    /// Returns max amount of messages supported by this secret key.
79    pub fn supported_message_count(&self) -> usize {
80        self.y.len()
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use ark_bls12_381::Bls12_381;
88    use ark_ec::pairing::Pairing;
89    use blake2::Blake2b512;
90
91    type Fr = <Bls12_381 as Pairing>::ScalarField;
92
93    #[test]
94    fn from_seed() {
95        let seed = b"test-seed";
96        let other_seed = b"other-seed";
97
98        assert_eq!(
99            SecretKey::<Fr>::from_seed::<Blake2b512>(seed, 10),
100            SecretKey::<Fr>::from_seed::<Blake2b512>(seed, 10),
101        );
102
103        assert!(
104            SecretKey::<Fr>::from_seed::<Blake2b512>(seed, 10)
105                != SecretKey::<Fr>::from_seed::<Blake2b512>(other_seed, 10)
106        );
107
108        assert_eq!(
109            SecretKey::<Fr>::from_seed::<Blake2b512>(seed, 10).y[0..9],
110            SecretKey::<Fr>::from_seed::<Blake2b512>(seed, 9).y,
111        );
112    }
113}