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