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