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 pezsp_application_crypto::RuntimeAppPublic;
28#[cfg(feature = "std")]
29use pezsp_core::Pair;
30use scale_info::TypeInfo;
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 pezsp_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 pezsp_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 pezsp_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 pezsp_crypto_hashing::blake2_256(data)
92}
93
94#[derive(
96 Encode, Decode, DecodeWithMemTracking, TypeInfo, pezsp_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 <pezsp_runtime::traits::BlakeTwo256 as pezsp_core::Hasher>::hash(signer).into()
139 },
140 Proof::OnChain { who, .. } => *who,
141 }
142 }
143}
144
145#[derive(Encode, Decode, TypeInfo, pezsp_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, TypeInfo, pezsp_core::RuntimeDebug, Clone, PartialEq, Eq, Default,
181)]
182pub struct Statement {
183 proof: Option<Proof>,
184 decryption_key: Option<DecryptionKey>,
185 channel: Option<Channel>,
186 priority: Option<u32>,
187 num_topics: u8,
188 topics: [Topic; MAX_TOPICS],
189 data: Option<Vec<u8>>,
190}
191
192impl Decode for Statement {
193 fn decode<I: codec::Input>(input: &mut I) -> core::result::Result<Self, codec::Error> {
194 let num_fields: codec::Compact<u32> = Decode::decode(input)?;
197 let mut tag = 0;
198 let mut statement = Statement::new();
199 for i in 0..num_fields.into() {
200 let field: Field = Decode::decode(input)?;
201 if i > 0 && field.discriminant() <= tag {
202 return Err("Invalid field order or duplicate fields".into());
203 }
204 tag = field.discriminant();
205 match field {
206 Field::AuthenticityProof(p) => statement.set_proof(p),
207 Field::DecryptionKey(key) => statement.set_decryption_key(key),
208 Field::Priority(p) => statement.set_priority(p),
209 Field::Channel(c) => statement.set_channel(c),
210 Field::Topic1(t) => statement.set_topic(0, t),
211 Field::Topic2(t) => statement.set_topic(1, t),
212 Field::Topic3(t) => statement.set_topic(2, t),
213 Field::Topic4(t) => statement.set_topic(3, t),
214 Field::Data(data) => statement.set_plain_data(data),
215 }
216 }
217 Ok(statement)
218 }
219}
220
221impl Encode for Statement {
222 fn encode(&self) -> Vec<u8> {
223 self.encoded(false)
224 }
225}
226
227#[derive(Clone, Copy, PartialEq, Eq, Debug)]
228pub enum SignatureVerificationResult {
230 Valid(AccountId),
232 Invalid,
234 NoSignature,
236}
237
238impl Statement {
239 pub fn new() -> Statement {
241 Default::default()
242 }
243
244 pub fn new_with_proof(proof: Proof) -> Statement {
246 let mut statement = Self::new();
247 statement.set_proof(proof);
248 statement
249 }
250
251 pub fn sign_sr25519_public(&mut self, key: &sr25519::Public) -> bool {
257 let to_sign = self.signature_material();
258 if let Some(signature) = key.sign(&to_sign) {
259 let proof = Proof::Sr25519 {
260 signature: signature.into_inner().into(),
261 signer: key.clone().into_inner().into(),
262 };
263 self.set_proof(proof);
264 true
265 } else {
266 false
267 }
268 }
269
270 #[cfg(feature = "std")]
272 pub fn sign_sr25519_private(&mut self, key: &pezsp_core::sr25519::Pair) {
273 let to_sign = self.signature_material();
274 let proof =
275 Proof::Sr25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
276 self.set_proof(proof);
277 }
278
279 pub fn sign_ed25519_public(&mut self, key: &ed25519::Public) -> bool {
285 let to_sign = self.signature_material();
286 if let Some(signature) = key.sign(&to_sign) {
287 let proof = Proof::Ed25519 {
288 signature: signature.into_inner().into(),
289 signer: key.clone().into_inner().into(),
290 };
291 self.set_proof(proof);
292 true
293 } else {
294 false
295 }
296 }
297
298 #[cfg(feature = "std")]
300 pub fn sign_ed25519_private(&mut self, key: &pezsp_core::ed25519::Pair) {
301 let to_sign = self.signature_material();
302 let proof =
303 Proof::Ed25519 { signature: key.sign(&to_sign).into(), signer: key.public().into() };
304 self.set_proof(proof);
305 }
306
307 pub fn sign_ecdsa_public(&mut self, key: &ecdsa::Public) -> bool {
317 let to_sign = self.signature_material();
318 if let Some(signature) = key.sign(&to_sign) {
319 let proof = Proof::Secp256k1Ecdsa {
320 signature: signature.into_inner().into(),
321 signer: key.clone().into_inner().0,
322 };
323 self.set_proof(proof);
324 true
325 } else {
326 false
327 }
328 }
329
330 #[cfg(feature = "std")]
332 pub fn sign_ecdsa_private(&mut self, key: &pezsp_core::ecdsa::Pair) {
333 let to_sign = self.signature_material();
334 let proof =
335 Proof::Secp256k1Ecdsa { signature: key.sign(&to_sign).into(), signer: key.public().0 };
336 self.set_proof(proof);
337 }
338
339 pub fn verify_signature(&self) -> SignatureVerificationResult {
341 use pezsp_runtime::traits::Verify;
342
343 match self.proof() {
344 Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature,
345 Some(Proof::Sr25519 { signature, signer }) => {
346 let to_sign = self.signature_material();
347 let signature = pezsp_core::sr25519::Signature::from(*signature);
348 let public = pezsp_core::sr25519::Public::from(*signer);
349 if signature.verify(to_sign.as_slice(), &public) {
350 SignatureVerificationResult::Valid(*signer)
351 } else {
352 SignatureVerificationResult::Invalid
353 }
354 },
355 Some(Proof::Ed25519 { signature, signer }) => {
356 let to_sign = self.signature_material();
357 let signature = pezsp_core::ed25519::Signature::from(*signature);
358 let public = pezsp_core::ed25519::Public::from(*signer);
359 if signature.verify(to_sign.as_slice(), &public) {
360 SignatureVerificationResult::Valid(*signer)
361 } else {
362 SignatureVerificationResult::Invalid
363 }
364 },
365 Some(Proof::Secp256k1Ecdsa { signature, signer }) => {
366 let to_sign = self.signature_material();
367 let signature = pezsp_core::ecdsa::Signature::from(*signature);
368 let public = pezsp_core::ecdsa::Public::from(*signer);
369 if signature.verify(to_sign.as_slice(), &public) {
370 let sender_hash =
371 <pezsp_runtime::traits::BlakeTwo256 as pezsp_core::Hasher>::hash(signer);
372 SignatureVerificationResult::Valid(sender_hash.into())
373 } else {
374 SignatureVerificationResult::Invalid
375 }
376 },
377 }
378 }
379
380 #[cfg(feature = "std")]
382 pub fn hash(&self) -> [u8; 32] {
383 self.using_encoded(hash_encoded)
384 }
385
386 pub fn topic(&self, index: usize) -> Option<Topic> {
388 if index < self.num_topics as usize {
389 Some(self.topics[index])
390 } else {
391 None
392 }
393 }
394
395 pub fn decryption_key(&self) -> Option<DecryptionKey> {
397 self.decryption_key
398 }
399
400 pub fn into_data(self) -> Option<Vec<u8>> {
402 self.data
403 }
404
405 pub fn proof(&self) -> Option<&Proof> {
407 self.proof.as_ref()
408 }
409
410 pub fn account_id(&self) -> Option<AccountId> {
412 self.proof.as_ref().map(Proof::account_id)
413 }
414
415 pub fn data(&self) -> Option<&Vec<u8>> {
417 self.data.as_ref()
418 }
419
420 pub fn data_len(&self) -> usize {
422 self.data().map_or(0, Vec::len)
423 }
424
425 pub fn channel(&self) -> Option<Channel> {
427 self.channel
428 }
429
430 pub fn priority(&self) -> Option<u32> {
432 self.priority
433 }
434
435 fn signature_material(&self) -> Vec<u8> {
437 self.encoded(true)
438 }
439
440 pub fn remove_proof(&mut self) {
442 self.proof = None;
443 }
444
445 pub fn set_proof(&mut self, proof: Proof) {
447 self.proof = Some(proof)
448 }
449
450 pub fn set_priority(&mut self, priority: u32) {
452 self.priority = Some(priority)
453 }
454
455 pub fn set_channel(&mut self, channel: Channel) {
457 self.channel = Some(channel)
458 }
459
460 pub fn set_topic(&mut self, index: usize, topic: Topic) {
462 if index < MAX_TOPICS {
463 self.topics[index] = topic;
464 self.num_topics = self.num_topics.max(index as u8 + 1);
465 }
466 }
467
468 pub fn set_decryption_key(&mut self, key: DecryptionKey) {
470 self.decryption_key = Some(key);
471 }
472
473 pub fn set_plain_data(&mut self, data: Vec<u8>) {
475 self.data = Some(data)
476 }
477
478 fn encoded(&self, for_signing: bool) -> Vec<u8> {
479 let num_fields = if !for_signing && self.proof.is_some() { 1 } else { 0 }
482 + if self.decryption_key.is_some() { 1 } else { 0 }
483 + if self.priority.is_some() { 1 } else { 0 }
484 + if self.channel.is_some() { 1 } else { 0 }
485 + if self.data.is_some() { 1 } else { 0 }
486 + self.num_topics as u32;
487
488 let mut output = Vec::new();
489 if !for_signing {
493 let compact_len = codec::Compact::<u32>(num_fields);
494 compact_len.encode_to(&mut output);
495
496 if let Some(proof) = &self.proof {
497 0u8.encode_to(&mut output);
498 proof.encode_to(&mut output);
499 }
500 }
501 if let Some(decryption_key) = &self.decryption_key {
502 1u8.encode_to(&mut output);
503 decryption_key.encode_to(&mut output);
504 }
505 if let Some(priority) = &self.priority {
506 2u8.encode_to(&mut output);
507 priority.encode_to(&mut output);
508 }
509 if let Some(channel) = &self.channel {
510 3u8.encode_to(&mut output);
511 channel.encode_to(&mut output);
512 }
513 for t in 0..self.num_topics {
514 (4u8 + t).encode_to(&mut output);
515 self.topics[t as usize].encode_to(&mut output);
516 }
517 if let Some(data) = &self.data {
518 8u8.encode_to(&mut output);
519 data.encode_to(&mut output);
520 }
521 output
522 }
523
524 #[cfg(feature = "std")]
526 pub fn encrypt(
527 &mut self,
528 data: &[u8],
529 key: &pezsp_core::ed25519::Public,
530 ) -> core::result::Result<(), ecies::Error> {
531 let encrypted = ecies::encrypt_ed25519(key, data)?;
532 self.data = Some(encrypted);
533 self.decryption_key = Some((*key).into());
534 Ok(())
535 }
536
537 #[cfg(feature = "std")]
539 pub fn decrypt_private(
540 &self,
541 key: &pezsp_core::ed25519::Pair,
542 ) -> core::result::Result<Option<Vec<u8>>, ecies::Error> {
543 self.data.as_ref().map(|d| ecies::decrypt_ed25519(key, d)).transpose()
544 }
545}
546
547#[cfg(test)]
548mod test {
549 use crate::{hash_encoded, Field, Proof, SignatureVerificationResult, Statement};
550 use codec::{Decode, Encode};
551 use pezsp_application_crypto::Pair;
552
553 #[test]
554 fn statement_encoding_matches_vec() {
555 let mut statement = Statement::new();
556 assert!(statement.proof().is_none());
557 let proof = Proof::OnChain { who: [42u8; 32], block_hash: [24u8; 32], event_index: 66 };
558
559 let decryption_key = [0xde; 32];
560 let topic1 = [0x01; 32];
561 let topic2 = [0x02; 32];
562 let data = vec![55, 99];
563 let priority = 999;
564 let channel = [0xcc; 32];
565
566 statement.set_proof(proof.clone());
567 statement.set_decryption_key(decryption_key);
568 statement.set_priority(priority);
569 statement.set_channel(channel);
570 statement.set_topic(0, topic1);
571 statement.set_topic(1, topic2);
572 statement.set_plain_data(data.clone());
573
574 statement.set_topic(5, [0x55; 32]);
575 assert_eq!(statement.topic(5), None);
576
577 let fields = vec![
578 Field::AuthenticityProof(proof.clone()),
579 Field::DecryptionKey(decryption_key),
580 Field::Priority(priority),
581 Field::Channel(channel),
582 Field::Topic1(topic1),
583 Field::Topic2(topic2),
584 Field::Data(data.clone()),
585 ];
586
587 let encoded = statement.encode();
588 assert_eq!(statement.hash(), hash_encoded(&encoded));
589 assert_eq!(encoded, fields.encode());
590
591 let decoded = Statement::decode(&mut encoded.as_slice()).unwrap();
592 assert_eq!(decoded, statement);
593 }
594
595 #[test]
596 fn decode_checks_fields() {
597 let topic1 = [0x01; 32];
598 let topic2 = [0x02; 32];
599 let priority = 999;
600
601 let fields = vec![
602 Field::Priority(priority),
603 Field::Topic1(topic1),
604 Field::Topic1(topic1),
605 Field::Topic2(topic2),
606 ]
607 .encode();
608
609 assert!(Statement::decode(&mut fields.as_slice()).is_err());
610
611 let fields =
612 vec![Field::Topic1(topic1), Field::Priority(priority), Field::Topic2(topic2)].encode();
613
614 assert!(Statement::decode(&mut fields.as_slice()).is_err());
615 }
616
617 #[test]
618 fn sign_and_verify() {
619 let mut statement = Statement::new();
620 statement.set_plain_data(vec![42]);
621
622 let sr25519_kp = pezsp_core::sr25519::Pair::from_string("//Alice", None).unwrap();
623 let ed25519_kp = pezsp_core::ed25519::Pair::from_string("//Alice", None).unwrap();
624 let secp256k1_kp = pezsp_core::ecdsa::Pair::from_string("//Alice", None).unwrap();
625
626 statement.sign_sr25519_private(&sr25519_kp);
627 assert_eq!(
628 statement.verify_signature(),
629 SignatureVerificationResult::Valid(sr25519_kp.public().0)
630 );
631
632 statement.sign_ed25519_private(&ed25519_kp);
633 assert_eq!(
634 statement.verify_signature(),
635 SignatureVerificationResult::Valid(ed25519_kp.public().0)
636 );
637
638 statement.sign_ecdsa_private(&secp256k1_kp);
639 assert_eq!(
640 statement.verify_signature(),
641 SignatureVerificationResult::Valid(pezsp_crypto_hashing::blake2_256(
642 &secp256k1_kp.public().0
643 ))
644 );
645
646 statement.set_proof(Proof::Sr25519 { signature: [0u8; 64], signer: [0u8; 32] });
648 assert_eq!(statement.verify_signature(), SignatureVerificationResult::Invalid);
649
650 statement.remove_proof();
651 assert_eq!(statement.verify_signature(), SignatureVerificationResult::NoSignature);
652 }
653
654 #[test]
655 fn encrypt_decrypt() {
656 let mut statement = Statement::new();
657 let (pair, _) = pezsp_core::ed25519::Pair::generate();
658 let plain = b"test data".to_vec();
659
660 statement.encrypt(&plain, &pair.public()).unwrap();
662 assert_ne!(plain.as_slice(), statement.data().unwrap().as_slice());
663
664 let decrypted = statement.decrypt_private(&pair).unwrap();
665 assert_eq!(decrypted, Some(plain));
666 }
667}