1use 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#[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 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 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 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 pub fn signing_key(&self) -> &SigningKey<P> {
111 &self.signing_key
112 }
113
114 pub fn verifying_key(&self) -> &VerifyingKey<P> {
116 &self.verifying_key
117 }
118}
119
120pub(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 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 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 let p = expand_p1_p2::<P>(seed_pk);
155 let p1_limbs = P::P1_LIMBS;
156
157 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 cpk[..param_pk_seed_bytes].copy_from_slice(seed_pk);
167
168 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}