Skip to main content

pq_mayo/
keypair.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! MAYO keypair generation.
4
5use crate::error::Result;
6use crate::keygen::mayo_keypair_compact;
7use crate::params::MayoParameter;
8use crate::signing_key::SigningKey;
9use crate::verifying_key::VerifyingKey;
10use rand::CryptoRng;
11use zeroize::{Zeroize, ZeroizeOnDrop};
12
13/// A MAYO keypair containing both signing and verifying keys.
14#[derive(Clone)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[cfg_attr(feature = "serde", serde(bound = ""))]
17pub struct KeyPair<P: MayoParameter> {
18    signing_key: SigningKey<P>,
19    verifying_key: VerifyingKey<P>,
20}
21
22impl<P: MayoParameter> AsRef<VerifyingKey<P>> for KeyPair<P> {
23    fn as_ref(&self) -> &VerifyingKey<P> {
24        &self.verifying_key
25    }
26}
27
28impl<P: MayoParameter> signature::KeypairRef for KeyPair<P> {
29    type VerifyingKey = VerifyingKey<P>;
30}
31
32impl<P: MayoParameter> core::fmt::Debug for KeyPair<P> {
33    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34        f.debug_struct("KeyPair")
35            .field("variant", &P::NAME)
36            .field("signing_key", &self.signing_key)
37            .field("verifying_key", &self.verifying_key)
38            .finish()
39    }
40}
41
42impl<P: MayoParameter> PartialEq for KeyPair<P> {
43    fn eq(&self, other: &Self) -> bool {
44        self.signing_key == other.signing_key && self.verifying_key == other.verifying_key
45    }
46}
47
48impl<P: MayoParameter> Eq for KeyPair<P> {}
49
50impl<P: MayoParameter> Zeroize for KeyPair<P> {
51    fn zeroize(&mut self) {
52        self.signing_key.zeroize();
53    }
54}
55
56impl<P: MayoParameter> ZeroizeOnDrop for KeyPair<P> {}
57
58impl<P: MayoParameter> KeyPair<P> {
59    /// Generate a new random keypair.
60    pub fn generate(rng: &mut impl CryptoRng) -> Result<Self> {
61        let mut cpk = vec![0u8; P::CPK_BYTES];
62        let mut csk = hybrid_array::Array::<u8, P::CskSize>::default();
63        mayo_keypair_compact::<P>(&mut cpk, &mut csk, rng)?;
64        Ok(Self {
65            signing_key: SigningKey {
66                bytes: csk,
67                cpk: cpk.clone(),
68            },
69            verifying_key: VerifyingKey::from_bytes_unchecked(cpk),
70        })
71    }
72
73    /// Generate a keypair from a specific seed.
74    ///
75    /// The seed must be exactly `SK_SEED_BYTES` long.
76    pub fn from_seed(seed: &[u8]) -> Result<Self> {
77        use crate::error::Error;
78        if seed.len() != P::SK_SEED_BYTES {
79            return Err(Error::InvalidSeedLength {
80                expected: P::SK_SEED_BYTES,
81                got: seed.len(),
82            });
83        }
84
85        let mut csk = hybrid_array::Array::<u8, P::CskSize>::default();
86        csk[..P::SK_SEED_BYTES].copy_from_slice(seed);
87
88        let mut cpk = vec![0u8; P::CPK_BYTES];
89        derive_cpk_from_csk::<P>(&csk, &mut cpk);
90
91        Ok(Self {
92            signing_key: SigningKey {
93                bytes: csk,
94                cpk: cpk.clone(),
95            },
96            verifying_key: VerifyingKey::from_bytes_unchecked(cpk),
97        })
98    }
99
100    /// Construct a keypair from a [`SigningKey`], deriving the corresponding [`VerifyingKey`].
101    pub fn from_signing_key(signing_key: SigningKey<P>) -> Result<Self> {
102        let verifying_key = VerifyingKey::from_bytes_unchecked(signing_key.cpk.clone());
103        Ok(Self {
104            signing_key,
105            verifying_key,
106        })
107    }
108
109    /// Get a reference to the signing key.
110    pub fn signing_key(&self) -> &SigningKey<P> {
111        &self.signing_key
112    }
113
114    /// Get a reference to the verifying key.
115    pub fn verifying_key(&self) -> &VerifyingKey<P> {
116        &self.verifying_key
117    }
118}
119
120/// Derive the compact public key from a compact secret key.
121pub(crate) fn derive_cpk_from_csk<P: MayoParameter>(csk: &[u8], cpk: &mut [u8]) {
122    use crate::codec::{decode, pack_m_vecs};
123    use crate::keygen::expand_p1_p2;
124    use crate::matrix_ops::{compute_p3, m_upper};
125    use shake::Shake256;
126    use shake::digest::{ExtendableOutput, Update, XofReader};
127    use zeroize::Zeroizing;
128
129    let m_vec_limbs = P::M_VEC_LIMBS;
130    let param_m = P::M;
131    let param_v = P::V;
132    let param_o = P::O;
133    let param_o_bytes = P::O_BYTES;
134    let param_pk_seed_bytes = P::PK_SEED_BYTES;
135    let param_sk_seed_bytes = P::SK_SEED_BYTES;
136    let param_p3_limbs = P::P3_LIMBS;
137
138    let seed_sk = &csk[..param_sk_seed_bytes];
139
140    // S = SHAKE256(seed_sk) -> pk_seed || O_bytes
141    let mut s = Zeroizing::new(vec![0u8; param_pk_seed_bytes + param_o_bytes]);
142    let mut hasher = Shake256::default();
143    hasher.update(seed_sk);
144    let mut reader = hasher.finalize_xof();
145    reader.read(&mut s);
146
147    let seed_pk = &s[..param_pk_seed_bytes];
148
149    // Decode O
150    let mut o = Zeroizing::new(vec![0u8; param_v * param_o]);
151    decode(&s[param_pk_seed_bytes..], &mut o, param_v * param_o);
152
153    // Expand P1, P2. These are public once seed_pk is stored in cpk.
154    let p = expand_p1_p2::<P>(seed_pk);
155    let p1_limbs = P::P1_LIMBS;
156
157    // Compute P3
158    let mut p3 = Zeroizing::new(vec![0u64; param_o * param_o * m_vec_limbs]);
159    {
160        let p1 = &p[..p1_limbs];
161        let mut p2 = Zeroizing::new(p[p1_limbs..p1_limbs + P::P2_LIMBS].to_vec());
162        compute_p3::<P>(p1, &mut p2, &o, &mut p3);
163    }
164
165    // Store seed_pk
166    cpk[..param_pk_seed_bytes].copy_from_slice(seed_pk);
167
168    // Upper(P3) -> pack into cpk
169    let mut p3_upper = vec![0u64; param_p3_limbs];
170    m_upper(m_vec_limbs, &p3, &mut p3_upper, param_o);
171    pack_m_vecs(
172        &p3_upper,
173        &mut cpk[param_pk_seed_bytes..],
174        param_p3_limbs / m_vec_limbs,
175        param_m,
176    );
177}