qp_dilithium_crypto/
traits.rs

1use super::types::{
2	DilithiumPair, DilithiumPublic, DilithiumSignatureScheme, DilithiumSigner, Error,
3	WrappedPublicBytes, WrappedSignatureBytes,
4};
5
6use crate::{DilithiumSignature, DilithiumSignatureWithPublic};
7use alloc::vec::Vec;
8use qp_poseidon::PoseidonHasher;
9use sp_core::{
10	crypto::{Derive, Public, PublicBytes, Signature, SignatureBytes},
11	ByteArray, Hasher, H256,
12};
13use sp_runtime::{
14	traits::{IdentifyAccount, Verify},
15	AccountId32, CryptoType,
16};
17
18/// Verifies a Dilithium ML-DSA-87 signature
19///
20/// This function performs signature verification using the Dilithium post-quantum
21/// cryptographic signature scheme (ML-DSA-87). It validates that the given signature
22/// was created by the holder of the private key corresponding to the public key.
23///
24/// # Arguments
25/// * `pub_key` - The public key bytes (must be valid Dilithium public key)
26/// * `msg` - The message that was signed
27/// * `sig` - The signature bytes to verify
28///
29/// # Returns
30/// `true` if the signature is valid and verification succeeds, `false` otherwise
31///
32/// # Examples
33/// ```ignore
34/// use qp_dilithium_crypto::verify;
35///
36/// let valid = verify(&public_key_bytes, &message, &signature_bytes);
37/// if valid {
38///     println!("Signature is valid!");
39/// }
40/// ```
41pub fn verify(pub_key: &[u8], msg: &[u8], sig: &[u8]) -> bool {
42	use qp_rusty_crystals_dilithium::ml_dsa_87::PublicKey;
43	match PublicKey::from_bytes(pub_key) {
44		Ok(pk) => pk.verify(msg, sig, None),
45		Err(e) => {
46			log::warn!("public key failed to deserialize {:?}", e);
47			false
48		},
49	}
50}
51
52//
53// Trait implementations for WrappedPublicBytes
54//
55
56impl<const N: usize, SubTag> Derive for WrappedPublicBytes<N, SubTag> {}
57impl<const N: usize, SubTag> AsMut<[u8]> for WrappedPublicBytes<N, SubTag> {
58	fn as_mut(&mut self) -> &mut [u8] {
59		self.0.as_mut()
60	}
61}
62impl<const N: usize, SubTag> AsRef<[u8]> for WrappedPublicBytes<N, SubTag> {
63	fn as_ref(&self) -> &[u8] {
64		self.0.as_slice()
65	}
66}
67impl<const N: usize, SubTag> TryFrom<&[u8]> for WrappedPublicBytes<N, SubTag> {
68	type Error = ();
69	fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
70		PublicBytes::from_slice(data)
71			.map(|bytes| WrappedPublicBytes(bytes))
72			.map_err(|_| ())
73	}
74}
75impl<const N: usize, SubTag> ByteArray for WrappedPublicBytes<N, SubTag> {
76	fn as_slice(&self) -> &[u8] {
77		self.0.as_slice()
78	}
79	const LEN: usize = N;
80	fn from_slice(data: &[u8]) -> Result<Self, ()> {
81		PublicBytes::from_slice(data)
82			.map(|bytes| WrappedPublicBytes(bytes))
83			.map_err(|_| ())
84	}
85	fn to_raw_vec(&self) -> Vec<u8> {
86		self.0.as_slice().to_vec()
87	}
88}
89impl<const N: usize, SubTag> CryptoType for WrappedPublicBytes<N, SubTag> {
90	type Pair = DilithiumPair;
91}
92impl<const N: usize, SubTag: Clone + Eq> Public for WrappedPublicBytes<N, SubTag> {}
93
94impl<const N: usize, SubTag> Default for WrappedPublicBytes<N, SubTag> {
95	fn default() -> Self {
96		WrappedPublicBytes(PublicBytes::default())
97	}
98}
99impl<const N: usize, SubTag> alloc::fmt::Debug for WrappedPublicBytes<N, SubTag> {
100	#[cfg(feature = "std")]
101	fn fmt(&self, f: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
102		use sp_core::bytes::to_hex;
103
104		write!(f, "{}", to_hex(&self.0.as_ref(), false))
105	}
106
107	#[cfg(not(feature = "std"))]
108	fn fmt(&self, _: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
109		Ok(())
110	}
111}
112
113impl IdentifyAccount for DilithiumPublic {
114	type AccountId = AccountId32;
115	fn into_account(self) -> Self::AccountId {
116		AccountId32::new(PoseidonHasher::hash(self.0.as_slice()).0)
117	}
118}
119
120pub struct WormholeAddress(pub H256);
121
122// AccountID32 for a wormhole address is the same as the address itself
123impl IdentifyAccount for WormholeAddress {
124	type AccountId = AccountId32;
125	fn into_account(self) -> Self::AccountId {
126		AccountId32::new(self.0.as_bytes().try_into().unwrap())
127	}
128}
129
130//
131// Trait implementations for WrappedSignatureBytes
132//
133impl<const N: usize, SubTag> Derive for WrappedSignatureBytes<N, SubTag> {}
134impl<const N: usize, SubTag> AsMut<[u8]> for WrappedSignatureBytes<N, SubTag> {
135	fn as_mut(&mut self) -> &mut [u8] {
136		self.0.as_mut()
137	}
138}
139impl<const N: usize, SubTag> AsRef<[u8]> for WrappedSignatureBytes<N, SubTag> {
140	fn as_ref(&self) -> &[u8] {
141		self.0.as_slice()
142	}
143}
144impl<const N: usize, SubTag> TryFrom<&[u8]> for WrappedSignatureBytes<N, SubTag> {
145	type Error = ();
146	fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
147		SignatureBytes::from_slice(data)
148			.map(|bytes| WrappedSignatureBytes(bytes))
149			.map_err(|_| ())
150	}
151}
152impl<const N: usize, SubTag> ByteArray for WrappedSignatureBytes<N, SubTag> {
153	fn as_slice(&self) -> &[u8] {
154		self.0.as_slice()
155	}
156	const LEN: usize = N;
157	fn from_slice(data: &[u8]) -> Result<Self, ()> {
158		SignatureBytes::from_slice(data)
159			.map(|bytes| WrappedSignatureBytes(bytes))
160			.map_err(|_| ())
161	}
162	fn to_raw_vec(&self) -> Vec<u8> {
163		self.0.as_slice().to_vec()
164	}
165}
166impl<const N: usize, SubTag> CryptoType for WrappedSignatureBytes<N, SubTag> {
167	type Pair = DilithiumPair;
168}
169impl<const N: usize, SubTag: Clone + Eq> Signature for WrappedSignatureBytes<N, SubTag> {}
170
171impl<const N: usize, SubTag> Default for WrappedSignatureBytes<N, SubTag> {
172	fn default() -> Self {
173		WrappedSignatureBytes(SignatureBytes::default())
174	}
175}
176
177impl<const N: usize, SubTag> alloc::fmt::Debug for WrappedSignatureBytes<N, SubTag> {
178	#[cfg(feature = "std")]
179	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
180		use sp_core::bytes::to_hex;
181
182		write!(f, "{}", to_hex(self.0.as_slice(), false))
183	}
184
185	#[cfg(not(feature = "std"))]
186	fn fmt(&self, _: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
187		Ok(())
188	}
189}
190
191//
192// Trait implementations for DilithiumPair
193//
194
195impl CryptoType for DilithiumPair {
196	type Pair = Self;
197}
198
199//
200// Trait implementations for DilithiumSignatureScheme
201//
202
203impl Verify for DilithiumSignatureScheme {
204	type Signer = DilithiumSigner;
205
206	fn verify<L: sp_runtime::traits::Lazy<[u8]>>(
207		&self,
208		mut msg: L,
209		signer: &<Self::Signer as IdentifyAccount>::AccountId,
210	) -> bool {
211		let Self::Dilithium(sig_public) = self;
212		let account = sig_public.public().clone().into_account();
213		if account != *signer {
214			return false;
215		}
216		let result =
217			verify(sig_public.public().as_ref(), msg.get(), sig_public.signature().as_ref());
218		result
219	}
220}
221
222//
223// Trait implementations for DilithiumSigner
224//
225impl From<DilithiumPublic> for DilithiumSigner {
226	fn from(x: DilithiumPublic) -> Self {
227		Self::Dilithium(x)
228	}
229}
230
231impl IdentifyAccount for DilithiumSigner {
232	type AccountId = AccountId32;
233
234	fn into_account(self) -> AccountId32 {
235		let Self::Dilithium(who) = self;
236		PoseidonHasher::hash(who.as_ref()).0.into()
237	}
238}
239
240impl From<DilithiumPublic> for AccountId32 {
241	fn from(public: DilithiumPublic) -> Self {
242		public.into_account()
243	}
244}
245
246//
247// Implementation methods for DilithiumPair
248//
249
250impl DilithiumPair {
251	pub fn from_seed(seed: &[u8]) -> Result<Self, Error> {
252		let keypair = crate::pair::generate(Some(seed))?;
253		Ok(DilithiumPair { secret: keypair.secret.to_bytes(), public: keypair.public.to_bytes() })
254	}
255	pub fn public(&self) -> DilithiumPublic {
256		DilithiumPublic::from_slice(&self.public).expect("Valid public key bytes")
257	}
258}
259
260impl alloc::fmt::Debug for DilithiumSignatureWithPublic {
261	#[cfg(feature = "std")]
262	fn fmt(&self, f: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
263		write!(
264			f,
265			"ResonanceSignatureWithPublic {{ signature: {:?}, public: {:?} }}",
266			self.signature(),
267			self.public()
268		)
269	}
270
271	#[cfg(not(feature = "std"))]
272	fn fmt(&self, f: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
273		write!(f, "ResonanceSignatureWithPublic")
274	}
275}
276
277impl From<DilithiumSignatureWithPublic> for DilithiumSignatureScheme {
278	fn from(x: DilithiumSignatureWithPublic) -> Self {
279		Self::Dilithium(x)
280	}
281}
282
283impl TryFrom<DilithiumSignatureScheme> for DilithiumSignatureWithPublic {
284	type Error = ();
285	fn try_from(m: DilithiumSignatureScheme) -> Result<Self, Self::Error> {
286		let DilithiumSignatureScheme::Dilithium(sig_with_public) = m;
287		Ok(sig_with_public)
288	}
289}
290
291impl AsMut<[u8]> for DilithiumSignatureWithPublic {
292	fn as_mut(&mut self) -> &mut [u8] {
293		self.bytes.as_mut()
294	}
295}
296impl TryFrom<&[u8]> for DilithiumSignatureWithPublic {
297	type Error = ();
298	fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
299		if data.len() != Self::TOTAL_LEN {
300			return Err(());
301		}
302		let (sig_bytes, pub_bytes) = data.split_at(<DilithiumSignature as ByteArray>::LEN);
303		let signature = DilithiumSignature::from_slice(sig_bytes).map_err(|_| ())?;
304		let public = DilithiumPublic::from_slice(pub_bytes).map_err(|_| ())?;
305		Ok(Self::new(signature, public))
306	}
307}
308
309impl ByteArray for DilithiumSignatureWithPublic {
310	const LEN: usize = Self::TOTAL_LEN;
311
312	fn to_raw_vec(&self) -> Vec<u8> {
313		self.to_bytes().to_vec()
314	}
315
316	fn from_slice(data: &[u8]) -> Result<Self, ()> {
317		if data.len() != Self::LEN {
318			return Err(());
319		}
320		let bytes = <[u8; Self::LEN]>::try_from(data).map_err(|_| ())?;
321		Self::from_bytes(&bytes).map_err(|_| ())
322	}
323
324	fn as_slice(&self) -> &[u8] {
325		self.bytes.as_slice()
326	}
327}
328impl AsRef<[u8; Self::LEN]> for DilithiumSignatureWithPublic {
329	fn as_ref(&self) -> &[u8; Self::LEN] {
330		&self.bytes
331	}
332}
333
334impl AsRef<[u8]> for DilithiumSignatureWithPublic {
335	fn as_ref(&self) -> &[u8] {
336		&self.bytes
337	}
338}
339impl Signature for DilithiumSignatureWithPublic {}
340
341impl CryptoType for DilithiumSignatureWithPublic {
342	type Pair = DilithiumPair;
343}