iota_types/
move_authenticator.rs1use std::{
5 collections::HashSet,
6 hash::{Hash, Hasher},
7 sync::Arc,
8};
9
10use fastcrypto::{error::FastCryptoError, traits::ToFromBytes};
11use iota_protocol_config::ProtocolConfig;
12use iota_sdk_types::crypto::IntentMessage;
13use once_cell::sync::OnceCell;
14use schemars::JsonSchema;
15use serde::{Deserialize, Serialize};
16
17use crate::{
18 base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber},
19 committee::EpochId,
20 crypto::{SignatureScheme, default_hash},
21 digests::{MoveAuthenticatorDigest, ObjectDigest, ZKLoginInputsDigest},
22 error::{IotaError, IotaResult, UserInputError, UserInputResult},
23 signature::{AuthenticatorTrait, VerifyParams},
24 signature_verification::VerifiedDigestCache,
25 transaction::{CallArg, InputObjectKind, ObjectArg, SharedInputObject},
26 type_input::TypeInput,
27};
28
29#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)]
34pub struct MoveAuthenticator {
35 call_args: Vec<CallArg>,
37 #[schemars(with = "Vec<String>")]
39 type_arguments: Vec<TypeInput>,
40 object_to_authenticate: CallArg,
43 #[serde(skip)]
46 bytes: OnceCell<Vec<u8>>,
47}
48
49impl Hash for MoveAuthenticator {
52 fn hash<H: Hasher>(&self, state: &mut H) {
53 self.as_ref().hash(state);
54 }
55}
56
57impl MoveAuthenticator {
58 pub fn new(
59 call_args: Vec<CallArg>,
60 type_arguments: Vec<TypeInput>,
61 object_to_authenticate: CallArg,
62 ) -> Self {
63 Self {
64 call_args,
65 type_arguments,
66 object_to_authenticate,
67 bytes: OnceCell::new(),
68 }
69 }
70
71 pub fn address(&self) -> IotaResult<IotaAddress> {
72 let (id, _, _) = self.object_to_authenticate_components()?;
73 Ok(IotaAddress::from(id))
74 }
75
76 pub fn digest(&self) -> MoveAuthenticatorDigest {
77 MoveAuthenticatorDigest::new(default_hash(self))
78 }
79
80 pub fn call_args(&self) -> &Vec<CallArg> {
81 &self.call_args
82 }
83
84 pub fn type_arguments(&self) -> &Vec<TypeInput> {
85 &self.type_arguments
86 }
87
88 pub fn object_to_authenticate(&self) -> &CallArg {
89 &self.object_to_authenticate
90 }
91
92 pub fn object_to_authenticate_components(
93 &self,
94 ) -> UserInputResult<(ObjectID, Option<SequenceNumber>, Option<ObjectDigest>)> {
95 Ok(match self.object_to_authenticate() {
96 CallArg::Pure(_) => {
97 return Err(UserInputError::Unsupported(
98 "MoveAuthenticator cannot authenticate pure inputs".to_string(),
99 ));
100 }
101 CallArg::Object(object_arg) => match object_arg {
102 ObjectArg::ImmOrOwnedObject((id, sequence_number, digest)) => {
103 (*id, Some(*sequence_number), Some(*digest))
104 }
105 ObjectArg::SharedObject { id, mutable, .. } => {
106 if *mutable {
107 return Err(UserInputError::Unsupported(
108 "MoveAuthenticator cannot authenticate mutable shared objects"
109 .to_string(),
110 ));
111 }
112
113 (*id, None, None)
114 }
115 ObjectArg::Receiving(_) => {
116 return Err(UserInputError::Unsupported(
117 "MoveAuthenticator cannot authenticate receiving objects".to_string(),
118 ));
119 }
120 },
121 })
122 }
123
124 pub fn input_objects(&self) -> Vec<InputObjectKind> {
127 self.call_args
128 .iter()
129 .flat_map(|arg| arg.input_objects())
130 .chain(self.object_to_authenticate().input_objects())
131 .collect::<Vec<_>>()
132 }
133
134 pub fn receiving_objects(&self) -> Vec<ObjectRef> {
135 self.call_args
136 .iter()
137 .flat_map(|arg| arg.receiving_objects())
138 .collect()
139 }
140
141 pub fn shared_objects(&self) -> Vec<SharedInputObject> {
144 self.call_args
145 .iter()
146 .flat_map(|arg| arg.shared_objects())
147 .chain(self.object_to_authenticate().shared_objects())
148 .collect()
149 }
150
151 pub fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
153 self.object_to_authenticate_components()?;
155
156 let max_args = (config.max_function_parameters() - 3) as usize;
168 fp_ensure!(
169 self.call_args().len() < max_args,
170 UserInputError::SizeLimitExceeded {
171 limit: "maximum arguments in MoveAuthenticator".to_string(),
172 value: max_args.to_string()
173 }
174 );
175
176 fp_ensure!(
177 self.receiving_objects().is_empty(),
178 UserInputError::Unsupported(
179 "MoveAuthenticator cannot have receiving objects as input".to_string(),
180 )
181 );
182
183 let mut used = HashSet::new();
184 fp_ensure!(
185 self.input_objects()
186 .iter()
187 .all(|o| used.insert(o.object_id())),
188 UserInputError::DuplicateObjectRefInput
189 );
190
191 self.call_args()
192 .iter()
193 .try_for_each(|obj| obj.validity_check(config))?;
194
195 let mut type_arguments_count = 0;
200 self.type_arguments().iter().try_for_each(|type_arg| {
201 crate::transaction::type_input_validity_check(
202 type_arg,
203 config,
204 &mut type_arguments_count,
205 )
206 })?;
207
208 Ok(())
209 }
210}
211
212impl AuthenticatorTrait for MoveAuthenticator {
213 fn verify_user_authenticator_epoch(
214 &self,
215 _epoch: EpochId,
216 _max_epoch_upper_bound_delta: Option<u64>,
217 ) -> IotaResult {
218 Ok(())
219 }
220 fn verify_claims<T>(
223 &self,
224 _value: &IntentMessage<T>,
225 author: IotaAddress,
226 _aux_verify_data: &VerifyParams,
227 _zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
228 ) -> IotaResult
229 where
230 T: Serialize,
231 {
232 if author != self.address()? {
233 return Err(IotaError::InvalidSignature {
234 error: "Invalid author".to_string(),
235 });
236 };
237
238 Ok(())
239 }
240}
241
242impl PartialEq for MoveAuthenticator {
245 fn eq(&self, other: &Self) -> bool {
246 self.as_ref() == other.as_ref()
247 }
248}
249
250impl ToFromBytes for MoveAuthenticator {
251 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
252 if bytes.first().ok_or(FastCryptoError::InvalidInput)?
254 != &SignatureScheme::MoveAuthenticator.flag()
255 {
256 return Err(FastCryptoError::InvalidInput);
257 }
258 let move_auth: MoveAuthenticator =
259 bcs::from_bytes(&bytes[1..]).map_err(|_| FastCryptoError::InvalidSignature)?;
260 Ok(move_auth)
261 }
262}
263
264impl Eq for MoveAuthenticator {}
267
268impl AsRef<[u8]> for MoveAuthenticator {
269 fn as_ref(&self) -> &[u8] {
270 self.bytes
271 .get_or_try_init::<_, eyre::Report>(|| {
272 let as_bytes = bcs::to_bytes(self).expect("BCS serialization should not fail");
273 let mut bytes = Vec::with_capacity(1 + as_bytes.len());
274 bytes.push(SignatureScheme::MoveAuthenticator.flag());
275 bytes.extend_from_slice(as_bytes.as_slice());
276 Ok(bytes)
277 })
278 .expect("OnceCell invariant violated")
279 }
280}