1#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(missing_docs)]
20
21extern crate alloc;
24
25use alloc::vec::Vec;
26use codec::{Decode, DecodeWithMemTracking, 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
33pub type Topic = [u8; 32];
35pub type DecryptionKey = [u8; 32];
37pub type Hash = [u8; 32];
39pub type BlockHash = [u8; 32];
41pub type AccountId = [u8; 32];
43pub type Channel = [u8; 32];
45
46pub 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
68pub mod ed25519 {
70 mod app_ed25519 {
71 use sp_application_crypto::{app_crypto, ed25519, key_types::STATEMENT};
72 app_crypto!(ed25519, STATEMENT);
73 }
74 pub type Public = app_ed25519::Public;
76 #[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#[cfg(feature = "std")]
91pub fn hash_encoded(data: &[u8]) -> [u8; 32] {
92 sp_crypto_hashing::blake2_256(data)
93}
94
95#[derive(
97 Encode, Decode, DecodeWithMemTracking, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq,
98)]
99pub enum Proof {
100 Sr25519 {
102 signature: [u8; 64],
104 signer: [u8; 32],
106 },
107 Ed25519 {
109 signature: [u8; 64],
111 signer: [u8; 32],
113 },
114 Secp256k1Ecdsa {
116 signature: [u8; 65],
118 signer: [u8; 33],
120 },
121 OnChain {
123 who: AccountId,
125 block_hash: BlockHash,
127 event_index: u64,
129 },
130}
131
132impl Proof {
133 pub fn account_id(&self) -> AccountId {
135 match self {
136 Proof::Sr25519 { signer, .. } => *signer,
137 Proof::Ed25519 { signer, .. } => *signer,
138 Proof::Secp256k1Ecdsa { signer, .. } =>
139 <sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer).into(),
140 Proof::OnChain { who, .. } => *who,
141 }
142 }
143}
144
145#[derive(Encode, Decode, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq)]
148#[repr(u8)]
149pub enum Field {
150 AuthenticityProof(Proof) = 0,
152 DecryptionKey(DecryptionKey) = 1,
154 Priority(u32) = 2,
156 Channel(Channel) = 3,
158 Topic1(Topic) = 4,
160 Topic2(Topic) = 5,
162 Topic3(Topic) = 6,
164 Topic4(Topic) = 7,
166 Data(Vec<u8>) = 8,
168}
169
170impl Field {
171 fn discriminant(&self) -> u8 {
172 unsafe { *(self as *const Self as *const u8) }
175 }
176}
177
178#[derive(
180 DecodeWithMemTracking,
181 TypeInfo,
182 sp_core::RuntimeDebug,
183 PassByCodec,
184 Clone,
185 PartialEq,
186 Eq,
187 Default,
188)]
189pub struct Statement {
190 proof: Option<Proof>,
191 decryption_key: Option<DecryptionKey>,
192 channel: Option<Channel>,
193 priority: Option<u32>,
194 num_topics: u8,
195 topics: [Topic; MAX_TOPICS],
196 data: Option<Vec<u8>>,
197}
198
199impl Decode for Statement {
200 fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
201 let num_fields: codec::Compact<u32> = Decode::decode(input)?;
204 let mut tag = 0;
205 let mut statement = Statement::new();
206 for i in 0..num_fields.into() {
207 let field: Field = Decode::decode(input)?;
208 if i > 0 && field.discriminant() <= tag {
209 return Err("Invalid field order or duplicate fields".into())
210 }
211 tag = field.discriminant();
212 match field {
213 Field::AuthenticityProof(p) => statement.set_proof(p),
214 Field::DecryptionKey(key) => statement.set_decryption_key(key),
215 Field::Priority(p) => statement.set_priority(p),
216 Field::Channel(c) => statement.set_channel(c),
217 Field::Topic1(t) => statement.set_topic(0, t),
218 Field::Topic2(t) => statement.set_topic(1, t),
219 Field::Topic3(t) => statement.set_topic(2, t),
220 Field::Topic4(t) => statement.set_topic(3, t),
221 Field::Data(data) => statement.set_plain_data(data),
222 }
223 }
224 Ok(statement)
225 }
226}
227
228impl Encode for Statement {
229 fn encode(&self) -> Vec<u8> {
230 self.encoded(false)
231 }
232}
233
234#[derive(Clone, Copy, PartialEq, Eq, Debug)]
235pub enum SignatureVerificationResult {
237 Valid(AccountId),
239 Invalid,
241 NoSignature,
243}
244
245impl Statement {
246 pub fn new() -> Statement {
248 Default::default()
249 }
250
251 pub fn new_with_proof(proof: Proof) -> Statement {
253 let mut statement = Self::new();
254 statement.set_proof(proof);
255 statement
256 }
257
258 pub fn sign_sr25519_public(&mut self, key: &sr25519::Public) -> bool {
264 let to_sign = self.signature_material();
265 if let Some(signature) = key.sign(&to_sign) {
266 let proof = Proof::Sr25519 {
267 signature: signature.into_inner().into(),
268 signer: key.clone().into_inner().into(),
269 };
270 self.set_proof(proof);
271 true
272 } else {
273 false
274 }
275 }
276
277 #[cfg(feature = "std")]
279 pub fn sign_sr25519_private(&mut self, key: &sp_core::sr25519::Pair) {
280 let to_sign = self.signature_material();
281 let proof =
282 Proof::Sr25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
283 self.set_proof(proof);
284 }
285
286 pub fn sign_ed25519_public(&mut self, key: &ed25519::Public) -> bool {
292 let to_sign = self.signature_material();
293 if let Some(signature) = key.sign(&to_sign) {
294 let proof = Proof::Ed25519 {
295 signature: signature.into_inner().into(),
296 signer: key.clone().into_inner().into(),
297 };
298 self.set_proof(proof);
299 true
300 } else {
301 false
302 }
303 }
304
305 #[cfg(feature = "std")]
307 pub fn sign_ed25519_private(&mut self, key: &sp_core::ed25519::Pair) {
308 let to_sign = self.signature_material();
309 let proof =
310 Proof::Ed25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
311 self.set_proof(proof);
312 }
313
314 pub fn sign_ecdsa_public(&mut self, key: &ecdsa::Public) -> bool {
324 let to_sign = self.signature_material();
325 if let Some(signature) = key.sign(&to_sign) {
326 let proof = Proof::Secp256k1Ecdsa {
327 signature: signature.into_inner().into(),
328 signer: key.clone().into_inner().0,
329 };
330 self.set_proof(proof);
331 true
332 } else {
333 false
334 }
335 }
336
337 #[cfg(feature = "std")]
339 pub fn sign_ecdsa_private(&mut self, key: &sp_core::ecdsa::Pair) {
340 let to_sign = self.signature_material();
341 let proof =
342 Proof::Secp256k1Ecdsa { signature: key.sign(&to_sign).into(), signer: key.public().0 };
343 self.set_proof(proof);
344 }
345
346 pub fn verify_signature(&self) -> SignatureVerificationResult {
348 use sp_runtime::traits::Verify;
349
350 match self.proof() {
351 Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature,
352 Some(Proof::Sr25519 { signature, signer }) => {
353 let to_sign = self.signature_material();
354 let signature = sp_core::sr25519::Signature::from(*signature);
355 let public = sp_core::sr25519::Public::from(*signer);
356 if signature.verify(to_sign.as_slice(), &public) {
357 SignatureVerificationResult::Valid(*signer)
358 } else {
359 SignatureVerificationResult::Invalid
360 }
361 },
362 Some(Proof::Ed25519 { signature, signer }) => {
363 let to_sign = self.signature_material();
364 let signature = sp_core::ed25519::Signature::from(*signature);
365 let public = sp_core::ed25519::Public::from(*signer);
366 if signature.verify(to_sign.as_slice(), &public) {
367 SignatureVerificationResult::Valid(*signer)
368 } else {
369 SignatureVerificationResult::Invalid
370 }
371 },
372 Some(Proof::Secp256k1Ecdsa { signature, signer }) => {
373 let to_sign = self.signature_material();
374 let signature = sp_core::ecdsa::Signature::from(*signature);
375 let public = sp_core::ecdsa::Public::from(*signer);
376 if signature.verify(to_sign.as_slice(), &public) {
377 let sender_hash =
378 <sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer);
379 SignatureVerificationResult::Valid(sender_hash.into())
380 } else {
381 SignatureVerificationResult::Invalid
382 }
383 },
384 }
385 }
386
387 #[cfg(feature = "std")]
389 pub fn hash(&self) -> [u8; 32] {
390 self.using_encoded(hash_encoded)
391 }
392
393 pub fn topic(&self, index: usize) -> Option<Topic> {
395 if index < self.num_topics as usize {
396 Some(self.topics[index])
397 } else {
398 None
399 }
400 }
401
402 pub fn decryption_key(&self) -> Option<DecryptionKey> {
404 self.decryption_key
405 }
406
407 pub fn into_data(self) -> Option<Vec<u8>> {
409 self.data
410 }
411
412 pub fn proof(&self) -> Option<&Proof> {
414 self.proof.as_ref()
415 }
416
417 pub fn account_id(&self) -> Option<AccountId> {
419 self.proof.as_ref().map(Proof::account_id)
420 }
421
422 pub fn data(&self) -> Option<&Vec<u8>> {
424 self.data.as_ref()
425 }
426
427 pub fn data_len(&self) -> usize {
429 self.data().map_or(0, Vec::len)
430 }
431
432 pub fn channel(&self) -> Option<Channel> {
434 self.channel
435 }
436
437 pub fn priority(&self) -> Option<u32> {
439 self.priority
440 }
441
442 fn signature_material(&self) -> Vec<u8> {
444 self.encoded(true)
445 }
446
447 pub fn remove_proof(&mut self) {
449 self.proof = None;
450 }
451
452 pub fn set_proof(&mut self, proof: Proof) {
454 self.proof = Some(proof)
455 }
456
457 pub fn set_priority(&mut self, priority: u32) {
459 self.priority = Some(priority)
460 }
461
462 pub fn set_channel(&mut self, channel: Channel) {
464 self.channel = Some(channel)
465 }
466
467 pub fn set_topic(&mut self, index: usize, topic: Topic) {
469 if index < MAX_TOPICS {
470 self.topics[index] = topic;
471 self.num_topics = self.num_topics.max(index as u8 + 1);
472 }
473 }
474
475 pub fn set_decryption_key(&mut self, key: DecryptionKey) {
477 self.decryption_key = Some(key);
478 }
479
480 pub fn set_plain_data(&mut self, data: Vec<u8>) {
482 self.data = Some(data)
483 }
484
485 fn encoded(&self, for_signing: bool) -> Vec<u8> {
486 let num_fields = if !for_signing && self.proof.is_some() { 1 } else { 0 } +
489 if self.decryption_key.is_some() { 1 } else { 0 } +
490 if self.priority.is_some() { 1 } else { 0 } +
491 if self.channel.is_some() { 1 } else { 0 } +
492 if self.data.is_some() { 1 } else { 0 } +
493 self.num_topics as u32;
494
495 let mut output = Vec::new();
496 if !for_signing {
500 let compact_len = codec::Compact::<u32>(num_fields);
501 compact_len.encode_to(&mut output);
502
503 if let Some(proof) = &self.proof {
504 0u8.encode_to(&mut output);
505 proof.encode_to(&mut output);
506 }
507 }
508 if let Some(decryption_key) = &self.decryption_key {
509 1u8.encode_to(&mut output);
510 decryption_key.encode_to(&mut output);
511 }
512 if let Some(priority) = &self.priority {
513 2u8.encode_to(&mut output);
514 priority.encode_to(&mut output);
515 }
516 if let Some(channel) = &self.channel {
517 3u8.encode_to(&mut output);
518 channel.encode_to(&mut output);
519 }
520 for t in 0..self.num_topics {
521 (4u8 + t).encode_to(&mut output);
522 self.topics[t as usize].encode_to(&mut output);
523 }
524 if let Some(data) = &self.data {
525 8u8.encode_to(&mut output);
526 data.encode_to(&mut output);
527 }
528 output
529 }
530
531 #[cfg(feature = "std")]
533 pub fn encrypt(
534 &mut self,
535 data: &[u8],
536 key: &sp_core::ed25519::Public,
537 ) -> core::result::Result<(), ecies::Error> {
538 let encrypted = ecies::encrypt_ed25519(key, data)?;
539 self.data = Some(encrypted);
540 self.decryption_key = Some((*key).into());
541 Ok(())
542 }
543
544 #[cfg(feature = "std")]
546 pub fn decrypt_private(
547 &self,
548 key: &sp_core::ed25519::Pair,
549 ) -> core::result::Result<Option<Vec<u8>>, ecies::Error> {
550 self.data.as_ref().map(|d| ecies::decrypt_ed25519(key, d)).transpose()
551 }
552}
553
554#[cfg(test)]
555mod test {
556 use crate::{hash_encoded, Field, Proof, SignatureVerificationResult, Statement};
557 use codec::{Decode, Encode};
558 use sp_application_crypto::Pair;
559
560 #[test]
561 fn statement_encoding_matches_vec() {
562 let mut statement = Statement::new();
563 assert!(statement.proof().is_none());
564 let proof = Proof::OnChain { who: [42u8; 32], block_hash: [24u8; 32], event_index: 66 };
565
566 let decryption_key = [0xde; 32];
567 let topic1 = [0x01; 32];
568 let topic2 = [0x02; 32];
569 let data = vec![55, 99];
570 let priority = 999;
571 let channel = [0xcc; 32];
572
573 statement.set_proof(proof.clone());
574 statement.set_decryption_key(decryption_key);
575 statement.set_priority(priority);
576 statement.set_channel(channel);
577 statement.set_topic(0, topic1);
578 statement.set_topic(1, topic2);
579 statement.set_plain_data(data.clone());
580
581 statement.set_topic(5, [0x55; 32]);
582 assert_eq!(statement.topic(5), None);
583
584 let fields = vec![
585 Field::AuthenticityProof(proof.clone()),
586 Field::DecryptionKey(decryption_key),
587 Field::Priority(priority),
588 Field::Channel(channel),
589 Field::Topic1(topic1),
590 Field::Topic2(topic2),
591 Field::Data(data.clone()),
592 ];
593
594 let encoded = statement.encode();
595 assert_eq!(statement.hash(), hash_encoded(&encoded));
596 assert_eq!(encoded, fields.encode());
597
598 let decoded = Statement::decode(&mut encoded.as_slice()).unwrap();
599 assert_eq!(decoded, statement);
600 }
601
602 #[test]
603 fn decode_checks_fields() {
604 let topic1 = [0x01; 32];
605 let topic2 = [0x02; 32];
606 let priority = 999;
607
608 let fields = vec![
609 Field::Priority(priority),
610 Field::Topic1(topic1),
611 Field::Topic1(topic1),
612 Field::Topic2(topic2),
613 ]
614 .encode();
615
616 assert!(Statement::decode(&mut fields.as_slice()).is_err());
617
618 let fields =
619 vec![Field::Topic1(topic1), Field::Priority(priority), Field::Topic2(topic2)].encode();
620
621 assert!(Statement::decode(&mut fields.as_slice()).is_err());
622 }
623
624 #[test]
625 fn sign_and_verify() {
626 let mut statement = Statement::new();
627 statement.set_plain_data(vec![42]);
628
629 let sr25519_kp = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap();
630 let ed25519_kp = sp_core::ed25519::Pair::from_string("//Alice", None).unwrap();
631 let secp256k1_kp = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
632
633 statement.sign_sr25519_private(&sr25519_kp);
634 assert_eq!(
635 statement.verify_signature(),
636 SignatureVerificationResult::Valid(sr25519_kp.public().0)
637 );
638
639 statement.sign_ed25519_private(&ed25519_kp);
640 assert_eq!(
641 statement.verify_signature(),
642 SignatureVerificationResult::Valid(ed25519_kp.public().0)
643 );
644
645 statement.sign_ecdsa_private(&secp256k1_kp);
646 assert_eq!(
647 statement.verify_signature(),
648 SignatureVerificationResult::Valid(sp_crypto_hashing::blake2_256(
649 &secp256k1_kp.public().0
650 ))
651 );
652
653 statement.set_proof(Proof::Sr25519 { signature: [0u8; 64], signer: [0u8; 32] });
655 assert_eq!(statement.verify_signature(), SignatureVerificationResult::Invalid);
656
657 statement.remove_proof();
658 assert_eq!(statement.verify_signature(), SignatureVerificationResult::NoSignature);
659 }
660
661 #[test]
662 fn encrypt_decrypt() {
663 let mut statement = Statement::new();
664 let (pair, _) = sp_core::ed25519::Pair::generate();
665 let plain = b"test data".to_vec();
666
667 statement.encrypt(&plain, &pair.public()).unwrap();
669 assert_ne!(plain.as_slice(), statement.data().unwrap().as_slice());
670
671 let decrypted = statement.decrypt_private(&pair).unwrap();
672 assert_eq!(decrypted, Some(plain));
673 }
674}