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 AccountKeyPair = 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_inner()))
170 }
171 iota_sdk_types::PublicKey::Secp256k1(pk) => {
172 PublicKey::Secp256k1(BytesRepresentation(pk.into_inner()))
173 }
174 iota_sdk_types::PublicKey::Secp256r1(pk) => {
175 PublicKey::Secp256r1(BytesRepresentation(pk.into_inner()))
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 kp = <$private_key>::random_with(rng);
508 let public = PublicKey::$variant(BytesRepresentation(kp.public_key().into_inner()));
509 (Address::from(&public), kp)
510 }
511 }
512 };
513}
514
515random_key_pair_from_sdk!(Ed25519PrivateKey, Ed25519);
516random_key_pair_from_sdk!(Secp256k1PrivateKey, Secp256k1);
517random_key_pair_from_sdk!(Secp256r1PrivateKey, Secp256r1);
518
519pub fn get_key_pair<KP: RandomKeyPair>() -> (Address, KP) {
522 get_key_pair_from_rng(&mut OsRng)
523}
524
525pub fn random_committee_key_pairs_of_size(size: usize) -> Vec<AuthorityKeyPair> {
527 let mut rng = StdRng::from_seed([0; 32]);
528 (0..size)
529 .map(|_| {
530 let key_pair = get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
536 get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
537 get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
538 get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
539 key_pair.1
540 })
541 .collect()
542}
543
544pub fn deterministic_random_account_key() -> (Address, AccountKeyPair) {
545 let mut rng = StdRng::from_seed([0; 32]);
546 get_key_pair_from_rng(&mut rng)
547}
548
549pub fn get_account_key_pair() -> (Address, AccountKeyPair) {
550 get_key_pair()
551}
552
553pub fn get_authority_key_pair() -> (Address, AuthorityKeyPair) {
554 get_key_pair()
555}
556
557pub fn get_key_pair_from_rng<KP: RandomKeyPair, R>(csprng: &mut R) -> (Address, KP)
560where
561 R: rand::CryptoRng + rand::RngCore,
562{
563 KP::generate_with_address(&mut StdRng::from_rng(csprng).unwrap())
564}
565
566pub fn get_key_pair_from_bytes<KP: KeypairTraits>(bytes: &[u8]) -> IotaResult<KP> {
568 let priv_length = <KP as KeypairTraits>::PrivKey::LENGTH;
569 let pub_key_length = <KP as KeypairTraits>::PubKey::LENGTH;
570 if bytes.len() != priv_length + pub_key_length {
571 return Err(IotaError::KeyConversion(format!(
572 "Invalid input byte length, expected {}: {}",
573 priv_length + pub_key_length,
574 bytes.len()
575 )));
576 }
577 let sk = <KP as KeypairTraits>::PrivKey::from_bytes(
578 bytes
579 .get(..priv_length)
580 .ok_or(IotaError::InvalidPrivateKey)?,
581 )
582 .map_err(|_| IotaError::InvalidPrivateKey)?;
583 Ok(sk.into())
584}
585
586pub fn zero_ed25519_signature() -> SimpleSignature {
590 SimpleSignature::from_bytes([0u8; 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH])
593 .expect("zero-filled ed25519 signature has the expected length")
594}
595
596impl IotaPublicKey for BLS12381PublicKey {
600 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Bls12381;
601}
602
603impl IotaPublicKey for Ed25519PublicKey {
604 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Ed25519;
605}
606
607impl IotaPublicKey for Secp256k1PublicKey {
608 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
609}
610
611impl IotaPublicKey for Secp256r1PublicKey {
612 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
613}
614
615pub trait IotaPublicKey: VerifyingKey {
616 const SIGNATURE_SCHEME: SignatureScheme;
617}
618
619pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
626 fn verify_secure<T: Serialize>(
627 &self,
628 data: &T,
629 intent: Intent,
630 committee: &Committee,
631 ) -> IotaResult;
632
633 fn add_to_verification_obligation<'a>(
634 &self,
635 committee: &'a Committee,
636 obligation: &mut VerificationObligation<'a>,
637 message_index: usize,
638 ) -> IotaResult<()>;
639}
640
641#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
642pub struct EmptySignInfo {}
643impl AuthoritySignInfoTrait for EmptySignInfo {
644 fn verify_secure<T: Serialize>(
645 &self,
646 _data: &T,
647 _intent: Intent,
648 _committee: &Committee,
649 ) -> IotaResult {
650 Ok(())
651 }
652
653 fn add_to_verification_obligation<'a>(
654 &self,
655 _committee: &'a Committee,
656 _obligation: &mut VerificationObligation<'a>,
657 _message_index: usize,
658 ) -> IotaResult<()> {
659 Ok(())
660 }
661}
662
663#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
664pub struct AuthoritySignInfo {
665 pub epoch: EpochId,
666 pub authority: AuthorityName,
667 pub signature: AuthoritySignature,
668}
669
670impl AuthoritySignInfoTrait for AuthoritySignInfo {
671 #[instrument(level = "trace", skip_all)]
672 fn verify_secure<T: Serialize>(
673 &self,
674 data: &T,
675 intent: Intent,
676 committee: &Committee,
677 ) -> IotaResult<()> {
678 let mut obligation = VerificationObligation::default();
679 let idx = obligation.add_message(data, self.epoch, intent);
680 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
681 obligation.verify_all()?;
682 Ok(())
683 }
684
685 fn add_to_verification_obligation<'a>(
686 &self,
687 committee: &'a Committee,
688 obligation: &mut VerificationObligation<'a>,
689 message_index: usize,
690 ) -> IotaResult<()> {
691 fp_ensure!(
692 self.epoch == committee.epoch(),
693 IotaError::WrongEpoch {
694 expected_epoch: committee.epoch(),
695 actual_epoch: self.epoch,
696 }
697 );
698 let weight = committee.weight(&self.authority);
699 fp_ensure!(
700 weight > 0,
701 IotaError::UnknownSigner {
702 signer: Some(self.authority.concise().to_string()),
703 index: None,
704 committee: Box::new(committee.clone())
705 }
706 );
707
708 obligation
709 .public_keys
710 .get_mut(message_index)
711 .ok_or(IotaError::InvalidAddress)?
712 .push(committee.public_key(&self.authority)?);
713 obligation
714 .signatures
715 .get_mut(message_index)
716 .ok_or(IotaError::InvalidAddress)?
717 .add_signature(self.signature.clone())
718 .map_err(|_| IotaError::InvalidSignature {
719 error: "Fail to aggregator auth sig".to_string(),
720 })?;
721 Ok(())
722 }
723}
724
725impl AuthoritySignInfo {
726 pub fn new<T>(
727 epoch: EpochId,
728 value: &T,
729 intent: Intent,
730 name: AuthorityName,
731 secret: &dyn Signer<AuthoritySignature>,
732 ) -> Self
733 where
734 T: Serialize,
735 {
736 Self {
737 epoch,
738 authority: name,
739 signature: AuthoritySignature::new_secure(
740 &IntentMessage::new(intent, value),
741 &epoch,
742 secret,
743 ),
744 }
745 }
746}
747
748impl Hash for AuthoritySignInfo {
749 fn hash<H: Hasher>(&self, state: &mut H) {
750 self.epoch.hash(state);
751 self.authority.hash(state);
752 }
753}
754
755impl Display for AuthoritySignInfo {
756 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
757 write!(
758 f,
759 "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
760 self.epoch, self.authority,
761 )
762 }
763}
764
765impl PartialEq for AuthoritySignInfo {
766 fn eq(&self, other: &Self) -> bool {
767 self.epoch == other.epoch && self.authority == other.authority
770 }
771}
772
773#[serde_as]
780#[derive(Clone, Debug, Serialize, Deserialize)]
781pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
782 pub epoch: EpochId,
783 pub signature: AggregateAuthoritySignature,
784 #[serde_as(as = "IotaBitmap")]
785 pub signers_map: RoaringBitmap,
786}
787
788pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
789
790#[serde_as]
793#[derive(Clone, Debug, Serialize, Deserialize)]
794pub struct IotaAuthorityStrongQuorumSignInfo {
795 pub epoch: EpochId,
796 pub signature: AggregateAuthoritySignatureAsBytes,
797 #[serde_as(as = "IotaBitmap")]
798 pub signers_map: RoaringBitmap,
799}
800
801impl From<&AuthorityStrongQuorumSignInfo> for IotaAuthorityStrongQuorumSignInfo {
802 fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
803 Self {
804 epoch: info.epoch,
805 signature: (&info.signature).into(),
806 signers_map: info.signers_map.clone(),
807 }
808 }
809}
810
811impl TryFrom<&IotaAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
812 type Error = FastCryptoError;
813
814 fn try_from(info: &IotaAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
815 Ok(Self {
816 epoch: info.epoch,
817 signature: (&info.signature).try_into()?,
818 signers_map: info.signers_map.clone(),
819 })
820 }
821}
822
823static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
838
839impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
840 for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
841{
842 #[instrument(level = "trace", skip_all)]
843 fn verify_secure<T: Serialize>(
844 &self,
845 data: &T,
846 intent: Intent,
847 committee: &Committee,
848 ) -> IotaResult {
849 let mut obligation = VerificationObligation::default();
850 let idx = obligation.add_message(data, self.epoch, intent);
851 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
852 obligation.verify_all()?;
853 Ok(())
854 }
855
856 fn add_to_verification_obligation<'a>(
857 &self,
858 committee: &'a Committee,
859 obligation: &mut VerificationObligation<'a>,
860 message_index: usize,
861 ) -> IotaResult<()> {
862 fp_ensure!(
864 self.epoch == committee.epoch(),
865 IotaError::WrongEpoch {
866 expected_epoch: committee.epoch(),
867 actual_epoch: self.epoch,
868 }
869 );
870
871 let mut weight = 0;
872
873 obligation
875 .signatures
876 .get_mut(message_index)
877 .ok_or(IotaError::InvalidAuthenticator)?
878 .add_aggregate(self.signature.clone())
879 .map_err(|_| IotaError::InvalidSignature {
880 error: "Signature Aggregation failed".to_string(),
881 })?;
882
883 let selected_public_keys = obligation
884 .public_keys
885 .get_mut(message_index)
886 .ok_or(IotaError::InvalidAuthenticator)?;
887
888 for authority_index in self.signers_map.iter() {
889 let authority = committee
890 .authority_by_index(authority_index)
891 .ok_or_else(|| IotaError::UnknownSigner {
892 signer: None,
893 index: Some(authority_index),
894 committee: Box::new(committee.clone()),
895 })?;
896 let voting_rights = committee.weight(authority);
897 fp_ensure!(
898 voting_rights > 0,
899 IotaError::UnknownSigner {
900 signer: Some(authority.concise().to_string()),
901 index: Some(authority_index),
902 committee: Box::new(committee.clone()),
903 }
904 );
905 weight += voting_rights;
906
907 selected_public_keys.push(committee.public_key(authority)?);
908 }
909
910 fp_ensure!(
911 weight >= Self::quorum_threshold(committee),
912 IotaError::CertificateRequiresQuorum
913 );
914
915 Ok(())
916 }
917}
918
919impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
920 pub fn new_from_auth_sign_infos(
921 auth_sign_infos: Vec<AuthoritySignInfo>,
922 committee: &Committee,
923 ) -> IotaResult<Self> {
924 fp_ensure!(
925 auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
926 IotaError::InvalidSignature {
927 error: "All signatures must be from the same epoch as the committee".to_string()
928 }
929 );
930 let total_stake: StakeUnit = auth_sign_infos
931 .iter()
932 .map(|a| committee.weight(&a.authority))
933 .sum();
934 fp_ensure!(
935 total_stake >= Self::quorum_threshold(committee),
936 IotaError::InvalidSignature {
937 error: "Signatures don't have enough stake to form a quorum".to_string()
938 }
939 );
940
941 let signatures: BTreeMap<_, _> = auth_sign_infos
942 .into_iter()
943 .map(|a| (a.authority, a.signature))
944 .collect();
945 let mut map = RoaringBitmap::new();
946 for pk in signatures.keys() {
947 map.insert(
948 committee
949 .authority_index(pk)
950 .ok_or_else(|| IotaError::UnknownSigner {
951 signer: Some(pk.concise().to_string()),
952 index: None,
953 committee: Box::new(committee.clone()),
954 })?,
955 );
956 }
957 let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
958
959 Ok(AuthorityQuorumSignInfo {
960 epoch: committee.epoch,
961 signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
962 IotaError::InvalidSignature {
963 error: e.to_string(),
964 }
965 })?,
966 signers_map: map,
967 })
968 }
969
970 pub fn authorities<'a>(
971 &'a self,
972 committee: &'a Committee,
973 ) -> impl Iterator<Item = IotaResult<&'a AuthorityName>> {
974 self.signers_map.iter().map(|i| {
975 committee
976 .authority_by_index(i)
977 .ok_or(IotaError::InvalidAuthenticator)
978 })
979 }
980
981 pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
982 committee.threshold::<STRONG_THRESHOLD>()
983 }
984
985 pub fn len(&self) -> u64 {
986 self.signers_map.len()
987 }
988
989 pub fn is_empty(&self) -> bool {
990 self.signers_map.is_empty()
991 }
992}
993
994impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
995 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
996 writeln!(
997 f,
998 "{} {{ epoch: {:?}, signers_map: {:?} }}",
999 if S {
1000 "AuthorityStrongQuorumSignInfo"
1001 } else {
1002 "AuthorityWeakQuorumSignInfo"
1003 },
1004 self.epoch,
1005 self.signers_map,
1006 )?;
1007 Ok(())
1008 }
1009}
1010
1011mod private {
1012 pub trait SealedAuthoritySignInfoTrait {}
1013 impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1014 impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1015 impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1016}
1017
1018pub trait Signable<W> {
1020 fn write(&self, writer: &mut W);
1021}
1022
1023mod bcs_signable {
1035
1036 pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1037 impl BcsSignable for crate::committee::Committee {}
1038 impl BcsSignable for iota_sdk_types::checkpoint::CheckpointSummary {}
1039 impl BcsSignable for iota_sdk_types::checkpoint::CheckpointContents {}
1040 #[cfg(not(target_arch = "wasm32"))]
1041 impl BcsSignable for crate::messages_consensus::VersionedMisbehaviorReport {}
1042
1043 impl BcsSignable for iota_sdk_types::TransactionEffects {}
1044 impl BcsSignable for iota_sdk_types::TransactionEvents {}
1045 impl BcsSignable for iota_sdk_types::Transaction {}
1046 impl BcsSignable for iota_sdk_types::SenderSignedTransaction {}
1047 impl BcsSignable for crate::object::ObjectInner {}
1048
1049 impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1050
1051 impl BcsSignable for super::bcs_signable_test::Foo {}
1052 #[cfg(test)]
1053 impl BcsSignable for super::bcs_signable_test::Bar {}
1054}
1055
1056impl<T, W> Signable<W> for T
1057where
1058 T: bcs_signable::BcsSignable,
1059 W: std::io::Write,
1060{
1061 fn write(&self, writer: &mut W) {
1062 let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1063 write!(writer, "{name}::").expect("Hasher should not fail");
1065 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1066 }
1067}
1068
1069impl<W> Signable<W> for EpochId
1070where
1071 W: std::io::Write,
1072{
1073 fn write(&self, writer: &mut W) {
1074 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1075 }
1076}
1077
1078fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1079 signable: &S,
1080) -> [u8; DIGEST_SIZE] {
1081 let mut digest = H::default();
1082 signable.write(&mut digest);
1083 let hash = digest.finalize();
1084 hash.into()
1085}
1086
1087pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1088 hash::<S, DefaultHash, 32>(signable)
1089}
1090
1091#[derive(Default)]
1092pub struct VerificationObligation<'a> {
1093 pub messages: Vec<Vec<u8>>,
1094 pub signatures: Vec<AggregateAuthoritySignature>,
1095 pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1096}
1097
1098impl<'a> VerificationObligation<'a> {
1099 pub fn new() -> VerificationObligation<'a> {
1100 VerificationObligation::default()
1101 }
1102
1103 pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1106 where
1107 T: Serialize,
1108 {
1109 let intent_msg = IntentMessage::new(intent, message_value);
1110 let mut intent_msg_bytes =
1111 bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1112 epoch.write(&mut intent_msg_bytes);
1113 self.signatures.push(AggregateAuthoritySignature::default());
1114 self.public_keys.push(Vec::new());
1115 self.messages.push(intent_msg_bytes);
1116 self.messages.len() - 1
1117 }
1118
1119 pub fn add_signature_and_public_key(
1122 &mut self,
1123 signature: &AuthoritySignature,
1124 public_key: &'a AuthorityPublicKey,
1125 idx: usize,
1126 ) -> IotaResult<()> {
1127 self.public_keys
1128 .get_mut(idx)
1129 .ok_or(IotaError::InvalidAuthenticator)?
1130 .push(public_key);
1131 self.signatures
1132 .get_mut(idx)
1133 .ok_or(IotaError::InvalidAuthenticator)?
1134 .add_signature(signature.clone())
1135 .map_err(|_| IotaError::InvalidSignature {
1136 error: "Failed to add signature to obligation".to_string(),
1137 })?;
1138 Ok(())
1139 }
1140
1141 #[instrument(level = "trace", skip_all)]
1142 pub fn verify_all(self) -> IotaResult<()> {
1143 let mut pks = Vec::with_capacity(self.public_keys.len());
1144 for pk in self.public_keys.clone() {
1145 pks.push(pk.into_iter());
1146 }
1147 AggregateAuthoritySignature::batch_verify(
1148 &self.signatures.iter().collect::<Vec<_>>()[..],
1149 pks,
1150 &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1151 )
1152 .map_err(|e| {
1153 let message = format!(
1154 "pks: {:?}, messages: {:?}, sigs: {:?}",
1155 self.public_keys,
1156 self.messages
1157 .iter()
1158 .map(Base64::encode)
1159 .collect::<Vec<String>>(),
1160 self.signatures
1161 .iter()
1162 .map(|s| Base64::encode(s.as_ref()))
1163 .collect::<Vec<String>>()
1164 );
1165
1166 let chunk_size = 2048;
1167
1168 for (i, chunk) in message
1171 .as_bytes()
1172 .chunks(chunk_size)
1173 .map(std::str::from_utf8)
1174 .enumerate()
1175 {
1176 warn!(
1177 "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1178 e,
1179 i,
1180 chunk.unwrap()
1181 );
1182 }
1183
1184 IotaError::InvalidSignature {
1185 error: format!("Failed to batch verify aggregated auth sig: {e}"),
1186 }
1187 })?;
1188 Ok(())
1189 }
1190}
1191
1192pub mod bcs_signable_test {
1193 use serde::{Deserialize, Serialize};
1194
1195 #[derive(Clone, Serialize, Deserialize)]
1196 pub struct Foo(pub String);
1197
1198 #[cfg(test)]
1199 #[derive(Serialize, Deserialize)]
1200 pub struct Bar(pub String);
1201
1202 #[cfg(test)]
1203 use super::VerificationObligation;
1204
1205 #[cfg(test)]
1206 pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1207 where
1208 T: super::bcs_signable::BcsSignable,
1209 {
1210 use iota_sdk_types::crypto::{Intent, IntentScope};
1211
1212 let mut obligation = VerificationObligation::default();
1213 let idx = obligation.add_message(
1215 value,
1216 0,
1217 Intent::iota_app(IntentScope::SenderSignedTransaction),
1218 );
1219 (obligation, idx)
1220 }
1221}
1222
1223impl FromStr for PublicKey {
1224 type Err = eyre::Report;
1225 fn from_str(s: &str) -> Result<Self, Self::Err> {
1226 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1227 }
1228}
1229
1230#[cfg(not(target_arch = "wasm32"))]
1233pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1234#[cfg(not(target_arch = "wasm32"))]
1235pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1236#[cfg(not(target_arch = "wasm32"))]
1237pub type RandomnessPrivateKey =
1238 fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;