1use crate::edwards::affine::PointBytes;
5use crate::sign::{HASH_HEAD, InnerSignature};
6use crate::{
7 CompressedEdwardsY, Context, EdwardsPoint, EdwardsScalar, PreHash, Signature, SigningError,
8 WideEdwardsScalarBytes,
9};
10
11#[cfg(feature = "serde")]
12use crate::PUBLIC_KEY_LENGTH;
13
14#[cfg(feature = "pkcs8")]
15use elliptic_curve::pkcs8;
16
17use core::{
18 fmt::{self, Debug, Formatter},
19 hash::{Hash, Hasher},
20};
21use elliptic_curve::Group;
22use sha3::{
23 Shake256,
24 digest::{Digest, ExtendableOutput, Update, XofReader},
25};
26use signature::Error;
27
28#[derive(Copy, Clone, Default, Eq)]
30pub struct VerifyingKey {
31 pub(crate) compressed: CompressedEdwardsY,
32 pub(crate) point: EdwardsPoint,
33}
34
35impl Debug for VerifyingKey {
36 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
37 write!(f, "VerifyingKey({:?}), {:?}", self.compressed, self.point)
38 }
39}
40
41impl AsRef<[u8]> for VerifyingKey {
42 fn as_ref(&self) -> &[u8] {
43 self.compressed.as_bytes()
44 }
45}
46
47impl Hash for VerifyingKey {
48 fn hash<H: Hasher>(&self, state: &mut H) {
49 self.compressed.as_bytes().hash(state);
50 }
51}
52
53impl PartialEq for VerifyingKey {
54 fn eq(&self, other: &Self) -> bool {
55 self.compressed.as_bytes() == other.compressed.as_bytes()
56 }
57}
58
59impl signature::Verifier<Signature> for VerifyingKey {
60 fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> {
61 self.verify_raw(signature, msg)
62 }
63}
64
65impl<D> signature::DigestVerifier<D, Signature> for VerifyingKey
66where
67 D: Digest + Update,
68{
69 fn verify_digest<F: Fn(&mut D) -> Result<(), Error>>(
70 &self,
71 f: F,
72 signature: &Signature,
73 ) -> Result<(), Error> {
74 let mut digest = D::new();
75 f(&mut digest)?;
76 self.verify_inner(signature, 1, &[], &digest.finalize())
77 }
78}
79
80impl signature::Verifier<Signature> for Context<'_, '_, VerifyingKey> {
81 fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> {
82 self.key.verify_ctx(signature, self.value, msg)
83 }
84}
85
86impl<D> signature::DigestVerifier<D, Signature> for Context<'_, '_, VerifyingKey>
87where
88 D: Digest + Update,
89{
90 fn verify_digest<F: Fn(&mut D) -> Result<(), Error>>(
91 &self,
92 f: F,
93 signature: &Signature,
94 ) -> Result<(), Error> {
95 let mut digest = D::new();
96 f(&mut digest)?;
97 self.key
98 .verify_inner(signature, 1, self.value, &digest.finalize())
99 }
100}
101
102#[cfg(feature = "pkcs8")]
103pub use ed448::pkcs8::PublicKeyBytes;
104
105#[cfg(feature = "pkcs8")]
106impl TryFrom<PublicKeyBytes> for VerifyingKey {
107 type Error = pkcs8::spki::Error;
108
109 fn try_from(value: PublicKeyBytes) -> Result<Self, Self::Error> {
110 VerifyingKey::try_from(&value)
111 }
112}
113
114#[cfg(feature = "pkcs8")]
115impl TryFrom<&PublicKeyBytes> for VerifyingKey {
116 type Error = pkcs8::spki::Error;
117
118 fn try_from(value: &PublicKeyBytes) -> Result<Self, Self::Error> {
119 VerifyingKey::from_bytes(&value.0).map_err(|_| pkcs8::spki::Error::KeyMalformed)
120 }
121}
122
123#[cfg(feature = "pkcs8")]
124impl From<VerifyingKey> for PublicKeyBytes {
125 fn from(key: VerifyingKey) -> Self {
126 Self(key.compressed.to_bytes())
127 }
128}
129
130#[cfg(all(feature = "alloc", feature = "pkcs8"))]
131impl pkcs8::EncodePublicKey for VerifyingKey {
132 fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> {
133 PublicKeyBytes::from(*self).to_public_key_der()
134 }
135}
136
137#[cfg(all(feature = "alloc", feature = "pkcs8"))]
138impl pkcs8::spki::DynSignatureAlgorithmIdentifier for VerifyingKey {
139 fn signature_algorithm_identifier(
140 &self,
141 ) -> pkcs8::spki::Result<pkcs8::spki::AlgorithmIdentifierOwned> {
142 Ok(pkcs8::spki::AlgorithmIdentifierOwned {
144 oid: super::ALGORITHM_OID,
145 parameters: None,
146 })
147 }
148}
149
150#[cfg(feature = "pkcs8")]
151impl TryFrom<pkcs8::spki::SubjectPublicKeyInfoRef<'_>> for VerifyingKey {
152 type Error = pkcs8::spki::Error;
153
154 fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
155 PublicKeyBytes::try_from(public_key)?.try_into()
156 }
157}
158
159#[cfg(feature = "serde")]
160impl serdect::serde::Serialize for VerifyingKey {
161 fn serialize<S: serdect::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
162 serdect::array::serialize_hex_lower_or_bin(self.compressed.as_bytes(), s)
163 }
164}
165
166#[cfg(feature = "serde")]
167impl<'de> serdect::serde::Deserialize<'de> for VerifyingKey {
168 fn deserialize<D: serdect::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
169 let mut bytes = [0u8; PUBLIC_KEY_LENGTH];
170 serdect::array::deserialize_hex_or_bin(&mut bytes, d)?;
171 VerifyingKey::from_bytes(&bytes).map_err(serdect::serde::de::Error::custom)
172 }
173}
174
175impl VerifyingKey {
176 pub fn to_bytes(&self) -> PointBytes {
178 self.compressed.to_bytes()
179 }
180
181 pub fn as_bytes(&self) -> &PointBytes {
183 self.compressed.as_bytes()
184 }
185
186 pub fn from_bytes(bytes: &PointBytes) -> Result<Self, Error> {
188 let compressed = CompressedEdwardsY(*bytes);
189 let point = compressed
190 .decompress()
191 .into_option()
192 .map(|point| point.to_edwards())
193 .ok_or(SigningError::InvalidPublicKeyBytes)?;
194 if point.is_identity().into() {
195 return Err(SigningError::InvalidPublicKeyBytes.into());
196 }
197 Ok(Self { compressed, point })
198 }
199
200 pub fn with_context<'k, 'v>(&'k self, context: &'v [u8]) -> Context<'k, 'v, Self> {
202 Context {
203 key: self,
204 value: context,
205 }
206 }
207
208 pub fn to_edwards(self) -> EdwardsPoint {
210 self.point
211 }
212
213 pub fn verify_raw(&self, signature: &Signature, message: &[u8]) -> Result<(), Error> {
222 self.verify_inner(signature, 0, &[], message)
223 }
224
225 pub fn verify_ctx(self, sig: &Signature, ctx: &[u8], message: &[u8]) -> Result<(), Error> {
235 self.verify_inner(sig, 0, ctx, message)
236 }
237
238 pub fn verify_prehashed<D>(
251 self,
252 sig: &Signature,
253 ctx: Option<&[u8]>,
254 mut prehashed_message: D,
255 ) -> Result<(), Error>
256 where
257 D: PreHash,
258 {
259 let mut m = [0u8; 64];
260 prehashed_message.fill_bytes(&mut m);
261 self.verify_inner(sig, 1, ctx.unwrap_or_default(), &m)
262 }
263
264 fn verify_inner(
265 &self,
266 signature: &Signature,
267 phflag: u8,
268 ctx: &[u8],
269 m: &[u8],
270 ) -> Result<(), Error> {
271 if signature.s_bytes()[56] != 0x00 {
275 return Err(SigningError::InvalidSignatureSComponent.into());
276 }
277 if self.point.is_identity().into() {
278 return Err(SigningError::InvalidPublicKeyBytes.into());
279 }
280
281 let inner_signature = InnerSignature::try_from(signature)?;
282 if inner_signature.r.is_identity().into() {
283 return Err(SigningError::InvalidSignatureRComponent.into());
284 }
285
286 if inner_signature.s.is_zero().into() {
287 return Err(SigningError::InvalidSignatureSComponent.into());
288 }
289
290 let mut bytes = WideEdwardsScalarBytes::default();
292 let ctx_len = ctx.len() as u8;
293 let mut reader = Shake256::default()
294 .chain(HASH_HEAD)
295 .chain([phflag])
296 .chain([ctx_len])
297 .chain(ctx)
298 .chain(signature.r_bytes())
299 .chain(self.compressed.as_bytes())
300 .chain(m)
301 .finalize_xof();
302 reader.read(&mut bytes);
303 let k = EdwardsScalar::from_bytes_mod_order_wide(&bytes);
304 let lhs = EdwardsPoint::GENERATOR * inner_signature.s;
306 let rhs = inner_signature.r + (self.point * k);
307 if lhs == rhs {
308 Ok(())
309 } else {
310 Err(SigningError::Verify.into())
311 }
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318 use crate::{PUBLIC_KEY_LENGTH, PreHasherXof, SecretKey, SigningKey};
319
320 struct Ed448TestVector<'a> {
321 s: &'a str,
322 q: &'a str,
323 m: &'a str,
324 ph: bool,
325 ctx: &'a str,
326 sig: &'a str,
327 }
328
329 const TEST_VECTORS: [Ed448TestVector; 6] = [
331 Ed448TestVector {
333 s: "6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b",
334 q: "5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180",
335 m: "",
336 ph: false,
337 ctx: "",
338 sig: "533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4dbb61149f05a7363268c71d95808ff2e652600",
339 },
340 Ed448TestVector {
342 s: "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
343 q: "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
344 m: "03",
345 ph: false,
346 ctx: "",
347 sig: "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f4352541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cbcee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0ff3348ab21aa4adafd1d234441cf807c03a00",
348 },
349 Ed448TestVector {
351 s: "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
352 q: "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
353 m: "03",
354 ph: false,
355 ctx: "666f6f",
356 sig: "d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5c8da1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d5428407e85dcbc98a49155c13764e66c3c00",
357 },
358 Ed448TestVector {
360 s: "2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d37569b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5",
361 q: "79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9bfe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00",
362 m: "15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567cfa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072fc1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a6039c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b590316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce012d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11",
363 ph: false,
364 ctx: "",
365 sig: "c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc60987fd08527c1a8e80d5823e65cafe2a3d00",
366 },
367 Ed448TestVector {
369 s: "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
370 q: "259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
371 m: "616263",
372 ph: true,
373 ctx: "",
374 sig: "822f6901f7480f3d5f562c592994d9693602875614483256505600bbc281ae381f54d6bce2ea911574932f52a4e6cadd78769375ec3ffd1b801a0d9b3f4030cd433964b6457ea39476511214f97469b57dd32dbc560a9a94d00bff07620464a3ad203df7dc7ce360c3cd3696d9d9fab90f00",
375 },
376 Ed448TestVector {
377 s: "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
378 q: "259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
379 m: "616263",
380 ph: true,
381 ctx: "666f6f",
382 sig: "c32299d46ec8ff02b54540982814dce9a05812f81962b649d528095916a2aa481065b1580423ef927ecf0af5888f90da0f6a9a85ad5dc3f280d91224ba9911a3653d00e484e2ce232521481c8658df304bb7745a73514cdb9bf3e15784ab71284f8d0704a608c54a6b62d97beb511d132100",
383 },
384 ];
385
386 #[test]
387 fn signatures() {
388 for tv in TEST_VECTORS.iter() {
389 let mut seed = SecretKey::default();
390 hex::decode_to_slice(tv.s, &mut seed).unwrap();
391 let mut q_enc = [0u8; PUBLIC_KEY_LENGTH];
392 hex::decode_to_slice(tv.q, &mut q_enc).unwrap();
393 let msg = hex::decode(tv.m).unwrap();
394 let ctx = hex::decode(tv.ctx).unwrap();
395 let mut sig = [0u8; 114];
396 hex::decode_to_slice(tv.sig, &mut sig[..]).unwrap();
397 let sig = Signature::try_from(&sig[..]).unwrap();
398
399 let skey = SigningKey::from(&seed);
400 assert_eq!(&q_enc[..], skey.verifying_key().as_bytes());
401 if tv.ph {
402 assert_eq!(
403 skey.sign_prehashed::<PreHasherXof<Shake256>>(
404 Some(&ctx[..]),
405 Shake256::default().chain(&msg).into(),
406 )
407 .unwrap(),
408 sig
409 );
410 } else {
411 assert_eq!(skey.sign_ctx(&ctx[..], &msg[..]).unwrap(), sig);
412 if ctx.is_empty() {
413 assert_eq!(skey.sign_raw(&msg[..]), sig);
414 }
415 }
416
417 let pkey = VerifyingKey::from_bytes(&q_enc).unwrap();
418 if tv.ph {
419 let mut reader = Shake256::default().chain(&msg).finalize_xof();
420 let mut hm = [0u8; 64];
421 reader.read(&mut hm);
422 assert!(pkey.verify_inner(&sig, 1, &ctx[..], &hm).is_ok());
423 assert!(pkey.verify_inner(&sig, 1, &[1u8], &hm).is_err());
424 hm[42] ^= 0x08;
425 assert!(pkey.verify_inner(&sig, 1, &ctx[..], &hm).is_err());
426 } else {
427 assert!(pkey.verify_ctx(&sig, &ctx[..], &msg[..]).is_ok());
428 assert!(pkey.verify_ctx(&sig, &[1u8], &msg[..]).is_err());
429 assert!(pkey.verify_ctx(&sig, &ctx[..], &[0u8]).is_err());
430 if ctx.is_empty() {
431 assert!(pkey.verify_raw(&sig, &msg[..]).is_ok());
432 }
433 }
434 }
435 }
436
437 #[cfg(feature = "serde")]
438 #[test]
439 fn serialization() {
440 use rand_chacha::ChaCha8Rng;
441 use rand_core::SeedableRng;
442
443 let mut rng = ChaCha8Rng::from_seed([0u8; 32]);
444 let signing_key = SigningKey::generate(&mut rng);
445 let verifying_key = signing_key.verifying_key();
446
447 let bytes = serde_bare::to_vec(&verifying_key).unwrap();
448 let verifying_key2: VerifyingKey = serde_bare::from_slice(&bytes).unwrap();
449 assert_eq!(verifying_key, verifying_key2);
450
451 let string = serde_json::to_string(&verifying_key).unwrap();
452 let verifying_key3: VerifyingKey = serde_json::from_str(&string).unwrap();
453 assert_eq!(verifying_key, verifying_key3);
454 }
455}