1use crate::{
4 B32, B64, EncodedVerifyingKey, MlDsaParams, MuBuilder, Signature,
5 algebra::{Elem, NttMatrix, NttVector, Vector},
6 crypto::H,
7 ntt::{Ntt, NttInverse},
8 param::ParameterSet,
9 param::VerifyingKeySize,
10 sampling::{expand_a, sample_in_ball},
11};
12use common::{Key, KeyExport, KeyInit, KeySizeUser};
13use module_lattice::MaybeBox;
14use shake::Shake256;
15use signature::{DigestVerifier, Error, MultipartVerifier};
16
17#[derive(Clone, Debug, PartialEq)]
19pub struct VerifyingKey<P: ParameterSet> {
20 rho: B32,
22
23 t1: MaybeBox<Vector<P::K>>,
25
26 precomputed_values: MaybeBox<PrecomputedValues<P>>,
28}
29
30#[derive(Clone, Debug, PartialEq)]
33struct PrecomputedValues<P: ParameterSet> {
34 A_hat: NttMatrix<P::K, P::L>,
36
37 t1_2d_hat: NttVector<P::K>,
39
40 tr: B64,
42}
43
44impl<P: MlDsaParams> PrecomputedValues<P> {
45 fn new(t1: &Vector<P::K>, enc: &EncodedVerifyingKey<P>, A_hat: NttMatrix<P::K, P::L>) -> Self {
46 let t1_2d_hat = (Elem::new(1 << 13) * t1).ntt();
47 let tr = H::default().absorb(enc).squeeze_new();
48
49 Self {
50 A_hat,
51 t1_2d_hat,
52 tr,
53 }
54 }
55}
56
57impl<P: MlDsaParams> VerifyingKey<P> {
58 pub(crate) fn new(
59 rho: B32,
60 t1: Vector<P::K>,
61 A_hat: NttMatrix<P::K, P::L>,
62 enc: Option<EncodedVerifyingKey<P>>,
63 ) -> Self {
64 let enc = enc.unwrap_or_else(|| Self::encode_internal(&rho, &t1));
65 let precomputed_values = PrecomputedValues::new(&t1, &enc, A_hat);
66
67 Self {
68 rho,
69 t1: MaybeBox::new(t1),
70 precomputed_values: MaybeBox::new(precomputed_values),
71 }
72 }
73
74 #[inline]
75 fn new_expand_a(rho: B32, t1: Vector<P::K>, enc: Option<EncodedVerifyingKey<P>>) -> Self {
76 let A_hat = expand_a(&rho);
77 Self::new(rho, t1, A_hat, enc)
78 }
79
80 pub fn compute_mu<F: FnOnce(&mut Shake256) -> Result<(), Error>>(
86 &self,
87 Mp: F,
88 ctx: &[u8],
89 ) -> Result<B64, Error> {
90 if ctx.len() > 255 {
91 return Err(Error::new());
92 }
93
94 let mut mu = MuBuilder::new(&self.precomputed_values.tr, ctx);
95 Mp(mu.as_mut())?;
96 Ok(mu.finish())
97 }
98
99 pub fn verify_internal(&self, M: &[u8], sigma: &Signature<P>) -> bool
104 where
105 P: MlDsaParams,
106 {
107 let mu = MuBuilder::internal(&self.precomputed_values.tr, &[M]);
108 self.raw_verify_mu(&mu, sigma)
109 }
110
111 pub(crate) fn raw_verify_mu(&self, mu: &B64, sigma: &Signature<P>) -> bool
112 where
113 P: MlDsaParams,
114 {
115 let c = sample_in_ball(&sigma.c_tilde, P::TAU);
117
118 let z_hat = sigma.z.ntt();
119 let c_hat = c.ntt();
120 let Az_hat = &self.precomputed_values.A_hat * &z_hat;
121 let ct1_2d_hat = &c_hat * &self.precomputed_values.t1_2d_hat;
122
123 let wp_approx = (&Az_hat - &ct1_2d_hat).ntt_inverse();
124 let w1p = sigma.h.use_hint(&wp_approx);
125
126 let w1p_tilde = P::encode_w1(&w1p);
127 let cp_tilde = H::default()
128 .absorb(mu)
129 .absorb(&w1p_tilde)
130 .squeeze_new::<P::Lambda>();
131
132 sigma.c_tilde == cp_tilde
133 }
134
135 pub fn verify_with_context(&self, M: &[u8], ctx: &[u8], sigma: &Signature<P>) -> bool {
137 self.raw_verify_with_context(&[M], ctx, sigma)
138 }
139
140 pub fn verify_mu(&self, mu: &B64, sigma: &Signature<P>) -> bool {
142 self.raw_verify_mu(mu, sigma)
143 }
144
145 fn raw_verify_with_context(&self, M: &[&[u8]], ctx: &[u8], sigma: &Signature<P>) -> bool {
146 if ctx.len() > 255 {
147 return false;
148 }
149
150 let mu = MuBuilder::new(&self.precomputed_values.tr, ctx).message(M);
151 self.verify_mu(&mu, sigma)
152 }
153
154 pub(crate) fn encode_internal(rho: &B32, t1: &Vector<P::K>) -> EncodedVerifyingKey<P> {
155 let t1_enc = P::encode_t1(t1);
156 P::concat_vk(rho.clone(), t1_enc)
157 }
158
159 #[must_use]
163 pub fn encode(&self) -> EncodedVerifyingKey<P> {
164 Self::encode_internal(&self.rho, &self.t1)
165 }
166
167 pub fn decode(enc: &EncodedVerifyingKey<P>) -> Self {
171 let (rho, t1_enc) = P::split_vk(enc);
172 let t1 = P::decode_t1(t1_enc);
173 Self::new_expand_a(rho.clone(), t1, Some(enc.clone()))
174 }
175}
176
177impl<P: MlDsaParams> KeySizeUser for VerifyingKey<P> {
178 type KeySize = VerifyingKeySize<P>;
179}
180
181impl<P: MlDsaParams> KeyInit for VerifyingKey<P> {
182 fn new(key: &Key<Self>) -> Self {
183 Self::decode(key)
184 }
185}
186
187impl<P: MlDsaParams> KeyExport for VerifyingKey<P> {
188 fn to_bytes(&self) -> Key<Self> {
189 self.encode()
190 }
191}
192
193impl<P: MlDsaParams> core::hash::Hash for VerifyingKey<P> {
194 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
195 self.encode().hash(state);
196 }
197}
198
199impl<P: MlDsaParams> signature::Verifier<Signature<P>> for VerifyingKey<P> {
200 fn verify(&self, msg: &[u8], signature: &Signature<P>) -> Result<(), Error> {
201 self.multipart_verify(&[msg], signature)
202 }
203}
204
205impl<P: MlDsaParams> MultipartVerifier<Signature<P>> for VerifyingKey<P> {
206 fn multipart_verify(&self, msg: &[&[u8]], signature: &Signature<P>) -> Result<(), Error> {
207 self.raw_verify_with_context(msg, &[], signature)
208 .then_some(())
209 .ok_or(Error::new())
210 }
211}
212
213impl<P: MlDsaParams> DigestVerifier<Shake256, Signature<P>> for VerifyingKey<P> {
214 fn verify_digest<F: Fn(&mut Shake256) -> Result<(), Error>>(
215 &self,
216 f: F,
217 signature: &Signature<P>,
218 ) -> Result<(), Error> {
219 let mut mu = MuBuilder::new(&self.precomputed_values.tr, &[]);
220 f(mu.as_mut())?;
221 let mu = mu.finish();
222
223 self.raw_verify_mu(&mu, signature)
224 .then_some(())
225 .ok_or(Error::new())
226 }
227}