1use std::{
8 collections::BTreeMap,
9 fmt::{Debug, Display, Formatter},
10 hash::{Hash, Hasher},
11 str::FromStr,
12};
13
14use anyhow::{Error, anyhow};
15use derive_more::{AsRef, From};
16pub use enum_dispatch::enum_dispatch;
17use eyre::eyre;
18pub use fastcrypto::traits::{
19 AggregateAuthenticator, Authenticator, EncodeDecodeBase64, KeyPair as KeypairTraits, Signer,
20 SigningKey, ToFromBytes, VerifyingKey,
21};
22use fastcrypto::{
23 bls12381::min_sig::{
24 BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair,
25 BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature,
26 },
27 ed25519::{Ed25519KeyPair, Ed25519PublicKey, Ed25519PublicKeyAsBytes, Ed25519Signature},
28 encoding::{Base64, Encoding, Hex},
29 error::{FastCryptoError, FastCryptoResult},
30 hash::{Blake2b256, HashFunction},
31 secp256k1::{Secp256k1PublicKey, Secp256k1PublicKeyAsBytes},
32 secp256r1::{Secp256r1PublicKey, Secp256r1PublicKeyAsBytes},
33 serde_helpers::BytesRepresentation,
34};
35use iota_sdk_crypto::{
36 ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey, secp256r1::Secp256r1PrivateKey,
37 simple::SimpleKeypair,
38};
39use iota_sdk_types::{
40 Address, SignatureScheme,
41 crypto::{Intent, IntentMessage, IntentScope, SimpleSignature},
42};
43use rand::{
44 SeedableRng,
45 rngs::{OsRng, StdRng},
46};
47use roaring::RoaringBitmap;
48use serde::{Deserialize, Serialize};
49use serde_with::{Bytes, serde_as};
50use tracing::{instrument, warn};
51
52use crate::{
53 base_types::{AuthorityName, ConciseableName},
54 committee::{Committee, CommitteeTrait, EpochId, StakeUnit},
55 error::{IotaError, IotaResult},
56 iota_serde::{IotaBitmap, Readable},
57};
58
59#[cfg(test)]
60#[path = "unit_tests/crypto_tests.rs"]
61mod crypto_tests;
62
63#[cfg(test)]
64#[path = "unit_tests/intent_tests.rs"]
65mod intent_tests;
66
67pub type AuthorityKeyPair = BLS12381KeyPair;
84pub type AuthorityPublicKey = BLS12381PublicKey;
85pub type AuthorityPrivateKey = BLS12381PrivateKey;
86pub type AuthoritySignature = BLS12381Signature;
87pub type AggregateAuthoritySignature = BLS12381AggregateSignature;
88pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes;
89
90pub type AccountPrivateKey = Ed25519PrivateKey;
91
92pub type NetworkKeyPair = Ed25519KeyPair;
93pub type NetworkPublicKey = Ed25519PublicKey;
94pub type NetworkPrivateKey = Ed25519PrivateKey;
95
96pub type DefaultHash = Blake2b256;
97
98pub const DEFAULT_EPOCH_ID: EpochId = 0;
99pub const IOTA_PRIV_KEY_PREFIX: &str = "iotaprivkey";
100
101pub fn generate_proof_of_possession(
108 keypair: &AuthorityKeyPair,
109 address: Address,
110) -> AuthoritySignature {
111 let mut msg: Vec<u8> = Vec::new();
112 msg.extend_from_slice(keypair.public().as_bytes());
113 msg.extend_from_slice(address.as_ref());
114 AuthoritySignature::new_secure(
115 &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg),
116 &DEFAULT_EPOCH_ID,
117 keypair,
118 )
119}
120
121pub fn verify_proof_of_possession(
124 pop: &AuthoritySignature,
125 authority_pubkey: &AuthorityPublicKey,
126 iota_address: Address,
127) -> Result<(), IotaError> {
128 authority_pubkey
129 .validate()
130 .map_err(|_| IotaError::InvalidSignature {
131 error: "Fail to validate pubkey".to_string(),
132 })?;
133 let mut msg = authority_pubkey.as_bytes().to_vec();
134 msg.extend_from_slice(iota_address.as_ref());
135 pop.verify_secure(
136 &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg),
137 DEFAULT_EPOCH_ID,
138 authority_pubkey.into(),
139 )
140}
141
142pub fn network_to_simple_keypair(kp: &NetworkKeyPair) -> SimpleKeypair {
146 use iota_sdk_crypto::ToFromBytes as _;
147
148 SimpleKeypair::from(
149 Ed25519PrivateKey::from_bytes(kp.as_bytes()).expect("valid ed25519 private key bytes"),
150 )
151}
152
153pub fn simple_to_network_keypair(kp: &SimpleKeypair) -> Result<NetworkKeyPair, Error> {
156 if kp.scheme() != SignatureScheme::Ed25519 {
157 return Err(anyhow!(
158 "invalid scheme for network keypair: {}",
159 kp.scheme()
160 ));
161 }
162 NetworkKeyPair::from_bytes(&kp.to_bytes()[1..]).map_err(|e| anyhow!(e))
163}
164
165impl From<&SimpleKeypair> for PublicKey {
166 fn from(kp: &SimpleKeypair) -> Self {
167 match kp.public_key() {
168 iota_sdk_types::PublicKey::Ed25519(pk) => {
169 PublicKey::Ed25519(BytesRepresentation(pk.into_bytes()))
170 }
171 iota_sdk_types::PublicKey::Secp256k1(pk) => {
172 PublicKey::Secp256k1(BytesRepresentation(pk.into_bytes()))
173 }
174 iota_sdk_types::PublicKey::Secp256r1(pk) => {
175 PublicKey::Secp256r1(BytesRepresentation(pk.into_bytes()))
176 }
177 _ => unreachable!("SimpleKeypair keys use the three simple signature schemes"),
178 }
179 }
180}
181
182#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
183pub enum PublicKey {
184 Ed25519(Ed25519PublicKeyAsBytes),
185 Secp256k1(Secp256k1PublicKeyAsBytes),
186 Secp256r1(Secp256r1PublicKeyAsBytes),
187 Passkey(Secp256r1PublicKeyAsBytes),
188}
189
190impl AsRef<[u8]> for PublicKey {
191 fn as_ref(&self) -> &[u8] {
192 match self {
193 PublicKey::Ed25519(pk) => &pk.0,
194 PublicKey::Secp256k1(pk) => &pk.0,
195 PublicKey::Secp256r1(pk) => &pk.0,
196 PublicKey::Passkey(pk) => &pk.0,
197 }
198 }
199}
200
201impl EncodeDecodeBase64 for PublicKey {
202 fn encode_base64(&self) -> String {
203 let mut bytes: Vec<u8> = Vec::new();
204 bytes.extend_from_slice(&[self.flag()]);
205 bytes.extend_from_slice(self.as_ref());
206 Base64::encode(&bytes[..])
207 }
208
209 fn decode_base64(value: &str) -> FastCryptoResult<Self> {
210 let bytes = Base64::decode(value)?;
211 match bytes.first() {
212 Some(x) => {
213 if x == &SignatureScheme::Ed25519.to_u8() {
214 let pk: Ed25519PublicKey =
215 Ed25519PublicKey::from_bytes(bytes.get(1..).ok_or(
216 FastCryptoError::InputLengthWrong(Ed25519PublicKey::LENGTH + 1),
217 )?)?;
218 Ok(PublicKey::Ed25519((&pk).into()))
219 } else if x == &SignatureScheme::Secp256k1.to_u8() {
220 let pk = Secp256k1PublicKey::from_bytes(bytes.get(1..).ok_or(
221 FastCryptoError::InputLengthWrong(Secp256k1PublicKey::LENGTH + 1),
222 )?)?;
223 Ok(PublicKey::Secp256k1((&pk).into()))
224 } else if x == &SignatureScheme::Secp256r1.to_u8() {
225 let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
226 FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
227 )?)?;
228 Ok(PublicKey::Secp256r1((&pk).into()))
229 } else if x == &SignatureScheme::PasskeyAuthenticator.to_u8() {
230 let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
231 FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
232 )?)?;
233 Ok(PublicKey::Passkey((&pk).into()))
234 } else {
235 Err(FastCryptoError::InvalidInput)
236 }
237 }
238 _ => Err(FastCryptoError::InvalidInput),
239 }
240 }
241}
242
243impl PublicKey {
244 pub fn flag(&self) -> u8 {
245 self.scheme().to_u8()
246 }
247
248 pub fn try_from_bytes(
249 curve: SignatureScheme,
250 key_bytes: &[u8],
251 ) -> Result<PublicKey, eyre::Report> {
252 match curve {
253 SignatureScheme::Ed25519 => Ok(PublicKey::Ed25519(
254 (&Ed25519PublicKey::from_bytes(key_bytes)?).into(),
255 )),
256 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
257 (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(),
258 )),
259 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
260 (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
261 )),
262 SignatureScheme::PasskeyAuthenticator => Ok(PublicKey::Passkey(
263 (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
264 )),
265 _ => Err(eyre!("Unsupported curve")),
266 }
267 }
268
269 pub fn scheme(&self) -> SignatureScheme {
270 match self {
271 PublicKey::Ed25519(_) => SignatureScheme::Ed25519,
272 PublicKey::Secp256k1(_) => SignatureScheme::Secp256k1,
273 PublicKey::Secp256r1(_) => SignatureScheme::Secp256r1,
274 PublicKey::Passkey(_) => SignatureScheme::PasskeyAuthenticator,
275 }
276 }
277}
278
279#[serde_as]
282#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, AsRef)]
283#[as_ref(forward)]
284pub struct AuthorityPublicKeyBytes(
285 #[serde_as(as = "Readable<Base64, Bytes>")] pub [u8; AuthorityPublicKey::LENGTH],
286);
287
288impl AuthorityPublicKeyBytes {
289 fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
290 let s = Hex::encode(self.0);
291 write!(f, "k#{s}")?;
292 Ok(())
293 }
294}
295
296impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes {
297 type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>;
298 type ConciseType = ConciseAuthorityPublicKeyBytes;
299
300 fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> {
305 ConciseAuthorityPublicKeyBytesRef(self)
306 }
307
308 fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes {
309 ConciseAuthorityPublicKeyBytes(*self)
310 }
311}
312
313pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes);
315
316impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> {
317 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
318 let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
319 write!(f, "k#{s}..")
320 }
321}
322
323impl Display for ConciseAuthorityPublicKeyBytesRef<'_> {
324 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
325 Debug::fmt(self, f)
326 }
327}
328
329#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
331pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes);
332
333impl Debug for ConciseAuthorityPublicKeyBytes {
334 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
335 let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
336 write!(f, "k#{s}..")
337 }
338}
339
340impl Display for ConciseAuthorityPublicKeyBytes {
341 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
342 Debug::fmt(self, f)
343 }
344}
345
346impl TryFrom<AuthorityPublicKeyBytes> for AuthorityPublicKey {
347 type Error = FastCryptoError;
348
349 fn try_from(bytes: AuthorityPublicKeyBytes) -> Result<AuthorityPublicKey, Self::Error> {
350 AuthorityPublicKey::from_bytes(bytes.as_ref())
351 }
352}
353
354impl From<&AuthorityPublicKey> for AuthorityPublicKeyBytes {
355 fn from(pk: &AuthorityPublicKey) -> AuthorityPublicKeyBytes {
356 AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap()
357 }
358}
359
360impl Debug for AuthorityPublicKeyBytes {
361 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
362 self.fmt_impl(f)
363 }
364}
365
366impl Display for AuthorityPublicKeyBytes {
367 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
368 self.fmt_impl(f)
369 }
370}
371
372impl ToFromBytes for AuthorityPublicKeyBytes {
373 fn from_bytes(bytes: &[u8]) -> Result<Self, fastcrypto::error::FastCryptoError> {
374 let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes
375 .try_into()
376 .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?;
377 Ok(AuthorityPublicKeyBytes(bytes))
378 }
379}
380
381impl AuthorityPublicKeyBytes {
382 pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]);
383
384 pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes
387where {
388 AuthorityPublicKeyBytes(bytes)
389 }
390}
391
392impl FromStr for AuthorityPublicKeyBytes {
393 type Err = Error;
394
395 fn from_str(s: &str) -> Result<Self, Self::Err> {
396 let value = Hex::decode(s).map_err(|e| anyhow!(e))?;
397 Self::from_bytes(&value[..]).map_err(|e| anyhow!(e))
398 }
399}
400
401impl Default for AuthorityPublicKeyBytes {
402 fn default() -> Self {
403 Self::ZERO
404 }
405}
406
407pub trait IotaAuthoritySignature {
411 fn verify_secure<T>(
412 &self,
413 value: &IntentMessage<T>,
414 epoch_id: EpochId,
415 author: AuthorityPublicKeyBytes,
416 ) -> Result<(), IotaError>
417 where
418 T: Serialize;
419
420 fn new_secure<T>(
421 value: &IntentMessage<T>,
422 epoch_id: &EpochId,
423 secret: &dyn Signer<Self>,
424 ) -> Self
425 where
426 T: Serialize;
427}
428
429impl IotaAuthoritySignature for AuthoritySignature {
430 #[instrument(level = "trace", skip_all)]
431 fn new_secure<T>(value: &IntentMessage<T>, epoch: &EpochId, secret: &dyn Signer<Self>) -> Self
432 where
433 T: Serialize,
434 {
435 let mut intent_msg_bytes =
436 bcs::to_bytes(&value).expect("Message serialization should not fail");
437 epoch.write(&mut intent_msg_bytes);
438 secret.sign(&intent_msg_bytes)
439 }
440
441 #[instrument(level = "trace", skip_all)]
442 fn verify_secure<T>(
443 &self,
444 value: &IntentMessage<T>,
445 epoch: EpochId,
446 author: AuthorityPublicKeyBytes,
447 ) -> Result<(), IotaError>
448 where
449 T: Serialize,
450 {
451 let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail");
452 epoch.write(&mut message);
453
454 let public_key = AuthorityPublicKey::try_from(author).map_err(|_| {
455 IotaError::KeyConversion(
456 "Failed to serialize public key bytes to valid public key".to_string(),
457 )
458 })?;
459 public_key
460 .verify(&message[..], self)
461 .map_err(|e| IotaError::InvalidSignature {
462 error: format!(
463 "Fail to verify auth sig {} epoch: {} author: {}",
464 e,
465 epoch,
466 author.concise()
467 ),
468 })
469 }
470}
471
472pub trait RandomKeyPair: Sized {
475 fn generate_with_address(rng: &mut StdRng) -> (Address, Self);
476}
477
478impl RandomKeyPair for BLS12381KeyPair {
479 fn generate_with_address(rng: &mut StdRng) -> (Address, Self) {
480 let kp = <BLS12381KeyPair as KeypairTraits>::generate(rng);
481 let mut hasher = DefaultHash::default();
484 hasher.update([SignatureScheme::Bls12381.to_u8()]);
485 hasher.update(kp.public().as_ref());
486 (Address::new(hasher.finalize().digest), kp)
487 }
488}
489
490impl RandomKeyPair for Ed25519KeyPair {
491 fn generate_with_address(rng: &mut StdRng) -> (Address, Self) {
492 let kp = <Ed25519KeyPair as KeypairTraits>::generate(rng);
493 let public = PublicKey::Ed25519(BytesRepresentation(
494 kp.public()
495 .as_ref()
496 .try_into()
497 .expect("ed25519 public keys are 32 bytes"),
498 ));
499 (Address::from(&public), kp)
500 }
501}
502
503macro_rules! random_key_pair_from_sdk {
504 ($private_key:ty, $variant:ident) => {
505 impl RandomKeyPair for $private_key {
506 fn generate_with_address(rng: &mut StdRng) -> (Address, Self) {
507 let key = <$private_key>::random_with(rng);
508 let public =
509 PublicKey::$variant(BytesRepresentation(key.public_key().into_bytes()));
510 (Address::from(&public), key)
511 }
512 }
513 };
514}
515
516random_key_pair_from_sdk!(Ed25519PrivateKey, Ed25519);
517random_key_pair_from_sdk!(Secp256k1PrivateKey, Secp256k1);
518random_key_pair_from_sdk!(Secp256r1PrivateKey, Secp256r1);
519
520pub fn get_key_pair<KP: RandomKeyPair>() -> (Address, KP) {
523 get_key_pair_from_rng(&mut OsRng)
524}
525
526pub fn random_committee_key_pairs_of_size(size: usize) -> Vec<AuthorityKeyPair> {
528 let mut rng = StdRng::from_seed([0; 32]);
529 (0..size)
530 .map(|_| {
531 let key_pair = get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
537 get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
538 get_key_pair_from_rng::<AccountPrivateKey, _>(&mut rng);
539 get_key_pair_from_rng::<AccountPrivateKey, _>(&mut rng);
540 key_pair.1
541 })
542 .collect()
543}
544
545pub fn deterministic_random_account_private_key() -> (Address, AccountPrivateKey) {
546 let mut rng = StdRng::from_seed([0; 32]);
547 get_key_pair_from_rng(&mut rng)
548}
549
550pub fn get_account_private_key() -> (Address, AccountPrivateKey) {
551 get_key_pair()
552}
553
554pub fn get_authority_key_pair() -> (Address, AuthorityKeyPair) {
555 get_key_pair()
556}
557
558pub fn get_key_pair_from_rng<KP: RandomKeyPair, R>(csprng: &mut R) -> (Address, KP)
561where
562 R: rand::CryptoRng + rand::RngCore,
563{
564 KP::generate_with_address(&mut StdRng::from_rng(csprng).unwrap())
565}
566
567pub fn get_key_pair_from_bytes<KP: KeypairTraits>(bytes: &[u8]) -> IotaResult<KP> {
569 let priv_length = <KP as KeypairTraits>::PrivKey::LENGTH;
570 let pub_key_length = <KP as KeypairTraits>::PubKey::LENGTH;
571 if bytes.len() != priv_length + pub_key_length {
572 return Err(IotaError::KeyConversion(format!(
573 "Invalid input byte length, expected {}: {}",
574 priv_length + pub_key_length,
575 bytes.len()
576 )));
577 }
578 let sk = <KP as KeypairTraits>::PrivKey::from_bytes(
579 bytes
580 .get(..priv_length)
581 .ok_or(IotaError::InvalidPrivateKey)?,
582 )
583 .map_err(|_| IotaError::InvalidPrivateKey)?;
584 Ok(sk.into())
585}
586
587pub fn zero_ed25519_signature() -> SimpleSignature {
591 SimpleSignature::from_bytes([0u8; 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH])
594 .expect("zero-filled ed25519 signature has the expected length")
595}
596
597impl IotaPublicKey for BLS12381PublicKey {
601 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Bls12381;
602}
603
604impl IotaPublicKey for Ed25519PublicKey {
605 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Ed25519;
606}
607
608impl IotaPublicKey for Secp256k1PublicKey {
609 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
610}
611
612impl IotaPublicKey for Secp256r1PublicKey {
613 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
614}
615
616pub trait IotaPublicKey: VerifyingKey {
617 const SIGNATURE_SCHEME: SignatureScheme;
618}
619
620pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
627 fn verify_secure<T: Serialize>(
628 &self,
629 data: &T,
630 intent: Intent,
631 committee: &Committee,
632 ) -> IotaResult;
633
634 fn add_to_verification_obligation<'a>(
635 &self,
636 committee: &'a Committee,
637 obligation: &mut VerificationObligation<'a>,
638 message_index: usize,
639 ) -> IotaResult<()>;
640}
641
642#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
643pub struct EmptySignInfo {}
644impl AuthoritySignInfoTrait for EmptySignInfo {
645 fn verify_secure<T: Serialize>(
646 &self,
647 _data: &T,
648 _intent: Intent,
649 _committee: &Committee,
650 ) -> IotaResult {
651 Ok(())
652 }
653
654 fn add_to_verification_obligation<'a>(
655 &self,
656 _committee: &'a Committee,
657 _obligation: &mut VerificationObligation<'a>,
658 _message_index: usize,
659 ) -> IotaResult<()> {
660 Ok(())
661 }
662}
663
664#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
665pub struct AuthoritySignInfo {
666 pub epoch: EpochId,
667 pub authority: AuthorityName,
668 pub signature: AuthoritySignature,
669}
670
671impl AuthoritySignInfoTrait for AuthoritySignInfo {
672 #[instrument(level = "trace", skip_all)]
673 fn verify_secure<T: Serialize>(
674 &self,
675 data: &T,
676 intent: Intent,
677 committee: &Committee,
678 ) -> IotaResult<()> {
679 let mut obligation = VerificationObligation::default();
680 let idx = obligation.add_message(data, self.epoch, intent);
681 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
682 obligation.verify_all()?;
683 Ok(())
684 }
685
686 fn add_to_verification_obligation<'a>(
687 &self,
688 committee: &'a Committee,
689 obligation: &mut VerificationObligation<'a>,
690 message_index: usize,
691 ) -> IotaResult<()> {
692 fp_ensure!(
693 self.epoch == committee.epoch(),
694 IotaError::WrongEpoch {
695 expected_epoch: committee.epoch(),
696 actual_epoch: self.epoch,
697 }
698 );
699 let weight = committee.weight(&self.authority);
700 fp_ensure!(
701 weight > 0,
702 IotaError::UnknownSigner {
703 signer: Some(self.authority.concise().to_string()),
704 index: None,
705 committee: Box::new(committee.clone())
706 }
707 );
708
709 obligation
710 .public_keys
711 .get_mut(message_index)
712 .ok_or(IotaError::InvalidAddress)?
713 .push(committee.public_key(&self.authority)?);
714 obligation
715 .signatures
716 .get_mut(message_index)
717 .ok_or(IotaError::InvalidAddress)?
718 .add_signature(self.signature.clone())
719 .map_err(|_| IotaError::InvalidSignature {
720 error: "Fail to aggregator auth sig".to_string(),
721 })?;
722 Ok(())
723 }
724}
725
726impl AuthoritySignInfo {
727 pub fn new<T>(
728 epoch: EpochId,
729 value: &T,
730 intent: Intent,
731 name: AuthorityName,
732 secret: &dyn Signer<AuthoritySignature>,
733 ) -> Self
734 where
735 T: Serialize,
736 {
737 Self {
738 epoch,
739 authority: name,
740 signature: AuthoritySignature::new_secure(
741 &IntentMessage::new(intent, value),
742 &epoch,
743 secret,
744 ),
745 }
746 }
747}
748
749impl Hash for AuthoritySignInfo {
750 fn hash<H: Hasher>(&self, state: &mut H) {
751 self.epoch.hash(state);
752 self.authority.hash(state);
753 }
754}
755
756impl Display for AuthoritySignInfo {
757 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
758 write!(
759 f,
760 "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
761 self.epoch, self.authority,
762 )
763 }
764}
765
766impl PartialEq for AuthoritySignInfo {
767 fn eq(&self, other: &Self) -> bool {
768 self.epoch == other.epoch && self.authority == other.authority
771 }
772}
773
774#[serde_as]
781#[derive(Clone, Debug, Serialize, Deserialize)]
782pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
783 pub epoch: EpochId,
784 pub signature: AggregateAuthoritySignature,
785 #[serde_as(as = "IotaBitmap")]
786 pub signers_map: RoaringBitmap,
787}
788
789pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
790
791#[serde_as]
794#[derive(Clone, Debug, Serialize, Deserialize)]
795pub struct IotaAuthorityStrongQuorumSignInfo {
796 pub epoch: EpochId,
797 pub signature: AggregateAuthoritySignatureAsBytes,
798 #[serde_as(as = "IotaBitmap")]
799 pub signers_map: RoaringBitmap,
800}
801
802impl From<&AuthorityStrongQuorumSignInfo> for IotaAuthorityStrongQuorumSignInfo {
803 fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
804 Self {
805 epoch: info.epoch,
806 signature: (&info.signature).into(),
807 signers_map: info.signers_map.clone(),
808 }
809 }
810}
811
812impl TryFrom<&IotaAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
813 type Error = FastCryptoError;
814
815 fn try_from(info: &IotaAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
816 Ok(Self {
817 epoch: info.epoch,
818 signature: (&info.signature).try_into()?,
819 signers_map: info.signers_map.clone(),
820 })
821 }
822}
823
824static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
839
840impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
841 for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
842{
843 #[instrument(level = "trace", skip_all)]
844 fn verify_secure<T: Serialize>(
845 &self,
846 data: &T,
847 intent: Intent,
848 committee: &Committee,
849 ) -> IotaResult {
850 let mut obligation = VerificationObligation::default();
851 let idx = obligation.add_message(data, self.epoch, intent);
852 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
853 obligation.verify_all()?;
854 Ok(())
855 }
856
857 fn add_to_verification_obligation<'a>(
858 &self,
859 committee: &'a Committee,
860 obligation: &mut VerificationObligation<'a>,
861 message_index: usize,
862 ) -> IotaResult<()> {
863 fp_ensure!(
865 self.epoch == committee.epoch(),
866 IotaError::WrongEpoch {
867 expected_epoch: committee.epoch(),
868 actual_epoch: self.epoch,
869 }
870 );
871
872 let mut weight = 0;
873
874 obligation
876 .signatures
877 .get_mut(message_index)
878 .ok_or(IotaError::InvalidAuthenticator)?
879 .add_aggregate(self.signature.clone())
880 .map_err(|_| IotaError::InvalidSignature {
881 error: "Signature Aggregation failed".to_string(),
882 })?;
883
884 let selected_public_keys = obligation
885 .public_keys
886 .get_mut(message_index)
887 .ok_or(IotaError::InvalidAuthenticator)?;
888
889 for authority_index in self.signers_map.iter() {
890 let authority = committee
891 .authority_by_index(authority_index)
892 .ok_or_else(|| IotaError::UnknownSigner {
893 signer: None,
894 index: Some(authority_index),
895 committee: Box::new(committee.clone()),
896 })?;
897 let voting_rights = committee.weight(authority);
898 fp_ensure!(
899 voting_rights > 0,
900 IotaError::UnknownSigner {
901 signer: Some(authority.concise().to_string()),
902 index: Some(authority_index),
903 committee: Box::new(committee.clone()),
904 }
905 );
906 weight += voting_rights;
907
908 selected_public_keys.push(committee.public_key(authority)?);
909 }
910
911 fp_ensure!(
912 weight >= Self::quorum_threshold(committee),
913 IotaError::CertificateRequiresQuorum
914 );
915
916 Ok(())
917 }
918}
919
920impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
921 pub fn new_from_auth_sign_infos(
922 auth_sign_infos: Vec<AuthoritySignInfo>,
923 committee: &Committee,
924 ) -> IotaResult<Self> {
925 fp_ensure!(
926 auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
927 IotaError::InvalidSignature {
928 error: "All signatures must be from the same epoch as the committee".to_string()
929 }
930 );
931 let total_stake: StakeUnit = auth_sign_infos
932 .iter()
933 .map(|a| committee.weight(&a.authority))
934 .sum();
935 fp_ensure!(
936 total_stake >= Self::quorum_threshold(committee),
937 IotaError::InvalidSignature {
938 error: "Signatures don't have enough stake to form a quorum".to_string()
939 }
940 );
941
942 let signatures: BTreeMap<_, _> = auth_sign_infos
943 .into_iter()
944 .map(|a| (a.authority, a.signature))
945 .collect();
946 let mut map = RoaringBitmap::new();
947 for pk in signatures.keys() {
948 map.insert(
949 committee
950 .authority_index(pk)
951 .ok_or_else(|| IotaError::UnknownSigner {
952 signer: Some(pk.concise().to_string()),
953 index: None,
954 committee: Box::new(committee.clone()),
955 })?,
956 );
957 }
958 let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
959
960 Ok(AuthorityQuorumSignInfo {
961 epoch: committee.epoch,
962 signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
963 IotaError::InvalidSignature {
964 error: e.to_string(),
965 }
966 })?,
967 signers_map: map,
968 })
969 }
970
971 pub fn authorities<'a>(
972 &'a self,
973 committee: &'a Committee,
974 ) -> impl Iterator<Item = IotaResult<&'a AuthorityName>> {
975 self.signers_map.iter().map(|i| {
976 committee
977 .authority_by_index(i)
978 .ok_or(IotaError::InvalidAuthenticator)
979 })
980 }
981
982 pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
983 committee.threshold::<STRONG_THRESHOLD>()
984 }
985
986 pub fn len(&self) -> u64 {
987 self.signers_map.len()
988 }
989
990 pub fn is_empty(&self) -> bool {
991 self.signers_map.is_empty()
992 }
993}
994
995impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
996 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
997 writeln!(
998 f,
999 "{} {{ epoch: {:?}, signers_map: {:?} }}",
1000 if S {
1001 "AuthorityStrongQuorumSignInfo"
1002 } else {
1003 "AuthorityWeakQuorumSignInfo"
1004 },
1005 self.epoch,
1006 self.signers_map,
1007 )?;
1008 Ok(())
1009 }
1010}
1011
1012mod private {
1013 pub trait SealedAuthoritySignInfoTrait {}
1014 impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1015 impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1016 impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1017}
1018
1019pub trait Signable<W> {
1021 fn write(&self, writer: &mut W);
1022}
1023
1024mod bcs_signable {
1036
1037 pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1038 impl BcsSignable for crate::committee::Committee {}
1039 impl BcsSignable for iota_sdk_types::checkpoint::CheckpointSummary {}
1040 impl BcsSignable for iota_sdk_types::checkpoint::CheckpointContents {}
1041 #[cfg(not(target_arch = "wasm32"))]
1042 impl BcsSignable for crate::messages_consensus::VersionedMisbehaviorReport {}
1043
1044 impl BcsSignable for iota_sdk_types::TransactionEffects {}
1045 impl BcsSignable for iota_sdk_types::TransactionEvents {}
1046 impl BcsSignable for iota_sdk_types::Transaction {}
1047 impl BcsSignable for iota_sdk_types::SenderSignedTransaction {}
1048 impl BcsSignable for crate::object::ObjectInner {}
1049
1050 impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1051
1052 impl BcsSignable for super::bcs_signable_test::Foo {}
1053 #[cfg(test)]
1054 impl BcsSignable for super::bcs_signable_test::Bar {}
1055}
1056
1057impl<T, W> Signable<W> for T
1058where
1059 T: bcs_signable::BcsSignable,
1060 W: std::io::Write,
1061{
1062 fn write(&self, writer: &mut W) {
1063 let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1064 write!(writer, "{name}::").expect("Hasher should not fail");
1066 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1067 }
1068}
1069
1070impl<W> Signable<W> for EpochId
1071where
1072 W: std::io::Write,
1073{
1074 fn write(&self, writer: &mut W) {
1075 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1076 }
1077}
1078
1079fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1080 signable: &S,
1081) -> [u8; DIGEST_SIZE] {
1082 let mut digest = H::default();
1083 signable.write(&mut digest);
1084 let hash = digest.finalize();
1085 hash.into()
1086}
1087
1088pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1089 hash::<S, DefaultHash, 32>(signable)
1090}
1091
1092#[derive(Default)]
1093pub struct VerificationObligation<'a> {
1094 pub messages: Vec<Vec<u8>>,
1095 pub signatures: Vec<AggregateAuthoritySignature>,
1096 pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1097}
1098
1099impl<'a> VerificationObligation<'a> {
1100 pub fn new() -> VerificationObligation<'a> {
1101 VerificationObligation::default()
1102 }
1103
1104 pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1107 where
1108 T: Serialize,
1109 {
1110 let intent_msg = IntentMessage::new(intent, message_value);
1111 let mut intent_msg_bytes =
1112 bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1113 epoch.write(&mut intent_msg_bytes);
1114 self.signatures.push(AggregateAuthoritySignature::default());
1115 self.public_keys.push(Vec::new());
1116 self.messages.push(intent_msg_bytes);
1117 self.messages.len() - 1
1118 }
1119
1120 pub fn add_signature_and_public_key(
1123 &mut self,
1124 signature: &AuthoritySignature,
1125 public_key: &'a AuthorityPublicKey,
1126 idx: usize,
1127 ) -> IotaResult<()> {
1128 self.public_keys
1129 .get_mut(idx)
1130 .ok_or(IotaError::InvalidAuthenticator)?
1131 .push(public_key);
1132 self.signatures
1133 .get_mut(idx)
1134 .ok_or(IotaError::InvalidAuthenticator)?
1135 .add_signature(signature.clone())
1136 .map_err(|_| IotaError::InvalidSignature {
1137 error: "Failed to add signature to obligation".to_string(),
1138 })?;
1139 Ok(())
1140 }
1141
1142 #[instrument(level = "trace", skip_all)]
1143 pub fn verify_all(self) -> IotaResult<()> {
1144 let mut pks = Vec::with_capacity(self.public_keys.len());
1145 for pk in self.public_keys.clone() {
1146 pks.push(pk.into_iter());
1147 }
1148 AggregateAuthoritySignature::batch_verify(
1149 &self.signatures.iter().collect::<Vec<_>>()[..],
1150 pks,
1151 &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1152 )
1153 .map_err(|e| {
1154 let message = format!(
1155 "pks: {:?}, messages: {:?}, sigs: {:?}",
1156 self.public_keys,
1157 self.messages
1158 .iter()
1159 .map(Base64::encode)
1160 .collect::<Vec<String>>(),
1161 self.signatures
1162 .iter()
1163 .map(|s| Base64::encode(s.as_ref()))
1164 .collect::<Vec<String>>()
1165 );
1166
1167 let chunk_size = 2048;
1168
1169 for (i, chunk) in message
1172 .as_bytes()
1173 .chunks(chunk_size)
1174 .map(std::str::from_utf8)
1175 .enumerate()
1176 {
1177 warn!(
1178 "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1179 e,
1180 i,
1181 chunk.unwrap()
1182 );
1183 }
1184
1185 IotaError::InvalidSignature {
1186 error: format!("Failed to batch verify aggregated auth sig: {e}"),
1187 }
1188 })?;
1189 Ok(())
1190 }
1191}
1192
1193pub mod bcs_signable_test {
1194 use serde::{Deserialize, Serialize};
1195
1196 #[derive(Clone, Serialize, Deserialize)]
1197 pub struct Foo(pub String);
1198
1199 #[cfg(test)]
1200 #[derive(Serialize, Deserialize)]
1201 pub struct Bar(pub String);
1202
1203 #[cfg(test)]
1204 use super::VerificationObligation;
1205
1206 #[cfg(test)]
1207 pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1208 where
1209 T: super::bcs_signable::BcsSignable,
1210 {
1211 use iota_sdk_types::crypto::{Intent, IntentScope};
1212
1213 let mut obligation = VerificationObligation::default();
1214 let idx = obligation.add_message(
1216 value,
1217 0,
1218 Intent::iota_app(IntentScope::SenderSignedTransaction),
1219 );
1220 (obligation, idx)
1221 }
1222}
1223
1224impl FromStr for PublicKey {
1225 type Err = eyre::Report;
1226 fn from_str(s: &str) -> Result<Self, Self::Err> {
1227 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1228 }
1229}
1230
1231#[cfg(not(target_arch = "wasm32"))]
1234pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1235#[cfg(not(target_arch = "wasm32"))]
1236pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1237#[cfg(not(target_arch = "wasm32"))]
1238pub type RandomnessPrivateKey =
1239 fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;