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 std::marker::PhantomData;
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14#[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 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 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 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 pub fn signing_key(&self) -> &SigningKey<P> {
121 &self.signing_key
122 }
123
124 pub fn verifying_key(&self) -> &VerifyingKey<P> {
126 &self.verifying_key
127 }
128}
129
130pub(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 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 let mut o = vec![0u8; param_v * param_o];
160 decode(&s[param_pk_seed_bytes..], &mut o, param_v * param_o);
161
162 let mut p = expand_p1_p2::<P>(seed_pk);
164 let p1_limbs = P::P1_LIMBS;
165
166 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 cpk[..param_pk_seed_bytes].copy_from_slice(seed_pk);
175
176 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}