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;
31
32pub type Topic = [u8; 32];
34pub type DecryptionKey = [u8; 32];
36pub type Hash = [u8; 32];
38pub type BlockHash = [u8; 32];
40pub type AccountId = [u8; 32];
42pub type Channel = [u8; 32];
44
45pub const MAX_TOPICS: usize = 4;
47
48#[cfg(feature = "std")]
49pub use store_api::{
50 Error, NetworkPriority, Result, StatementSource, StatementStore, SubmitResult,
51};
52
53#[cfg(feature = "std")]
54mod ecies;
55pub mod runtime_api;
56#[cfg(feature = "std")]
57mod store_api;
58
59mod sr25519 {
60 mod app_sr25519 {
61 use sp_application_crypto::{app_crypto, key_types::STATEMENT, sr25519};
62 app_crypto!(sr25519, STATEMENT);
63 }
64 pub type Public = app_sr25519::Public;
65}
66
67pub mod ed25519 {
69 mod app_ed25519 {
70 use sp_application_crypto::{app_crypto, ed25519, key_types::STATEMENT};
71 app_crypto!(ed25519, STATEMENT);
72 }
73 pub type Public = app_ed25519::Public;
75 #[cfg(feature = "std")]
77 pub type Pair = app_ed25519::Pair;
78}
79
80mod ecdsa {
81 mod app_ecdsa {
82 use sp_application_crypto::{app_crypto, ecdsa, key_types::STATEMENT};
83 app_crypto!(ecdsa, STATEMENT);
84 }
85 pub type Public = app_ecdsa::Public;
86}
87
88#[cfg(feature = "std")]
90pub fn hash_encoded(data: &[u8]) -> [u8; 32] {
91 sp_crypto_hashing::blake2_256(data)
92}
93
94#[derive(
96 Encode, Decode, DecodeWithMemTracking, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq,
97)]
98pub enum Proof {
99 Sr25519 {
101 signature: [u8; 64],
103 signer: [u8; 32],
105 },
106 Ed25519 {
108 signature: [u8; 64],
110 signer: [u8; 32],
112 },
113 Secp256k1Ecdsa {
115 signature: [u8; 65],
117 signer: [u8; 33],
119 },
120 OnChain {
122 who: AccountId,
124 block_hash: BlockHash,
126 event_index: u64,
128 },
129}
130
131impl Proof {
132 pub fn account_id(&self) -> AccountId {
134 match self {
135 Proof::Sr25519 { signer, .. } => *signer,
136 Proof::Ed25519 { signer, .. } => *signer,
137 Proof::Secp256k1Ecdsa { signer, .. } =>
138 <sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer).into(),
139 Proof::OnChain { who, .. } => *who,
140 }
141 }
142}
143
144#[derive(Encode, Decode, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq)]
147#[repr(u8)]
148pub enum Field {
149 AuthenticityProof(Proof) = 0,
151 DecryptionKey(DecryptionKey) = 1,
153 Priority(u32) = 2,
155 Channel(Channel) = 3,
157 Topic1(Topic) = 4,
159 Topic2(Topic) = 5,
161 Topic3(Topic) = 6,
163 Topic4(Topic) = 7,
165 Data(Vec<u8>) = 8,
167}
168
169impl Field {
170 fn discriminant(&self) -> u8 {
171 unsafe { *(self as *const Self as *const u8) }
174 }
175}
176
177#[derive(DecodeWithMemTracking, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq, Default)]
179pub struct Statement {
180 proof: Option<Proof>,
181 decryption_key: Option<DecryptionKey>,
182 channel: Option<Channel>,
183 priority: Option<u32>,
184 num_topics: u8,
185 topics: [Topic; MAX_TOPICS],
186 data: Option<Vec<u8>>,
187}
188
189impl Decode for Statement {
190 fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
191 let num_fields: codec::Compact<u32> = Decode::decode(input)?;
194 let mut tag = 0;
195 let mut statement = Statement::new();
196 for i in 0..num_fields.into() {
197 let field: Field = Decode::decode(input)?;
198 if i > 0 && field.discriminant() <= tag {
199 return Err("Invalid field order or duplicate fields".into())
200 }
201 tag = field.discriminant();
202 match field {
203 Field::AuthenticityProof(p) => statement.set_proof(p),
204 Field::DecryptionKey(key) => statement.set_decryption_key(key),
205 Field::Priority(p) => statement.set_priority(p),
206 Field::Channel(c) => statement.set_channel(c),
207 Field::Topic1(t) => statement.set_topic(0, t),
208 Field::Topic2(t) => statement.set_topic(1, t),
209 Field::Topic3(t) => statement.set_topic(2, t),
210 Field::Topic4(t) => statement.set_topic(3, t),
211 Field::Data(data) => statement.set_plain_data(data),
212 }
213 }
214 Ok(statement)
215 }
216}
217
218impl Encode for Statement {
219 fn encode(&self) -> Vec<u8> {
220 self.encoded(false)
221 }
222}
223
224#[derive(Clone, Copy, PartialEq, Eq, Debug)]
225pub enum SignatureVerificationResult {
227 Valid(AccountId),
229 Invalid,
231 NoSignature,
233}
234
235impl Statement {
236 pub fn new() -> Statement {
238 Default::default()
239 }
240
241 pub fn new_with_proof(proof: Proof) -> Statement {
243 let mut statement = Self::new();
244 statement.set_proof(proof);
245 statement
246 }
247
248 pub fn sign_sr25519_public(&mut self, key: &sr25519::Public) -> bool {
254 let to_sign = self.signature_material();
255 if let Some(signature) = key.sign(&to_sign) {
256 let proof = Proof::Sr25519 {
257 signature: signature.into_inner().into(),
258 signer: key.clone().into_inner().into(),
259 };
260 self.set_proof(proof);
261 true
262 } else {
263 false
264 }
265 }
266
267 #[cfg(feature = "std")]
269 pub fn sign_sr25519_private(&mut self, key: &sp_core::sr25519::Pair) {
270 let to_sign = self.signature_material();
271 let proof =
272 Proof::Sr25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
273 self.set_proof(proof);
274 }
275
276 pub fn sign_ed25519_public(&mut self, key: &ed25519::Public) -> bool {
282 let to_sign = self.signature_material();
283 if let Some(signature) = key.sign(&to_sign) {
284 let proof = Proof::Ed25519 {
285 signature: signature.into_inner().into(),
286 signer: key.clone().into_inner().into(),
287 };
288 self.set_proof(proof);
289 true
290 } else {
291 false
292 }
293 }
294
295 #[cfg(feature = "std")]
297 pub fn sign_ed25519_private(&mut self, key: &sp_core::ed25519::Pair) {
298 let to_sign = self.signature_material();
299 let proof =
300 Proof::Ed25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
301 self.set_proof(proof);
302 }
303
304 pub fn sign_ecdsa_public(&mut self, key: &ecdsa::Public) -> bool {
314 let to_sign = self.signature_material();
315 if let Some(signature) = key.sign(&to_sign) {
316 let proof = Proof::Secp256k1Ecdsa {
317 signature: signature.into_inner().into(),
318 signer: key.clone().into_inner().0,
319 };
320 self.set_proof(proof);
321 true
322 } else {
323 false
324 }
325 }
326
327 #[cfg(feature = "std")]
329 pub fn sign_ecdsa_private(&mut self, key: &sp_core::ecdsa::Pair) {
330 let to_sign = self.signature_material();
331 let proof =
332 Proof::Secp256k1Ecdsa { signature: key.sign(&to_sign).into(), signer: key.public().0 };
333 self.set_proof(proof);
334 }
335
336 pub fn verify_signature(&self) -> SignatureVerificationResult {
338 use sp_runtime::traits::Verify;
339
340 match self.proof() {
341 Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature,
342 Some(Proof::Sr25519 { signature, signer }) => {
343 let to_sign = self.signature_material();
344 let signature = sp_core::sr25519::Signature::from(*signature);
345 let public = sp_core::sr25519::Public::from(*signer);
346 if signature.verify(to_sign.as_slice(), &public) {
347 SignatureVerificationResult::Valid(*signer)
348 } else {
349 SignatureVerificationResult::Invalid
350 }
351 },
352 Some(Proof::Ed25519 { signature, signer }) => {
353 let to_sign = self.signature_material();
354 let signature = sp_core::ed25519::Signature::from(*signature);
355 let public = sp_core::ed25519::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::Secp256k1Ecdsa { signature, signer }) => {
363 let to_sign = self.signature_material();
364 let signature = sp_core::ecdsa::Signature::from(*signature);
365 let public = sp_core::ecdsa::Public::from(*signer);
366 if signature.verify(to_sign.as_slice(), &public) {
367 let sender_hash =
368 <sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer);
369 SignatureVerificationResult::Valid(sender_hash.into())
370 } else {
371 SignatureVerificationResult::Invalid
372 }
373 },
374 }
375 }
376
377 #[cfg(feature = "std")]
379 pub fn hash(&self) -> [u8; 32] {
380 self.using_encoded(hash_encoded)
381 }
382
383 pub fn topic(&self, index: usize) -> Option<Topic> {
385 if index < self.num_topics as usize {
386 Some(self.topics[index])
387 } else {
388 None
389 }
390 }
391
392 pub fn decryption_key(&self) -> Option<DecryptionKey> {
394 self.decryption_key
395 }
396
397 pub fn into_data(self) -> Option<Vec<u8>> {
399 self.data
400 }
401
402 pub fn proof(&self) -> Option<&Proof> {
404 self.proof.as_ref()
405 }
406
407 pub fn account_id(&self) -> Option<AccountId> {
409 self.proof.as_ref().map(Proof::account_id)
410 }
411
412 pub fn data(&self) -> Option<&Vec<u8>> {
414 self.data.as_ref()
415 }
416
417 pub fn data_len(&self) -> usize {
419 self.data().map_or(0, Vec::len)
420 }
421
422 pub fn channel(&self) -> Option<Channel> {
424 self.channel
425 }
426
427 pub fn priority(&self) -> Option<u32> {
429 self.priority
430 }
431
432 fn signature_material(&self) -> Vec<u8> {
434 self.encoded(true)
435 }
436
437 pub fn remove_proof(&mut self) {
439 self.proof = None;
440 }
441
442 pub fn set_proof(&mut self, proof: Proof) {
444 self.proof = Some(proof)
445 }
446
447 pub fn set_priority(&mut self, priority: u32) {
449 self.priority = Some(priority)
450 }
451
452 pub fn set_channel(&mut self, channel: Channel) {
454 self.channel = Some(channel)
455 }
456
457 pub fn set_topic(&mut self, index: usize, topic: Topic) {
459 if index < MAX_TOPICS {
460 self.topics[index] = topic;
461 self.num_topics = self.num_topics.max(index as u8 + 1);
462 }
463 }
464
465 pub fn set_decryption_key(&mut self, key: DecryptionKey) {
467 self.decryption_key = Some(key);
468 }
469
470 pub fn set_plain_data(&mut self, data: Vec<u8>) {
472 self.data = Some(data)
473 }
474
475 fn encoded(&self, for_signing: bool) -> Vec<u8> {
476 let num_fields = if !for_signing && self.proof.is_some() { 1 } else { 0 } +
479 if self.decryption_key.is_some() { 1 } else { 0 } +
480 if self.priority.is_some() { 1 } else { 0 } +
481 if self.channel.is_some() { 1 } else { 0 } +
482 if self.data.is_some() { 1 } else { 0 } +
483 self.num_topics as u32;
484
485 let mut output = Vec::new();
486 if !for_signing {
490 let compact_len = codec::Compact::<u32>(num_fields);
491 compact_len.encode_to(&mut output);
492
493 if let Some(proof) = &self.proof {
494 0u8.encode_to(&mut output);
495 proof.encode_to(&mut output);
496 }
497 }
498 if let Some(decryption_key) = &self.decryption_key {
499 1u8.encode_to(&mut output);
500 decryption_key.encode_to(&mut output);
501 }
502 if let Some(priority) = &self.priority {
503 2u8.encode_to(&mut output);
504 priority.encode_to(&mut output);
505 }
506 if let Some(channel) = &self.channel {
507 3u8.encode_to(&mut output);
508 channel.encode_to(&mut output);
509 }
510 for t in 0..self.num_topics {
511 (4u8 + t).encode_to(&mut output);
512 self.topics[t as usize].encode_to(&mut output);
513 }
514 if let Some(data) = &self.data {
515 8u8.encode_to(&mut output);
516 data.encode_to(&mut output);
517 }
518 output
519 }
520
521 #[cfg(feature = "std")]
523 pub fn encrypt(
524 &mut self,
525 data: &[u8],
526 key: &sp_core::ed25519::Public,
527 ) -> core::result::Result<(), ecies::Error> {
528 let encrypted = ecies::encrypt_ed25519(key, data)?;
529 self.data = Some(encrypted);
530 self.decryption_key = Some((*key).into());
531 Ok(())
532 }
533
534 #[cfg(feature = "std")]
536 pub fn decrypt_private(
537 &self,
538 key: &sp_core::ed25519::Pair,
539 ) -> core::result::Result<Option<Vec<u8>>, ecies::Error> {
540 self.data.as_ref().map(|d| ecies::decrypt_ed25519(key, d)).transpose()
541 }
542}
543
544#[cfg(test)]
545mod test {
546 use crate::{hash_encoded, Field, Proof, SignatureVerificationResult, Statement};
547 use codec::{Decode, Encode};
548 use sp_application_crypto::Pair;
549
550 #[test]
551 fn statement_encoding_matches_vec() {
552 let mut statement = Statement::new();
553 assert!(statement.proof().is_none());
554 let proof = Proof::OnChain { who: [42u8; 32], block_hash: [24u8; 32], event_index: 66 };
555
556 let decryption_key = [0xde; 32];
557 let topic1 = [0x01; 32];
558 let topic2 = [0x02; 32];
559 let data = vec![55, 99];
560 let priority = 999;
561 let channel = [0xcc; 32];
562
563 statement.set_proof(proof.clone());
564 statement.set_decryption_key(decryption_key);
565 statement.set_priority(priority);
566 statement.set_channel(channel);
567 statement.set_topic(0, topic1);
568 statement.set_topic(1, topic2);
569 statement.set_plain_data(data.clone());
570
571 statement.set_topic(5, [0x55; 32]);
572 assert_eq!(statement.topic(5), None);
573
574 let fields = vec![
575 Field::AuthenticityProof(proof.clone()),
576 Field::DecryptionKey(decryption_key),
577 Field::Priority(priority),
578 Field::Channel(channel),
579 Field::Topic1(topic1),
580 Field::Topic2(topic2),
581 Field::Data(data.clone()),
582 ];
583
584 let encoded = statement.encode();
585 assert_eq!(statement.hash(), hash_encoded(&encoded));
586 assert_eq!(encoded, fields.encode());
587
588 let decoded = Statement::decode(&mut encoded.as_slice()).unwrap();
589 assert_eq!(decoded, statement);
590 }
591
592 #[test]
593 fn decode_checks_fields() {
594 let topic1 = [0x01; 32];
595 let topic2 = [0x02; 32];
596 let priority = 999;
597
598 let fields = vec![
599 Field::Priority(priority),
600 Field::Topic1(topic1),
601 Field::Topic1(topic1),
602 Field::Topic2(topic2),
603 ]
604 .encode();
605
606 assert!(Statement::decode(&mut fields.as_slice()).is_err());
607
608 let fields =
609 vec![Field::Topic1(topic1), Field::Priority(priority), Field::Topic2(topic2)].encode();
610
611 assert!(Statement::decode(&mut fields.as_slice()).is_err());
612 }
613
614 #[test]
615 fn sign_and_verify() {
616 let mut statement = Statement::new();
617 statement.set_plain_data(vec![42]);
618
619 let sr25519_kp = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap();
620 let ed25519_kp = sp_core::ed25519::Pair::from_string("//Alice", None).unwrap();
621 let secp256k1_kp = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
622
623 statement.sign_sr25519_private(&sr25519_kp);
624 assert_eq!(
625 statement.verify_signature(),
626 SignatureVerificationResult::Valid(sr25519_kp.public().0)
627 );
628
629 statement.sign_ed25519_private(&ed25519_kp);
630 assert_eq!(
631 statement.verify_signature(),
632 SignatureVerificationResult::Valid(ed25519_kp.public().0)
633 );
634
635 statement.sign_ecdsa_private(&secp256k1_kp);
636 assert_eq!(
637 statement.verify_signature(),
638 SignatureVerificationResult::Valid(sp_crypto_hashing::blake2_256(
639 &secp256k1_kp.public().0
640 ))
641 );
642
643 statement.set_proof(Proof::Sr25519 { signature: [0u8; 64], signer: [0u8; 32] });
645 assert_eq!(statement.verify_signature(), SignatureVerificationResult::Invalid);
646
647 statement.remove_proof();
648 assert_eq!(statement.verify_signature(), SignatureVerificationResult::NoSignature);
649 }
650
651 #[test]
652 fn encrypt_decrypt() {
653 let mut statement = Statement::new();
654 let (pair, _) = sp_core::ed25519::Pair::generate();
655 let plain = b"test data".to_vec();
656
657 statement.encrypt(&plain, &pair.public()).unwrap();
659 assert_ne!(plain.as_slice(), statement.data().unwrap().as_slice());
660
661 let decrypted = statement.decrypt_private(&pair).unwrap();
662 assert_eq!(decrypted, Some(plain));
663 }
664}