1#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(missing_docs)]
20
21extern 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
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(Encode, Decode, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq)]
97pub enum Proof {
98 Sr25519 {
100 signature: [u8; 64],
102 signer: [u8; 32],
104 },
105 Ed25519 {
107 signature: [u8; 64],
109 signer: [u8; 32],
111 },
112 Secp256k1Ecdsa {
114 signature: [u8; 65],
116 signer: [u8; 33],
118 },
119 OnChain {
121 who: AccountId,
123 block_hash: BlockHash,
125 event_index: u64,
127 },
128}
129
130impl Proof {
131 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#[derive(Encode, Decode, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq)]
146#[repr(u8)]
147pub enum Field {
148 AuthenticityProof(Proof) = 0,
150 DecryptionKey(DecryptionKey) = 1,
152 Priority(u32) = 2,
154 Channel(Channel) = 3,
156 Topic1(Topic) = 4,
158 Topic2(Topic) = 5,
160 Topic3(Topic) = 6,
162 Topic4(Topic) = 7,
164 Data(Vec<u8>) = 8,
166}
167
168impl Field {
169 fn discriminant(&self) -> u8 {
170 unsafe { *(self as *const Self as *const u8) }
173 }
174}
175
176#[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 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)]
224pub enum SignatureVerificationResult {
226 Valid(AccountId),
228 Invalid,
230 NoSignature,
232}
233
234impl Statement {
235 pub fn new() -> Statement {
237 Default::default()
238 }
239
240 pub fn new_with_proof(proof: Proof) -> Statement {
242 let mut statement = Self::new();
243 statement.set_proof(proof);
244 statement
245 }
246
247 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 #[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 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 #[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 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 #[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 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 #[cfg(feature = "std")]
378 pub fn hash(&self) -> [u8; 32] {
379 self.using_encoded(hash_encoded)
380 }
381
382 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 pub fn decryption_key(&self) -> Option<DecryptionKey> {
393 self.decryption_key
394 }
395
396 pub fn into_data(self) -> Option<Vec<u8>> {
398 self.data
399 }
400
401 pub fn proof(&self) -> Option<&Proof> {
403 self.proof.as_ref()
404 }
405
406 pub fn account_id(&self) -> Option<AccountId> {
408 self.proof.as_ref().map(Proof::account_id)
409 }
410
411 pub fn data(&self) -> Option<&Vec<u8>> {
413 self.data.as_ref()
414 }
415
416 pub fn data_len(&self) -> usize {
418 self.data().map_or(0, Vec::len)
419 }
420
421 pub fn channel(&self) -> Option<Channel> {
423 self.channel
424 }
425
426 pub fn priority(&self) -> Option<u32> {
428 self.priority
429 }
430
431 fn signature_material(&self) -> Vec<u8> {
433 self.encoded(true)
434 }
435
436 pub fn remove_proof(&mut self) {
438 self.proof = None;
439 }
440
441 pub fn set_proof(&mut self, proof: Proof) {
443 self.proof = Some(proof)
444 }
445
446 pub fn set_priority(&mut self, priority: u32) {
448 self.priority = Some(priority)
449 }
450
451 pub fn set_channel(&mut self, channel: Channel) {
453 self.channel = Some(channel)
454 }
455
456 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 pub fn set_decryption_key(&mut self, key: DecryptionKey) {
466 self.decryption_key = Some(key);
467 }
468
469 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 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 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 #[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 #[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 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 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}