sp_statement_store/
lib.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#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(missing_docs)]
20
21//! A crate which contains statement-store primitives.
22
23extern crate alloc;
24
25use alloc::vec::Vec;
26use codec::{Decode, Encode};
27use scale_info::TypeInfo;
28use sp_application_crypto::RuntimeAppPublic;
29#[cfg(feature = "std")]
30use sp_core::Pair;
31use sp_runtime_interface::pass_by::PassByCodec;
32
33/// Statement topic.
34pub type Topic = [u8; 32];
35/// Decryption key identifier.
36pub type DecryptionKey = [u8; 32];
37/// Statement hash.
38pub type Hash = [u8; 32];
39/// Block hash.
40pub type BlockHash = [u8; 32];
41/// Account id
42pub type AccountId = [u8; 32];
43/// Statement channel.
44pub type Channel = [u8; 32];
45
46/// Total number of topic fields allowed.
47pub const MAX_TOPICS: usize = 4;
48
49#[cfg(feature = "std")]
50pub use store_api::{
51	Error, NetworkPriority, Result, StatementSource, StatementStore, SubmitResult,
52};
53
54#[cfg(feature = "std")]
55mod ecies;
56pub mod runtime_api;
57#[cfg(feature = "std")]
58mod store_api;
59
60mod sr25519 {
61	mod app_sr25519 {
62		use sp_application_crypto::{app_crypto, key_types::STATEMENT, sr25519};
63		app_crypto!(sr25519, STATEMENT);
64	}
65	pub type Public = app_sr25519::Public;
66}
67
68/// Statement-store specific ed25519 crypto primitives.
69pub mod ed25519 {
70	mod app_ed25519 {
71		use sp_application_crypto::{app_crypto, ed25519, key_types::STATEMENT};
72		app_crypto!(ed25519, STATEMENT);
73	}
74	/// Statement-store specific ed25519 public key.
75	pub type Public = app_ed25519::Public;
76	/// Statement-store specific ed25519 key pair.
77	#[cfg(feature = "std")]
78	pub type Pair = app_ed25519::Pair;
79}
80
81mod ecdsa {
82	mod app_ecdsa {
83		use sp_application_crypto::{app_crypto, ecdsa, key_types::STATEMENT};
84		app_crypto!(ecdsa, STATEMENT);
85	}
86	pub type Public = app_ecdsa::Public;
87}
88
89/// Returns blake2-256 hash for the encoded statement.
90#[cfg(feature = "std")]
91pub fn hash_encoded(data: &[u8]) -> [u8; 32] {
92	sp_crypto_hashing::blake2_256(data)
93}
94
95/// Statement proof.
96#[derive(Encode, Decode, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq)]
97pub enum Proof {
98	/// Sr25519 Signature.
99	Sr25519 {
100		/// Signature.
101		signature: [u8; 64],
102		/// Public key.
103		signer: [u8; 32],
104	},
105	/// Ed25519 Signature.
106	Ed25519 {
107		/// Signature.
108		signature: [u8; 64],
109		/// Public key.
110		signer: [u8; 32],
111	},
112	/// Secp256k1 Signature.
113	Secp256k1Ecdsa {
114		/// Signature.
115		signature: [u8; 65],
116		/// Public key.
117		signer: [u8; 33],
118	},
119	/// On-chain event proof.
120	OnChain {
121		/// Account identifier associated with the event.
122		who: AccountId,
123		/// Hash of block that contains the event.
124		block_hash: BlockHash,
125		/// Index of the event in the event list.
126		event_index: u64,
127	},
128}
129
130impl Proof {
131	/// Return account id for the proof creator.
132	pub fn account_id(&self) -> AccountId {
133		match self {
134			Proof::Sr25519 { signer, .. } => *signer,
135			Proof::Ed25519 { signer, .. } => *signer,
136			Proof::Secp256k1Ecdsa { signer, .. } =>
137				<sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer).into(),
138			Proof::OnChain { who, .. } => *who,
139		}
140	}
141}
142
143/// Statement attributes. Each statement is a list of 0 or more fields. Fields may only appear once
144/// and in the order declared here.
145#[derive(Encode, Decode, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq)]
146#[repr(u8)]
147pub enum Field {
148	/// Statement proof.
149	AuthenticityProof(Proof) = 0,
150	/// An identifier for the key that `Data` field may be decrypted with.
151	DecryptionKey(DecryptionKey) = 1,
152	/// Priority when competing with other messages from the same sender.
153	Priority(u32) = 2,
154	/// Account channel to use. Only one message per `(account, channel)` pair is allowed.
155	Channel(Channel) = 3,
156	/// First statement topic.
157	Topic1(Topic) = 4,
158	/// Second statement topic.
159	Topic2(Topic) = 5,
160	/// Third statement topic.
161	Topic3(Topic) = 6,
162	/// Fourth statement topic.
163	Topic4(Topic) = 7,
164	/// Additional data.
165	Data(Vec<u8>) = 8,
166}
167
168impl Field {
169	fn discriminant(&self) -> u8 {
170		// This is safe for repr(u8)
171		// see https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting
172		unsafe { *(self as *const Self as *const u8) }
173	}
174}
175
176/// Statement structure.
177#[derive(TypeInfo, sp_core::RuntimeDebug, PassByCodec, Clone, PartialEq, Eq, Default)]
178pub struct Statement {
179	proof: Option<Proof>,
180	decryption_key: Option<DecryptionKey>,
181	channel: Option<Channel>,
182	priority: Option<u32>,
183	num_topics: u8,
184	topics: [Topic; MAX_TOPICS],
185	data: Option<Vec<u8>>,
186}
187
188impl Decode for Statement {
189	fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
190		// Encoding matches that of Vec<Field>. Basically this just means accepting that there
191		// will be a prefix of vector length.
192		let num_fields: codec::Compact<u32> = Decode::decode(input)?;
193		let mut tag = 0;
194		let mut statement = Statement::new();
195		for i in 0..num_fields.into() {
196			let field: Field = Decode::decode(input)?;
197			if i > 0 && field.discriminant() <= tag {
198				return Err("Invalid field order or duplicate fields".into())
199			}
200			tag = field.discriminant();
201			match field {
202				Field::AuthenticityProof(p) => statement.set_proof(p),
203				Field::DecryptionKey(key) => statement.set_decryption_key(key),
204				Field::Priority(p) => statement.set_priority(p),
205				Field::Channel(c) => statement.set_channel(c),
206				Field::Topic1(t) => statement.set_topic(0, t),
207				Field::Topic2(t) => statement.set_topic(1, t),
208				Field::Topic3(t) => statement.set_topic(2, t),
209				Field::Topic4(t) => statement.set_topic(3, t),
210				Field::Data(data) => statement.set_plain_data(data),
211			}
212		}
213		Ok(statement)
214	}
215}
216
217impl Encode for Statement {
218	fn encode(&self) -> Vec<u8> {
219		self.encoded(false)
220	}
221}
222
223#[derive(Clone, Copy, PartialEq, Eq, Debug)]
224/// Result returned by `Statement::verify_signature`
225pub enum SignatureVerificationResult {
226	/// Signature is valid and matches this account id.
227	Valid(AccountId),
228	/// Signature has failed verification.
229	Invalid,
230	/// No signature in the proof or no proof.
231	NoSignature,
232}
233
234impl Statement {
235	/// Create a new empty statement with no proof.
236	pub fn new() -> Statement {
237		Default::default()
238	}
239
240	/// Create a new statement with a proof.
241	pub fn new_with_proof(proof: Proof) -> Statement {
242		let mut statement = Self::new();
243		statement.set_proof(proof);
244		statement
245	}
246
247	/// Sign with a key that matches given public key in the keystore.
248	///
249	/// Returns `true` if signing worked (private key present etc).
250	///
251	/// NOTE: This can only be called from the runtime.
252	pub fn sign_sr25519_public(&mut self, key: &sr25519::Public) -> bool {
253		let to_sign = self.signature_material();
254		if let Some(signature) = key.sign(&to_sign) {
255			let proof = Proof::Sr25519 {
256				signature: signature.into_inner().into(),
257				signer: key.clone().into_inner().into(),
258			};
259			self.set_proof(proof);
260			true
261		} else {
262			false
263		}
264	}
265
266	/// Sign with a given private key and add the signature proof field.
267	#[cfg(feature = "std")]
268	pub fn sign_sr25519_private(&mut self, key: &sp_core::sr25519::Pair) {
269		let to_sign = self.signature_material();
270		let proof =
271			Proof::Sr25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
272		self.set_proof(proof);
273	}
274
275	/// Sign with a key that matches given public key in the keystore.
276	///
277	/// Returns `true` if signing worked (private key present etc).
278	///
279	/// NOTE: This can only be called from the runtime.
280	pub fn sign_ed25519_public(&mut self, key: &ed25519::Public) -> bool {
281		let to_sign = self.signature_material();
282		if let Some(signature) = key.sign(&to_sign) {
283			let proof = Proof::Ed25519 {
284				signature: signature.into_inner().into(),
285				signer: key.clone().into_inner().into(),
286			};
287			self.set_proof(proof);
288			true
289		} else {
290			false
291		}
292	}
293
294	/// Sign with a given private key and add the signature proof field.
295	#[cfg(feature = "std")]
296	pub fn sign_ed25519_private(&mut self, key: &sp_core::ed25519::Pair) {
297		let to_sign = self.signature_material();
298		let proof =
299			Proof::Ed25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
300		self.set_proof(proof);
301	}
302
303	/// Sign with a key that matches given public key in the keystore.
304	///
305	/// Returns `true` if signing worked (private key present etc).
306	///
307	/// NOTE: This can only be called from the runtime.
308	///
309	/// Returns `true` if signing worked (private key present etc).
310	///
311	/// NOTE: This can only be called from the runtime.
312	pub fn sign_ecdsa_public(&mut self, key: &ecdsa::Public) -> bool {
313		let to_sign = self.signature_material();
314		if let Some(signature) = key.sign(&to_sign) {
315			let proof = Proof::Secp256k1Ecdsa {
316				signature: signature.into_inner().into(),
317				signer: key.clone().into_inner().0,
318			};
319			self.set_proof(proof);
320			true
321		} else {
322			false
323		}
324	}
325
326	/// Sign with a given private key and add the signature proof field.
327	#[cfg(feature = "std")]
328	pub fn sign_ecdsa_private(&mut self, key: &sp_core::ecdsa::Pair) {
329		let to_sign = self.signature_material();
330		let proof =
331			Proof::Secp256k1Ecdsa { signature: key.sign(&to_sign).into(), signer: key.public().0 };
332		self.set_proof(proof);
333	}
334
335	/// Check proof signature, if any.
336	pub fn verify_signature(&self) -> SignatureVerificationResult {
337		use sp_runtime::traits::Verify;
338
339		match self.proof() {
340			Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature,
341			Some(Proof::Sr25519 { signature, signer }) => {
342				let to_sign = self.signature_material();
343				let signature = sp_core::sr25519::Signature::from(*signature);
344				let public = sp_core::sr25519::Public::from(*signer);
345				if signature.verify(to_sign.as_slice(), &public) {
346					SignatureVerificationResult::Valid(*signer)
347				} else {
348					SignatureVerificationResult::Invalid
349				}
350			},
351			Some(Proof::Ed25519 { signature, signer }) => {
352				let to_sign = self.signature_material();
353				let signature = sp_core::ed25519::Signature::from(*signature);
354				let public = sp_core::ed25519::Public::from(*signer);
355				if signature.verify(to_sign.as_slice(), &public) {
356					SignatureVerificationResult::Valid(*signer)
357				} else {
358					SignatureVerificationResult::Invalid
359				}
360			},
361			Some(Proof::Secp256k1Ecdsa { signature, signer }) => {
362				let to_sign = self.signature_material();
363				let signature = sp_core::ecdsa::Signature::from(*signature);
364				let public = sp_core::ecdsa::Public::from(*signer);
365				if signature.verify(to_sign.as_slice(), &public) {
366					let sender_hash =
367						<sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer);
368					SignatureVerificationResult::Valid(sender_hash.into())
369				} else {
370					SignatureVerificationResult::Invalid
371				}
372			},
373		}
374	}
375
376	/// Calculate statement hash.
377	#[cfg(feature = "std")]
378	pub fn hash(&self) -> [u8; 32] {
379		self.using_encoded(hash_encoded)
380	}
381
382	/// Returns a topic by topic index.
383	pub fn topic(&self, index: usize) -> Option<Topic> {
384		if index < self.num_topics as usize {
385			Some(self.topics[index])
386		} else {
387			None
388		}
389	}
390
391	/// Returns decryption key if any.
392	pub fn decryption_key(&self) -> Option<DecryptionKey> {
393		self.decryption_key
394	}
395
396	/// Convert to internal data.
397	pub fn into_data(self) -> Option<Vec<u8>> {
398		self.data
399	}
400
401	/// Get a reference to the statement proof, if any.
402	pub fn proof(&self) -> Option<&Proof> {
403		self.proof.as_ref()
404	}
405
406	/// Get proof account id, if any
407	pub fn account_id(&self) -> Option<AccountId> {
408		self.proof.as_ref().map(Proof::account_id)
409	}
410
411	/// Get plain data.
412	pub fn data(&self) -> Option<&Vec<u8>> {
413		self.data.as_ref()
414	}
415
416	/// Get plain data len.
417	pub fn data_len(&self) -> usize {
418		self.data().map_or(0, Vec::len)
419	}
420
421	/// Get channel, if any.
422	pub fn channel(&self) -> Option<Channel> {
423		self.channel
424	}
425
426	/// Get priority, if any.
427	pub fn priority(&self) -> Option<u32> {
428		self.priority
429	}
430
431	/// Return encoded fields that can be signed to construct or verify a proof
432	fn signature_material(&self) -> Vec<u8> {
433		self.encoded(true)
434	}
435
436	/// Remove the proof of this statement.
437	pub fn remove_proof(&mut self) {
438		self.proof = None;
439	}
440
441	/// Set statement proof. Any existing proof is overwritten.
442	pub fn set_proof(&mut self, proof: Proof) {
443		self.proof = Some(proof)
444	}
445
446	/// Set statement priority.
447	pub fn set_priority(&mut self, priority: u32) {
448		self.priority = Some(priority)
449	}
450
451	/// Set statement channel.
452	pub fn set_channel(&mut self, channel: Channel) {
453		self.channel = Some(channel)
454	}
455
456	/// Set topic by index. Does noting if index is over `MAX_TOPICS`.
457	pub fn set_topic(&mut self, index: usize, topic: Topic) {
458		if index < MAX_TOPICS {
459			self.topics[index] = topic;
460			self.num_topics = self.num_topics.max(index as u8 + 1);
461		}
462	}
463
464	/// Set decryption key.
465	pub fn set_decryption_key(&mut self, key: DecryptionKey) {
466		self.decryption_key = Some(key);
467	}
468
469	/// Set unencrypted statement data.
470	pub fn set_plain_data(&mut self, data: Vec<u8>) {
471		self.data = Some(data)
472	}
473
474	fn encoded(&self, for_signing: bool) -> Vec<u8> {
475		// Encoding matches that of Vec<Field>. Basically this just means accepting that there
476		// will be a prefix of vector length.
477		let num_fields = if !for_signing && self.proof.is_some() { 1 } else { 0 } +
478			if self.decryption_key.is_some() { 1 } else { 0 } +
479			if self.priority.is_some() { 1 } else { 0 } +
480			if self.channel.is_some() { 1 } else { 0 } +
481			if self.data.is_some() { 1 } else { 0 } +
482			self.num_topics as u32;
483
484		let mut output = Vec::new();
485		// When encoding signature payload, the length prefix is omitted.
486		// This is so that the signature for encoded statement can potentially be derived without
487		// needing to re-encode the statement.
488		if !for_signing {
489			let compact_len = codec::Compact::<u32>(num_fields);
490			compact_len.encode_to(&mut output);
491
492			if let Some(proof) = &self.proof {
493				0u8.encode_to(&mut output);
494				proof.encode_to(&mut output);
495			}
496		}
497		if let Some(decryption_key) = &self.decryption_key {
498			1u8.encode_to(&mut output);
499			decryption_key.encode_to(&mut output);
500		}
501		if let Some(priority) = &self.priority {
502			2u8.encode_to(&mut output);
503			priority.encode_to(&mut output);
504		}
505		if let Some(channel) = &self.channel {
506			3u8.encode_to(&mut output);
507			channel.encode_to(&mut output);
508		}
509		for t in 0..self.num_topics {
510			(4u8 + t).encode_to(&mut output);
511			self.topics[t as usize].encode_to(&mut output);
512		}
513		if let Some(data) = &self.data {
514			8u8.encode_to(&mut output);
515			data.encode_to(&mut output);
516		}
517		output
518	}
519
520	/// Encrypt give data with given key and store both in the statements.
521	#[cfg(feature = "std")]
522	pub fn encrypt(
523		&mut self,
524		data: &[u8],
525		key: &sp_core::ed25519::Public,
526	) -> core::result::Result<(), ecies::Error> {
527		let encrypted = ecies::encrypt_ed25519(key, data)?;
528		self.data = Some(encrypted);
529		self.decryption_key = Some((*key).into());
530		Ok(())
531	}
532
533	/// Decrypt data (if any) with the given private key.
534	#[cfg(feature = "std")]
535	pub fn decrypt_private(
536		&self,
537		key: &sp_core::ed25519::Pair,
538	) -> core::result::Result<Option<Vec<u8>>, ecies::Error> {
539		self.data.as_ref().map(|d| ecies::decrypt_ed25519(key, d)).transpose()
540	}
541}
542
543#[cfg(test)]
544mod test {
545	use crate::{hash_encoded, Field, Proof, SignatureVerificationResult, Statement};
546	use codec::{Decode, Encode};
547	use sp_application_crypto::Pair;
548
549	#[test]
550	fn statement_encoding_matches_vec() {
551		let mut statement = Statement::new();
552		assert!(statement.proof().is_none());
553		let proof = Proof::OnChain { who: [42u8; 32], block_hash: [24u8; 32], event_index: 66 };
554
555		let decryption_key = [0xde; 32];
556		let topic1 = [0x01; 32];
557		let topic2 = [0x02; 32];
558		let data = vec![55, 99];
559		let priority = 999;
560		let channel = [0xcc; 32];
561
562		statement.set_proof(proof.clone());
563		statement.set_decryption_key(decryption_key);
564		statement.set_priority(priority);
565		statement.set_channel(channel);
566		statement.set_topic(0, topic1);
567		statement.set_topic(1, topic2);
568		statement.set_plain_data(data.clone());
569
570		statement.set_topic(5, [0x55; 32]);
571		assert_eq!(statement.topic(5), None);
572
573		let fields = vec![
574			Field::AuthenticityProof(proof.clone()),
575			Field::DecryptionKey(decryption_key),
576			Field::Priority(priority),
577			Field::Channel(channel),
578			Field::Topic1(topic1),
579			Field::Topic2(topic2),
580			Field::Data(data.clone()),
581		];
582
583		let encoded = statement.encode();
584		assert_eq!(statement.hash(), hash_encoded(&encoded));
585		assert_eq!(encoded, fields.encode());
586
587		let decoded = Statement::decode(&mut encoded.as_slice()).unwrap();
588		assert_eq!(decoded, statement);
589	}
590
591	#[test]
592	fn decode_checks_fields() {
593		let topic1 = [0x01; 32];
594		let topic2 = [0x02; 32];
595		let priority = 999;
596
597		let fields = vec![
598			Field::Priority(priority),
599			Field::Topic1(topic1),
600			Field::Topic1(topic1),
601			Field::Topic2(topic2),
602		]
603		.encode();
604
605		assert!(Statement::decode(&mut fields.as_slice()).is_err());
606
607		let fields =
608			vec![Field::Topic1(topic1), Field::Priority(priority), Field::Topic2(topic2)].encode();
609
610		assert!(Statement::decode(&mut fields.as_slice()).is_err());
611	}
612
613	#[test]
614	fn sign_and_verify() {
615		let mut statement = Statement::new();
616		statement.set_plain_data(vec![42]);
617
618		let sr25519_kp = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap();
619		let ed25519_kp = sp_core::ed25519::Pair::from_string("//Alice", None).unwrap();
620		let secp256k1_kp = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
621
622		statement.sign_sr25519_private(&sr25519_kp);
623		assert_eq!(
624			statement.verify_signature(),
625			SignatureVerificationResult::Valid(sr25519_kp.public().0)
626		);
627
628		statement.sign_ed25519_private(&ed25519_kp);
629		assert_eq!(
630			statement.verify_signature(),
631			SignatureVerificationResult::Valid(ed25519_kp.public().0)
632		);
633
634		statement.sign_ecdsa_private(&secp256k1_kp);
635		assert_eq!(
636			statement.verify_signature(),
637			SignatureVerificationResult::Valid(sp_crypto_hashing::blake2_256(
638				&secp256k1_kp.public().0
639			))
640		);
641
642		// set an invalid signature
643		statement.set_proof(Proof::Sr25519 { signature: [0u8; 64], signer: [0u8; 32] });
644		assert_eq!(statement.verify_signature(), SignatureVerificationResult::Invalid);
645
646		statement.remove_proof();
647		assert_eq!(statement.verify_signature(), SignatureVerificationResult::NoSignature);
648	}
649
650	#[test]
651	fn encrypt_decrypt() {
652		let mut statement = Statement::new();
653		let (pair, _) = sp_core::ed25519::Pair::generate();
654		let plain = b"test data".to_vec();
655
656		//let sr25519_kp = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap();
657		statement.encrypt(&plain, &pair.public()).unwrap();
658		assert_ne!(plain.as_slice(), statement.data().unwrap().as_slice());
659
660		let decrypted = statement.decrypt_private(&pair).unwrap();
661		assert_eq!(decrypted, Some(plain));
662	}
663}