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