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, InvalidReason, RejectionReason, 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(Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug, Clone, PartialEq, Eq)]
96pub enum Proof {
97 Sr25519 {
99 signature: [u8; 64],
101 signer: [u8; 32],
103 },
104 Ed25519 {
106 signature: [u8; 64],
108 signer: [u8; 32],
110 },
111 Secp256k1Ecdsa {
113 signature: [u8; 65],
115 signer: [u8; 33],
117 },
118 OnChain {
120 who: AccountId,
122 block_hash: BlockHash,
124 event_index: u64,
126 },
127}
128
129impl Proof {
130 pub fn account_id(&self) -> AccountId {
132 match self {
133 Proof::Sr25519 { signer, .. } => *signer,
134 Proof::Ed25519 { signer, .. } => *signer,
135 Proof::Secp256k1Ecdsa { signer, .. } =>
136 <sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer).into(),
137 Proof::OnChain { who, .. } => *who,
138 }
139 }
140}
141
142#[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)]
145#[repr(u8)]
146pub enum Field {
147 AuthenticityProof(Proof) = 0,
149 DecryptionKey(DecryptionKey) = 1,
151 Priority(u32) = 2,
153 Channel(Channel) = 3,
155 Topic1(Topic) = 4,
157 Topic2(Topic) = 5,
159 Topic3(Topic) = 6,
161 Topic4(Topic) = 7,
163 Data(Vec<u8>) = 8,
165}
166
167impl Field {
168 fn discriminant(&self) -> u8 {
169 unsafe { *(self as *const Self as *const u8) }
172 }
173}
174
175#[derive(DecodeWithMemTracking, TypeInfo, Debug, Clone, PartialEq, Eq, Default)]
177pub struct Statement {
178 proof: Option<Proof>,
179 decryption_key: Option<DecryptionKey>,
180 channel: Option<Channel>,
181 priority: Option<u32>,
182 num_topics: u8,
183 topics: [Topic; MAX_TOPICS],
184 data: Option<Vec<u8>>,
185}
186
187impl Decode for Statement {
188 fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
189 let num_fields: codec::Compact<u32> = Decode::decode(input)?;
192 let mut tag = 0;
193 let mut statement = Statement::new();
194 for i in 0..num_fields.into() {
195 let field: Field = Decode::decode(input)?;
196 if i > 0 && field.discriminant() <= tag {
197 return Err("Invalid field order or duplicate fields".into())
198 }
199 tag = field.discriminant();
200 match field {
201 Field::AuthenticityProof(p) => statement.set_proof(p),
202 Field::DecryptionKey(key) => statement.set_decryption_key(key),
203 Field::Priority(p) => statement.set_priority(p),
204 Field::Channel(c) => statement.set_channel(c),
205 Field::Topic1(t) => statement.set_topic(0, t),
206 Field::Topic2(t) => statement.set_topic(1, t),
207 Field::Topic3(t) => statement.set_topic(2, t),
208 Field::Topic4(t) => statement.set_topic(3, t),
209 Field::Data(data) => statement.set_plain_data(data),
210 }
211 }
212 Ok(statement)
213 }
214}
215
216impl Encode for Statement {
217 fn encode(&self) -> Vec<u8> {
218 self.encoded(false)
219 }
220}
221
222#[derive(Clone, Copy, PartialEq, Eq, Debug)]
223pub enum SignatureVerificationResult {
225 Valid(AccountId),
227 Invalid,
229 NoSignature,
231}
232
233impl Statement {
234 pub fn new() -> Statement {
236 Default::default()
237 }
238
239 pub fn new_with_proof(proof: Proof) -> Statement {
241 let mut statement = Self::new();
242 statement.set_proof(proof);
243 statement
244 }
245
246 pub fn sign_sr25519_public(&mut self, key: &sr25519::Public) -> bool {
252 let to_sign = self.signature_material();
253 if let Some(signature) = key.sign(&to_sign) {
254 let proof = Proof::Sr25519 {
255 signature: signature.into_inner().into(),
256 signer: key.clone().into_inner().into(),
257 };
258 self.set_proof(proof);
259 true
260 } else {
261 false
262 }
263 }
264
265 #[cfg(feature = "std")]
267 pub fn sign_sr25519_private(&mut self, key: &sp_core::sr25519::Pair) {
268 let to_sign = self.signature_material();
269 let proof =
270 Proof::Sr25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
271 self.set_proof(proof);
272 }
273
274 pub fn sign_ed25519_public(&mut self, key: &ed25519::Public) -> bool {
280 let to_sign = self.signature_material();
281 if let Some(signature) = key.sign(&to_sign) {
282 let proof = Proof::Ed25519 {
283 signature: signature.into_inner().into(),
284 signer: key.clone().into_inner().into(),
285 };
286 self.set_proof(proof);
287 true
288 } else {
289 false
290 }
291 }
292
293 #[cfg(feature = "std")]
295 pub fn sign_ed25519_private(&mut self, key: &sp_core::ed25519::Pair) {
296 let to_sign = self.signature_material();
297 let proof =
298 Proof::Ed25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
299 self.set_proof(proof);
300 }
301
302 pub fn sign_ecdsa_public(&mut self, key: &ecdsa::Public) -> bool {
312 let to_sign = self.signature_material();
313 if let Some(signature) = key.sign(&to_sign) {
314 let proof = Proof::Secp256k1Ecdsa {
315 signature: signature.into_inner().into(),
316 signer: key.clone().into_inner().0,
317 };
318 self.set_proof(proof);
319 true
320 } else {
321 false
322 }
323 }
324
325 #[cfg(feature = "std")]
327 pub fn sign_ecdsa_private(&mut self, key: &sp_core::ecdsa::Pair) {
328 let to_sign = self.signature_material();
329 let proof =
330 Proof::Secp256k1Ecdsa { signature: key.sign(&to_sign).into(), signer: key.public().0 };
331 self.set_proof(proof);
332 }
333
334 pub fn verify_signature(&self) -> SignatureVerificationResult {
336 use sp_runtime::traits::Verify;
337
338 match self.proof() {
339 Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature,
340 Some(Proof::Sr25519 { signature, signer }) => {
341 let to_sign = self.signature_material();
342 let signature = sp_core::sr25519::Signature::from(*signature);
343 let public = sp_core::sr25519::Public::from(*signer);
344 if signature.verify(to_sign.as_slice(), &public) {
345 SignatureVerificationResult::Valid(*signer)
346 } else {
347 SignatureVerificationResult::Invalid
348 }
349 },
350 Some(Proof::Ed25519 { signature, signer }) => {
351 let to_sign = self.signature_material();
352 let signature = sp_core::ed25519::Signature::from(*signature);
353 let public = sp_core::ed25519::Public::from(*signer);
354 if signature.verify(to_sign.as_slice(), &public) {
355 SignatureVerificationResult::Valid(*signer)
356 } else {
357 SignatureVerificationResult::Invalid
358 }
359 },
360 Some(Proof::Secp256k1Ecdsa { signature, signer }) => {
361 let to_sign = self.signature_material();
362 let signature = sp_core::ecdsa::Signature::from(*signature);
363 let public = sp_core::ecdsa::Public::from(*signer);
364 if signature.verify(to_sign.as_slice(), &public) {
365 let sender_hash =
366 <sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer);
367 SignatureVerificationResult::Valid(sender_hash.into())
368 } else {
369 SignatureVerificationResult::Invalid
370 }
371 },
372 }
373 }
374
375 #[cfg(feature = "std")]
377 pub fn hash(&self) -> [u8; 32] {
378 self.using_encoded(hash_encoded)
379 }
380
381 pub fn topic(&self, index: usize) -> Option<Topic> {
383 if index < self.num_topics as usize {
384 Some(self.topics[index])
385 } else {
386 None
387 }
388 }
389
390 pub fn decryption_key(&self) -> Option<DecryptionKey> {
392 self.decryption_key
393 }
394
395 pub fn into_data(self) -> Option<Vec<u8>> {
397 self.data
398 }
399
400 pub fn proof(&self) -> Option<&Proof> {
402 self.proof.as_ref()
403 }
404
405 pub fn account_id(&self) -> Option<AccountId> {
407 self.proof.as_ref().map(Proof::account_id)
408 }
409
410 pub fn data(&self) -> Option<&Vec<u8>> {
412 self.data.as_ref()
413 }
414
415 pub fn data_len(&self) -> usize {
417 self.data().map_or(0, Vec::len)
418 }
419
420 pub fn channel(&self) -> Option<Channel> {
422 self.channel
423 }
424
425 pub fn priority(&self) -> Option<u32> {
427 self.priority
428 }
429
430 fn signature_material(&self) -> Vec<u8> {
432 self.encoded(true)
433 }
434
435 pub fn remove_proof(&mut self) {
437 self.proof = None;
438 }
439
440 pub fn set_proof(&mut self, proof: Proof) {
442 self.proof = Some(proof)
443 }
444
445 pub fn set_priority(&mut self, priority: u32) {
447 self.priority = Some(priority)
448 }
449
450 pub fn set_channel(&mut self, channel: Channel) {
452 self.channel = Some(channel)
453 }
454
455 pub fn set_topic(&mut self, index: usize, topic: Topic) {
457 if index < MAX_TOPICS {
458 self.topics[index] = topic;
459 self.num_topics = self.num_topics.max(index as u8 + 1);
460 }
461 }
462
463 pub fn set_decryption_key(&mut self, key: DecryptionKey) {
465 self.decryption_key = Some(key);
466 }
467
468 pub fn set_plain_data(&mut self, data: Vec<u8>) {
470 self.data = Some(data)
471 }
472
473 fn encoded(&self, for_signing: bool) -> Vec<u8> {
474 let num_fields = if !for_signing && self.proof.is_some() { 1 } else { 0 } +
477 if self.decryption_key.is_some() { 1 } else { 0 } +
478 if self.priority.is_some() { 1 } else { 0 } +
479 if self.channel.is_some() { 1 } else { 0 } +
480 if self.data.is_some() { 1 } else { 0 } +
481 self.num_topics as u32;
482
483 let mut output = Vec::new();
484 if !for_signing {
488 let compact_len = codec::Compact::<u32>(num_fields);
489 compact_len.encode_to(&mut output);
490
491 if let Some(proof) = &self.proof {
492 0u8.encode_to(&mut output);
493 proof.encode_to(&mut output);
494 }
495 }
496 if let Some(decryption_key) = &self.decryption_key {
497 1u8.encode_to(&mut output);
498 decryption_key.encode_to(&mut output);
499 }
500 if let Some(priority) = &self.priority {
501 2u8.encode_to(&mut output);
502 priority.encode_to(&mut output);
503 }
504 if let Some(channel) = &self.channel {
505 3u8.encode_to(&mut output);
506 channel.encode_to(&mut output);
507 }
508 for t in 0..self.num_topics {
509 (4u8 + t).encode_to(&mut output);
510 self.topics[t as usize].encode_to(&mut output);
511 }
512 if let Some(data) = &self.data {
513 8u8.encode_to(&mut output);
514 data.encode_to(&mut output);
515 }
516 output
517 }
518
519 #[cfg(feature = "std")]
521 pub fn encrypt(
522 &mut self,
523 data: &[u8],
524 key: &sp_core::ed25519::Public,
525 ) -> core::result::Result<(), ecies::Error> {
526 let encrypted = ecies::encrypt_ed25519(key, data)?;
527 self.data = Some(encrypted);
528 self.decryption_key = Some((*key).into());
529 Ok(())
530 }
531
532 #[cfg(feature = "std")]
534 pub fn decrypt_private(
535 &self,
536 key: &sp_core::ed25519::Pair,
537 ) -> core::result::Result<Option<Vec<u8>>, ecies::Error> {
538 self.data.as_ref().map(|d| ecies::decrypt_ed25519(key, d)).transpose()
539 }
540}
541
542#[cfg(test)]
543mod test {
544 use crate::{hash_encoded, Field, Proof, SignatureVerificationResult, Statement};
545 use codec::{Decode, Encode};
546 use sp_application_crypto::Pair;
547
548 #[test]
549 fn statement_encoding_matches_vec() {
550 let mut statement = Statement::new();
551 assert!(statement.proof().is_none());
552 let proof = Proof::OnChain { who: [42u8; 32], block_hash: [24u8; 32], event_index: 66 };
553
554 let decryption_key = [0xde; 32];
555 let topic1 = [0x01; 32];
556 let topic2 = [0x02; 32];
557 let data = vec![55, 99];
558 let priority = 999;
559 let channel = [0xcc; 32];
560
561 statement.set_proof(proof.clone());
562 statement.set_decryption_key(decryption_key);
563 statement.set_priority(priority);
564 statement.set_channel(channel);
565 statement.set_topic(0, topic1);
566 statement.set_topic(1, topic2);
567 statement.set_plain_data(data.clone());
568
569 statement.set_topic(5, [0x55; 32]);
570 assert_eq!(statement.topic(5), None);
571
572 let fields = vec![
573 Field::AuthenticityProof(proof.clone()),
574 Field::DecryptionKey(decryption_key),
575 Field::Priority(priority),
576 Field::Channel(channel),
577 Field::Topic1(topic1),
578 Field::Topic2(topic2),
579 Field::Data(data.clone()),
580 ];
581
582 let encoded = statement.encode();
583 assert_eq!(statement.hash(), hash_encoded(&encoded));
584 assert_eq!(encoded, fields.encode());
585
586 let decoded = Statement::decode(&mut encoded.as_slice()).unwrap();
587 assert_eq!(decoded, statement);
588 }
589
590 #[test]
591 fn decode_checks_fields() {
592 let topic1 = [0x01; 32];
593 let topic2 = [0x02; 32];
594 let priority = 999;
595
596 let fields = vec![
597 Field::Priority(priority),
598 Field::Topic1(topic1),
599 Field::Topic1(topic1),
600 Field::Topic2(topic2),
601 ]
602 .encode();
603
604 assert!(Statement::decode(&mut fields.as_slice()).is_err());
605
606 let fields =
607 vec![Field::Topic1(topic1), Field::Priority(priority), Field::Topic2(topic2)].encode();
608
609 assert!(Statement::decode(&mut fields.as_slice()).is_err());
610 }
611
612 #[test]
613 fn sign_and_verify() {
614 let mut statement = Statement::new();
615 statement.set_plain_data(vec![42]);
616
617 let sr25519_kp = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap();
618 let ed25519_kp = sp_core::ed25519::Pair::from_string("//Alice", None).unwrap();
619 let secp256k1_kp = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
620
621 statement.sign_sr25519_private(&sr25519_kp);
622 assert_eq!(
623 statement.verify_signature(),
624 SignatureVerificationResult::Valid(sr25519_kp.public().0)
625 );
626
627 statement.sign_ed25519_private(&ed25519_kp);
628 assert_eq!(
629 statement.verify_signature(),
630 SignatureVerificationResult::Valid(ed25519_kp.public().0)
631 );
632
633 statement.sign_ecdsa_private(&secp256k1_kp);
634 assert_eq!(
635 statement.verify_signature(),
636 SignatureVerificationResult::Valid(sp_crypto_hashing::blake2_256(
637 &secp256k1_kp.public().0
638 ))
639 );
640
641 statement.set_proof(Proof::Sr25519 { signature: [0u8; 64], signer: [0u8; 32] });
643 assert_eq!(statement.verify_signature(), SignatureVerificationResult::Invalid);
644
645 statement.remove_proof();
646 assert_eq!(statement.verify_signature(), SignatureVerificationResult::NoSignature);
647 }
648
649 #[test]
650 fn encrypt_decrypt() {
651 let mut statement = Statement::new();
652 let (pair, _) = sp_core::ed25519::Pair::generate();
653 let plain = b"test data".to_vec();
654
655 statement.encrypt(&plain, &pair.public()).unwrap();
657 assert_ne!(plain.as_slice(), statement.data().unwrap().as_slice());
658
659 let decrypted = statement.decrypt_private(&pair).unwrap();
660 assert_eq!(decrypted, Some(plain));
661 }
662}