referrerpolicy=no-referrer-when-downgrade

sp_core/
crypto_bytes.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Generic byte array which can be specialized with a marker type.
19
20use crate::{
21	crypto::{CryptoType, Derive, FromEntropy, Public, Signature, UncheckedFrom},
22	hash::{H256, H512},
23};
24
25use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
26use core::marker::PhantomData;
27use scale_info::TypeInfo;
28
29#[cfg(feature = "serde")]
30use crate::crypto::Ss58Codec;
31#[cfg(feature = "serde")]
32use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
33
34#[cfg(all(not(feature = "std"), feature = "serde"))]
35use alloc::{format, string::String};
36
37pub use public_bytes::*;
38pub use signature_bytes::*;
39
40/// Generic byte array holding some crypto-related raw data.
41///
42/// The type is generic over a constant length `N` and a "tag" `T` which
43/// can be used to specialize the byte array without requiring newtypes.
44///
45/// The tag `T` is held in a `PhantomData<fn() ->T>`, a trick allowing
46/// `CryptoBytes` to be `Send` and `Sync` regardless of `T` properties
47/// ([ref](https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns)).
48#[derive(Encode, Decode, DecodeWithMemTracking, MaxEncodedLen)]
49#[repr(transparent)]
50pub struct CryptoBytes<const N: usize, T = ()>(pub [u8; N], PhantomData<fn() -> T>);
51
52impl<const N: usize, T> Copy for CryptoBytes<N, T> {}
53
54impl<const N: usize, T> Clone for CryptoBytes<N, T> {
55	fn clone(&self) -> Self {
56		Self(self.0, PhantomData)
57	}
58}
59
60impl<const N: usize, T> TypeInfo for CryptoBytes<N, T> {
61	type Identity = [u8; N];
62
63	fn type_info() -> scale_info::Type {
64		Self::Identity::type_info()
65	}
66}
67
68impl<const N: usize, T> PartialOrd for CryptoBytes<N, T> {
69	fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
70		self.0.partial_cmp(&other.0)
71	}
72}
73
74impl<const N: usize, T> Ord for CryptoBytes<N, T> {
75	fn cmp(&self, other: &Self) -> core::cmp::Ordering {
76		self.0.cmp(&other.0)
77	}
78}
79
80impl<const N: usize, T> PartialEq for CryptoBytes<N, T> {
81	fn eq(&self, other: &Self) -> bool {
82		self.0.eq(&other.0)
83	}
84}
85
86impl<const N: usize, T> core::hash::Hash for CryptoBytes<N, T> {
87	fn hash<H: scale_info::prelude::hash::Hasher>(&self, state: &mut H) {
88		self.0.hash(state)
89	}
90}
91
92impl<const N: usize, T> Eq for CryptoBytes<N, T> {}
93
94impl<const N: usize, T> Default for CryptoBytes<N, T> {
95	fn default() -> Self {
96		Self([0_u8; N], PhantomData)
97	}
98}
99
100impl<const N: usize, T> AsRef<[u8]> for CryptoBytes<N, T> {
101	fn as_ref(&self) -> &[u8] {
102		&self.0[..]
103	}
104}
105
106impl<const N: usize, T> AsMut<[u8]> for CryptoBytes<N, T> {
107	fn as_mut(&mut self) -> &mut [u8] {
108		&mut self.0[..]
109	}
110}
111
112impl<const N: usize, T> From<CryptoBytes<N, T>> for [u8; N] {
113	fn from(v: CryptoBytes<N, T>) -> [u8; N] {
114		v.0
115	}
116}
117
118impl<const N: usize, T> AsRef<[u8; N]> for CryptoBytes<N, T> {
119	fn as_ref(&self) -> &[u8; N] {
120		&self.0
121	}
122}
123
124impl<const N: usize, T> AsMut<[u8; N]> for CryptoBytes<N, T> {
125	fn as_mut(&mut self) -> &mut [u8; N] {
126		&mut self.0
127	}
128}
129
130impl<const N: usize, T> From<[u8; N]> for CryptoBytes<N, T> {
131	fn from(value: [u8; N]) -> Self {
132		Self::from_raw(value)
133	}
134}
135
136impl<const N: usize, T> TryFrom<&[u8]> for CryptoBytes<N, T> {
137	type Error = ();
138
139	fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
140		if data.len() != N {
141			return Err(())
142		}
143		let mut r = [0u8; N];
144		r.copy_from_slice(data);
145		Ok(Self::from_raw(r))
146	}
147}
148
149impl<const N: usize, T> UncheckedFrom<[u8; N]> for CryptoBytes<N, T> {
150	fn unchecked_from(data: [u8; N]) -> Self {
151		Self::from_raw(data)
152	}
153}
154
155impl<const N: usize, T> core::ops::Deref for CryptoBytes<N, T> {
156	type Target = [u8];
157
158	fn deref(&self) -> &Self::Target {
159		&self.0
160	}
161}
162
163impl<const N: usize, T> CryptoBytes<N, T> {
164	/// Construct from raw array.
165	pub fn from_raw(inner: [u8; N]) -> Self {
166		Self(inner, PhantomData)
167	}
168
169	/// Construct from raw array.
170	pub fn to_raw(self) -> [u8; N] {
171		self.0
172	}
173
174	/// Return a slice filled with raw data.
175	pub fn as_array_ref(&self) -> &[u8; N] {
176		&self.0
177	}
178}
179
180impl<const N: usize, T> crate::ByteArray for CryptoBytes<N, T> {
181	const LEN: usize = N;
182}
183
184impl<const N: usize, T> FromEntropy for CryptoBytes<N, T> {
185	fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
186		let mut result = Self::default();
187		input.read(result.as_mut())?;
188		Ok(result)
189	}
190}
191
192impl<T> From<CryptoBytes<32, T>> for H256 {
193	fn from(x: CryptoBytes<32, T>) -> H256 {
194		H256::from(x.0)
195	}
196}
197
198impl<T> From<CryptoBytes<64, T>> for H512 {
199	fn from(x: CryptoBytes<64, T>) -> H512 {
200		H512::from(x.0)
201	}
202}
203
204impl<T> UncheckedFrom<H256> for CryptoBytes<32, T> {
205	fn unchecked_from(x: H256) -> Self {
206		Self::from_h256(x)
207	}
208}
209
210impl<T> CryptoBytes<32, T> {
211	/// A new instance from an H256.
212	pub fn from_h256(x: H256) -> Self {
213		Self::from_raw(x.into())
214	}
215}
216
217impl<T> CryptoBytes<64, T> {
218	/// A new instance from an H512.
219	pub fn from_h512(x: H512) -> Self {
220		Self::from_raw(x.into())
221	}
222}
223
224mod public_bytes {
225	use super::*;
226
227	/// Tag used for generic public key bytes.
228	pub struct PublicTag;
229
230	/// Generic encoded public key.
231	pub type PublicBytes<const N: usize, SubTag> = CryptoBytes<N, (PublicTag, SubTag)>;
232
233	impl<const N: usize, SubTag> Derive for PublicBytes<N, SubTag> where Self: CryptoType {}
234
235	impl<const N: usize, SubTag> Public for PublicBytes<N, SubTag> where Self: CryptoType {}
236
237	impl<const N: usize, SubTag> core::fmt::Debug for PublicBytes<N, SubTag>
238	where
239		Self: CryptoType,
240	{
241		#[cfg(feature = "std")]
242		fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
243			let s = self.to_ss58check();
244			write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.as_ref()), &s[0..8])
245		}
246
247		#[cfg(not(feature = "std"))]
248		fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
249			Ok(())
250		}
251	}
252
253	#[cfg(feature = "std")]
254	impl<const N: usize, SubTag> std::fmt::Display for PublicBytes<N, SubTag>
255	where
256		Self: CryptoType,
257	{
258		fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
259			write!(f, "{}", self.to_ss58check())
260		}
261	}
262
263	#[cfg(feature = "std")]
264	impl<const N: usize, SubTag> std::str::FromStr for PublicBytes<N, SubTag>
265	where
266		Self: CryptoType,
267	{
268		type Err = crate::crypto::PublicError;
269
270		fn from_str(s: &str) -> Result<Self, Self::Err> {
271			Self::from_ss58check(s)
272		}
273	}
274
275	#[cfg(feature = "serde")]
276	impl<const N: usize, SubTag> Serialize for PublicBytes<N, SubTag>
277	where
278		Self: CryptoType,
279	{
280		fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
281		where
282			S: Serializer,
283		{
284			serializer.serialize_str(&self.to_ss58check())
285		}
286	}
287
288	#[cfg(feature = "serde")]
289	impl<'de, const N: usize, SubTag> Deserialize<'de> for PublicBytes<N, SubTag>
290	where
291		Self: CryptoType,
292	{
293		fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
294		where
295			D: Deserializer<'de>,
296		{
297			Self::from_ss58check(&String::deserialize(deserializer)?)
298				.map_err(|e| de::Error::custom(format!("{:?}", e)))
299		}
300	}
301}
302
303mod signature_bytes {
304	use super::*;
305
306	/// Tag used for generic signature bytes.
307	pub struct SignatureTag;
308
309	/// Generic encoded signature.
310	pub type SignatureBytes<const N: usize, SubTag> = CryptoBytes<N, (SignatureTag, SubTag)>;
311
312	impl<const N: usize, SubTag> Signature for SignatureBytes<N, SubTag> where Self: CryptoType {}
313
314	#[cfg(feature = "serde")]
315	impl<const N: usize, SubTag> Serialize for SignatureBytes<N, SubTag>
316	where
317		Self: CryptoType,
318	{
319		fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
320		where
321			S: Serializer,
322		{
323			serializer.serialize_str(&array_bytes::bytes2hex("", self))
324		}
325	}
326
327	#[cfg(feature = "serde")]
328	impl<'de, const N: usize, SubTag> Deserialize<'de> for SignatureBytes<N, SubTag>
329	where
330		Self: CryptoType,
331	{
332		fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
333		where
334			D: Deserializer<'de>,
335		{
336			let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?)
337				.map_err(|e| de::Error::custom(format!("{:?}", e)))?;
338			Self::try_from(signature_hex.as_ref())
339				.map_err(|e| de::Error::custom(format!("{:?}", e)))
340		}
341	}
342
343	impl<const N: usize, SubTag> core::fmt::Debug for SignatureBytes<N, SubTag>
344	where
345		Self: CryptoType,
346	{
347		#[cfg(feature = "std")]
348		fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
349			write!(f, "{}", crate::hexdisplay::HexDisplay::from(&&self.0[..]))
350		}
351
352		#[cfg(not(feature = "std"))]
353		fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
354			Ok(())
355		}
356	}
357}