sui_types/
signature_verification.rs1use nonempty::NonEmpty;
5use shared_crypto::intent::Intent;
6
7use crate::base_types::SuiAddress;
8use crate::committee::EpochId;
9use crate::digests::ZKLoginInputsDigest;
10use crate::error::{SuiErrorKind, SuiResult};
11use crate::signature::VerifyParams;
12use crate::transaction::{SenderSignedData, TransactionDataAPI};
13use lru::LruCache;
14use parking_lot::RwLock;
15use prometheus::IntCounter;
16use std::hash::Hash;
17use std::sync::Arc;
18
19const VERIFIED_CERTIFICATE_CACHE_SIZE: usize = 100_000;
24
25pub struct VerifiedDigestCache<D> {
26 inner: RwLock<LruCache<D, ()>>,
27 cache_hits_counter: IntCounter,
28 cache_misses_counter: IntCounter,
29 cache_evictions_counter: IntCounter,
30}
31
32impl<D: Hash + Eq + Copy> VerifiedDigestCache<D> {
33 pub fn new(
34 cache_hits_counter: IntCounter,
35 cache_misses_counter: IntCounter,
36 cache_evictions_counter: IntCounter,
37 ) -> Self {
38 Self {
39 inner: RwLock::new(LruCache::new(
40 std::num::NonZeroUsize::new(VERIFIED_CERTIFICATE_CACHE_SIZE).unwrap(),
41 )),
42 cache_hits_counter,
43 cache_misses_counter,
44 cache_evictions_counter,
45 }
46 }
47
48 pub fn is_cached(&self, digest: &D) -> bool {
49 let inner = self.inner.read();
50 if inner.contains(digest) {
51 self.cache_hits_counter.inc();
52 true
53 } else {
54 self.cache_misses_counter.inc();
55 false
56 }
57 }
58
59 pub fn cache_digest(&self, digest: D) {
60 let mut inner = self.inner.write();
61 if let Some(old) = inner.push(digest, ())
62 && old.0 != digest
63 {
64 self.cache_evictions_counter.inc();
65 }
66 }
67
68 pub fn cache_digests(&self, digests: Vec<D>) {
69 let mut inner = self.inner.write();
70 digests.into_iter().for_each(|d| {
71 if let Some(old) = inner.push(d, ())
72 && old.0 != d
73 {
74 self.cache_evictions_counter.inc();
75 }
76 });
77 }
78
79 pub fn is_verified<F, G>(&self, digest: D, verify_callback: F, uncached_checks: G) -> SuiResult
80 where
81 F: FnOnce() -> SuiResult,
82 G: FnOnce() -> SuiResult,
83 {
84 if !self.is_cached(&digest) {
85 verify_callback()?;
86 self.cache_digest(digest);
87 } else {
88 uncached_checks()?;
90 }
91 Ok(())
92 }
93
94 pub fn clear(&self) {
95 let mut inner = self.inner.write();
96 inner.clear();
97 }
98
99 pub fn new_empty() -> Self {
101 Self::new(
102 IntCounter::new("test_cache_hits", "test cache hits").unwrap(),
103 IntCounter::new("test_cache_misses", "test cache misses").unwrap(),
104 IntCounter::new("test_cache_evictions", "test cache evictions").unwrap(),
105 )
106 }
107}
108
109pub fn verify_sender_signed_data_message_signatures(
111 txn: &SenderSignedData,
112 current_epoch: EpochId,
113 verify_params: &VerifyParams,
114 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
115 aliased_addresses: Vec<(SuiAddress, NonEmpty<SuiAddress>)>,
116) -> SuiResult {
117 let intent_message = txn.intent_message();
118 assert_eq!(intent_message.intent, Intent::sui_transaction());
119
120 if intent_message.value.is_system_tx() {
123 return Ok(());
124 }
125
126 let required_signers = txn.intent_message().value.required_signers();
128 fp_ensure!(
129 txn.inner().tx_signatures.len() == required_signers.len(),
130 SuiErrorKind::SignerSignatureNumberMismatch {
131 actual: txn.inner().tx_signatures.len(),
132 expected: required_signers.len()
133 }
134 .into()
135 );
136
137 let present_sigs = txn.get_signer_sig_mapping(verify_params.verify_legacy_zklogin_address)?;
139 let required_signer_alias_sets = required_signers.map(|s| {
140 aliased_addresses
141 .iter()
142 .find(|(addr, _)| *addr == s)
143 .map(|(_, aliases)| aliases.clone())
144 .unwrap_or(NonEmpty::new(s))
145 });
146 for s in required_signer_alias_sets {
147 if !s.iter().any(|s| present_sigs.contains_key(s)) {
148 return Err(SuiErrorKind::SignerSignatureAbsent {
149 expected: s
150 .iter()
151 .map(|s| s.to_string())
152 .collect::<Vec<_>>()
153 .join(" or "),
154 actual: present_sigs.keys().map(|s| s.to_string()).collect(),
155 }
156 .into());
157 }
158 }
159
160 for (signer, signature) in present_sigs {
162 signature.verify_authenticator(
163 intent_message,
164 signer,
165 current_epoch,
166 verify_params,
167 zklogin_inputs_cache.clone(),
168 )?;
169 }
170 Ok(())
171}