Skip to main content

pq_mayo/
verifying_key.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! MAYO verifying (public) key.
4
5use crate::error::Error;
6use crate::mayo_signature::Signature;
7use crate::params::MayoParameter;
8use crate::signing_key::SigningKey;
9use crate::verify::{
10    VerifyScratch, expand_public_key, mayo_verify, mayo_verify_with_expanded_pk,
11    mayo_verify_with_expanded_pk_and_scratch,
12};
13use core::marker::PhantomData;
14
15/// A MAYO verifying key (compact public key).
16#[derive(Clone)]
17pub struct VerifyingKey<P: MayoParameter> {
18    pub(crate) bytes: Vec<u8>,
19    pub(crate) _marker: PhantomData<P>,
20}
21
22impl<P: MayoParameter> AsRef<[u8]> for VerifyingKey<P> {
23    fn as_ref(&self) -> &[u8] {
24        &self.bytes
25    }
26}
27
28impl<P: MayoParameter> TryFrom<&[u8]> for VerifyingKey<P> {
29    type Error = Error;
30
31    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
32        if bytes.len() != P::CPK_BYTES {
33            return Err(Error::InvalidKeyLength {
34                expected: P::CPK_BYTES,
35                got: bytes.len(),
36            });
37        }
38        Ok(Self::from_bytes_unchecked(bytes.to_vec()))
39    }
40}
41
42impl<P: MayoParameter> TryFrom<Vec<u8>> for VerifyingKey<P> {
43    type Error = Error;
44
45    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
46        if bytes.len() != P::CPK_BYTES {
47            return Err(Error::InvalidKeyLength {
48                expected: P::CPK_BYTES,
49                got: bytes.len(),
50            });
51        }
52        Ok(Self::from_bytes_unchecked(bytes))
53    }
54}
55
56impl<P: MayoParameter> TryFrom<&Vec<u8>> for VerifyingKey<P> {
57    type Error = Error;
58
59    fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
60        Self::try_from(bytes.as_slice())
61    }
62}
63
64impl<P: MayoParameter> TryFrom<Box<[u8]>> for VerifyingKey<P> {
65    type Error = Error;
66
67    fn try_from(bytes: Box<[u8]>) -> Result<Self, Self::Error> {
68        if bytes.len() != P::CPK_BYTES {
69            return Err(Error::InvalidKeyLength {
70                expected: P::CPK_BYTES,
71                got: bytes.len(),
72            });
73        }
74        Ok(Self::from_bytes_unchecked(bytes.into_vec()))
75    }
76}
77
78impl<P: MayoParameter> PartialEq for VerifyingKey<P> {
79    fn eq(&self, other: &Self) -> bool {
80        self.bytes == other.bytes
81    }
82}
83
84impl<P: MayoParameter> Eq for VerifyingKey<P> {}
85
86impl<P: MayoParameter> core::fmt::Debug for VerifyingKey<P> {
87    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
88        f.debug_struct("VerifyingKey")
89            .field("variant", &P::NAME)
90            .field("bytes", &hex::encode(&self.bytes))
91            .finish()
92    }
93}
94
95impl<P: MayoParameter> From<&SigningKey<P>> for VerifyingKey<P> {
96    fn from(sk: &SigningKey<P>) -> Self {
97        Self::from_bytes_unchecked(sk.cpk.clone())
98    }
99}
100
101impl<P: MayoParameter> signature::Verifier<Signature<P>> for VerifyingKey<P> {
102    fn verify(&self, msg: &[u8], signature: &Signature<P>) -> Result<(), signature::Error> {
103        mayo_verify::<P>(msg, signature.as_ref(), &self.bytes).map_err(Into::into)
104    }
105}
106
107impl<P: MayoParameter> VerifyingKey<P> {
108    pub(crate) fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
109        Self {
110            bytes,
111            _marker: PhantomData,
112        }
113    }
114
115    /// Expand this compact verifying key for faster repeated verification.
116    pub fn expand(&self) -> ExpandedVerifyingKey<P> {
117        ExpandedVerifyingKey::from_bytes_unchecked(self.bytes.clone())
118    }
119}
120
121/// A MAYO verifying key with cached expanded public material.
122///
123/// This keeps the compact public key bytes for serialization and equality,
124/// and additionally stores expanded public data used by verification.
125#[derive(Clone)]
126pub struct ExpandedVerifyingKey<P: MayoParameter> {
127    bytes: Vec<u8>,
128    expanded_pk: Vec<u64>,
129    p3: Vec<u64>,
130    _marker: PhantomData<P>,
131}
132
133/// A reusable MAYO verification context.
134///
135/// This stores an expanded verifying key plus mutable scratch buffers for
136/// repeated verification with the same public key.
137pub struct VerificationContext<P: MayoParameter> {
138    key: ExpandedVerifyingKey<P>,
139    scratch: VerifyScratch,
140}
141
142impl<P: MayoParameter> AsRef<[u8]> for ExpandedVerifyingKey<P> {
143    fn as_ref(&self) -> &[u8] {
144        &self.bytes
145    }
146}
147
148impl<P: MayoParameter> TryFrom<&[u8]> for ExpandedVerifyingKey<P> {
149    type Error = Error;
150
151    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
152        VerifyingKey::<P>::try_from(bytes).map(|vk| vk.expand())
153    }
154}
155
156impl<P: MayoParameter> TryFrom<Vec<u8>> for ExpandedVerifyingKey<P> {
157    type Error = Error;
158
159    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
160        if bytes.len() != P::CPK_BYTES {
161            return Err(Error::InvalidKeyLength {
162                expected: P::CPK_BYTES,
163                got: bytes.len(),
164            });
165        }
166        Ok(Self::from_bytes_unchecked(bytes))
167    }
168}
169
170impl<P: MayoParameter> TryFrom<&Vec<u8>> for ExpandedVerifyingKey<P> {
171    type Error = Error;
172
173    fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
174        Self::try_from(bytes.as_slice())
175    }
176}
177
178impl<P: MayoParameter> TryFrom<Box<[u8]>> for ExpandedVerifyingKey<P> {
179    type Error = Error;
180
181    fn try_from(bytes: Box<[u8]>) -> Result<Self, Self::Error> {
182        Self::try_from(bytes.into_vec())
183    }
184}
185
186impl<P: MayoParameter> From<&VerifyingKey<P>> for ExpandedVerifyingKey<P> {
187    fn from(vk: &VerifyingKey<P>) -> Self {
188        vk.expand()
189    }
190}
191
192impl<P: MayoParameter> From<&SigningKey<P>> for ExpandedVerifyingKey<P> {
193    fn from(sk: &SigningKey<P>) -> Self {
194        Self::from_bytes_unchecked(sk.cpk.clone())
195    }
196}
197
198impl<P: MayoParameter> PartialEq for ExpandedVerifyingKey<P> {
199    fn eq(&self, other: &Self) -> bool {
200        self.bytes == other.bytes
201    }
202}
203
204impl<P: MayoParameter> Eq for ExpandedVerifyingKey<P> {}
205
206impl<P: MayoParameter> PartialEq for VerificationContext<P> {
207    fn eq(&self, other: &Self) -> bool {
208        self.key == other.key
209    }
210}
211
212impl<P: MayoParameter> Eq for VerificationContext<P> {}
213
214impl<P: MayoParameter> core::fmt::Debug for ExpandedVerifyingKey<P> {
215    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216        f.debug_struct("ExpandedVerifyingKey")
217            .field("variant", &P::NAME)
218            .field("bytes", &hex::encode(&self.bytes))
219            .finish()
220    }
221}
222
223impl<P: MayoParameter> core::fmt::Debug for VerificationContext<P> {
224    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
225        f.debug_struct("VerificationContext")
226            .field("variant", &P::NAME)
227            .field("key", &self.key)
228            .finish_non_exhaustive()
229    }
230}
231
232impl<P: MayoParameter> signature::Verifier<Signature<P>> for ExpandedVerifyingKey<P> {
233    fn verify(&self, msg: &[u8], signature: &Signature<P>) -> Result<(), signature::Error> {
234        mayo_verify_with_expanded_pk::<P>(msg, signature.as_ref(), &self.expanded_pk, &self.p3)
235            .map_err(Into::into)
236    }
237}
238
239impl<P: MayoParameter> ExpandedVerifyingKey<P> {
240    fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
241        let (expanded_pk, p3) = expand_public_key::<P>(&bytes);
242        Self {
243            bytes,
244            expanded_pk,
245            p3,
246            _marker: PhantomData,
247        }
248    }
249
250    /// Return the compact verifying key form.
251    pub fn compact(&self) -> VerifyingKey<P> {
252        VerifyingKey::from_bytes_unchecked(self.bytes.clone())
253    }
254
255    /// Create a reusable verification context for this expanded key.
256    pub fn context(&self) -> VerificationContext<P> {
257        VerificationContext::from(self)
258    }
259}
260
261impl<P: MayoParameter> VerificationContext<P> {
262    /// Verify a signature using cached expanded public material and scratch buffers.
263    pub fn verify(&mut self, msg: &[u8], signature: &Signature<P>) -> Result<(), signature::Error> {
264        mayo_verify_with_expanded_pk_and_scratch::<P>(
265            msg,
266            signature.as_ref(),
267            &self.key.expanded_pk,
268            &self.key.p3,
269            &mut self.scratch,
270        )
271        .map_err(Into::into)
272    }
273
274    /// Return the expanded verifying key backing this context.
275    pub fn verifying_key(&self) -> &ExpandedVerifyingKey<P> {
276        &self.key
277    }
278}
279
280impl<P: MayoParameter> From<&ExpandedVerifyingKey<P>> for VerificationContext<P> {
281    fn from(key: &ExpandedVerifyingKey<P>) -> Self {
282        Self {
283            key: key.clone(),
284            scratch: VerifyScratch::new::<P>(),
285        }
286    }
287}
288
289impl<P: MayoParameter> From<&VerifyingKey<P>> for VerificationContext<P> {
290    fn from(key: &VerifyingKey<P>) -> Self {
291        Self::from(&key.expand())
292    }
293}
294
295#[cfg(feature = "serde")]
296impl<P: MayoParameter> serde::Serialize for VerifyingKey<P> {
297    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
298    where
299        S: serde::Serializer,
300    {
301        serdect::slice::serialize_hex_lower_or_bin(&self.bytes, serializer)
302    }
303}
304
305#[cfg(feature = "serde")]
306impl<'de, P: MayoParameter> serde::Deserialize<'de> for VerifyingKey<P> {
307    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308    where
309        D: serde::Deserializer<'de>,
310    {
311        let bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
312        Self::try_from(bytes).map_err(serde::de::Error::custom)
313    }
314}
315
316#[cfg(feature = "serde")]
317impl<P: MayoParameter> serde::Serialize for ExpandedVerifyingKey<P> {
318    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
319    where
320        S: serde::Serializer,
321    {
322        serdect::slice::serialize_hex_lower_or_bin(&self.bytes, serializer)
323    }
324}
325
326#[cfg(feature = "serde")]
327impl<'de, P: MayoParameter> serde::Deserialize<'de> for ExpandedVerifyingKey<P> {
328    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
329    where
330        D: serde::Deserializer<'de>,
331    {
332        let bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
333        Self::try_from(bytes).map_err(serde::de::Error::custom)
334    }
335}