1use core::u32;
2
3use crate::errors::InvokeError;
4use crate::errors::RuntimeError;
5use crate::internal_prelude::*;
6use crate::vm::wasm::*;
7use crate::vm::ScryptoVmVersion;
8use radix_engine_interface::api::actor_api::EventFlags;
9use radix_engine_interface::api::field_api::LockFlags;
10use radix_engine_interface::api::key_value_store_api::KeyValueStoreDataSchema;
11use radix_engine_interface::api::{ActorRefHandle, AttachedModuleId, FieldValue, SystemApi};
12use radix_engine_interface::types::ClientCostingEntry;
13use radix_engine_interface::types::Level;
14use radix_engine_profiling_derive::trace_resources;
15use sbor::rust::vec::Vec;
16
17pub struct ScryptoRuntime<'y, Y: SystemApi<RuntimeError>> {
19 api: &'y mut Y,
20 buffers: IndexMap<BufferId, Vec<u8>>,
21 next_buffer_id: BufferId,
22 package_address: PackageAddress,
23 export_name: String,
24 wasm_execution_units_buffer: u32,
25 scrypto_vm_version: ScryptoVmVersion,
26 wasm_execution_units_base: u32,
27}
28
29impl<'y, Y: SystemApi<RuntimeError>> ScryptoRuntime<'y, Y> {
30 pub fn new(
31 api: &'y mut Y,
32 package_address: PackageAddress,
33 export_name: String,
34 scrypto_vm_version: ScryptoVmVersion,
35 ) -> Self {
36 let wasm_execution_units_base = if scrypto_vm_version < ScryptoVmVersion::cuttlefish() {
37 0
38 } else {
39 28000
44 };
45
46 ScryptoRuntime {
47 api,
48 buffers: index_map_new(),
49 next_buffer_id: 0,
50 package_address,
51 export_name,
52 wasm_execution_units_buffer: 0,
53 scrypto_vm_version,
54 wasm_execution_units_base,
55 }
56 }
57 pub fn parse_blueprint_id(
58 package_address: Vec<u8>,
59 blueprint_name: Vec<u8>,
60 ) -> Result<(PackageAddress, String), InvokeError<WasmRuntimeError>> {
61 let package_address = PackageAddress::try_from(package_address.as_slice())
62 .map_err(|_| WasmRuntimeError::InvalidPackageAddress)?;
63 let blueprint_name =
64 String::from_utf8(blueprint_name).map_err(|_| WasmRuntimeError::InvalidString)?;
65 Ok((package_address, blueprint_name))
66 }
67
68 #[cold]
69 fn consume_wasm_execution_exceeding_buffer(
70 &mut self,
71 n: u32,
72 ) -> Result<(), InvokeError<WasmRuntimeError>> {
73 assert!(n > self.wasm_execution_units_buffer);
74 let n_remaining_after_buffer_used = n - self.wasm_execution_units_buffer;
75 let amount_to_request =
76 n_remaining_after_buffer_used.saturating_add(WASM_EXECUTION_COST_UNITS_BUFFER);
77
78 self.api
79 .consume_cost_units(ClientCostingEntry::RunWasmCode {
80 package_address: &self.package_address,
81 export_name: &self.export_name,
82 wasm_execution_units: amount_to_request,
83 })
84 .map_err(InvokeError::downstream)?;
85 self.wasm_execution_units_buffer = amount_to_request - n_remaining_after_buffer_used;
86 Ok(())
87 }
88}
89
90impl<'y, Y: SystemApi<RuntimeError>> WasmRuntime for ScryptoRuntime<'y, Y> {
91 fn allocate_buffer(
92 &mut self,
93 buffer: Vec<u8>,
94 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
95 assert!(buffer.len() <= 0xffffffff);
96
97 let max_number_of_buffers = match self.scrypto_vm_version {
98 ScryptoVmVersion::V1_0 | ScryptoVmVersion::V1_1 => 32,
99 ScryptoVmVersion::V1_2 => 4,
103 };
104 if self.buffers.len() >= max_number_of_buffers {
105 return Err(InvokeError::SelfError(WasmRuntimeError::TooManyBuffers));
106 }
107
108 let id = self.next_buffer_id;
109 let len = buffer.len();
110
111 self.buffers.insert(id, buffer);
112 self.next_buffer_id += 1;
113
114 Ok(Buffer::new(id, len as u32))
115 }
116
117 fn buffer_consume(
118 &mut self,
119 buffer_id: BufferId,
120 ) -> Result<Vec<u8>, InvokeError<WasmRuntimeError>> {
121 self.buffers
122 .swap_remove(&buffer_id)
123 .ok_or(InvokeError::SelfError(WasmRuntimeError::BufferNotFound(
124 buffer_id,
125 )))
126 }
127
128 fn object_call(
129 &mut self,
130 receiver: Vec<u8>,
131 ident: Vec<u8>,
132 args: Vec<u8>,
133 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
134 let receiver = NodeId(
135 TryInto::<[u8; NodeId::LENGTH]>::try_into(receiver.as_ref())
136 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
137 );
138 let ident = String::from_utf8(ident).map_err(|_| WasmRuntimeError::InvalidString)?;
139 let return_data = self.api.call_method(&receiver, ident.as_str(), args)?;
140
141 self.allocate_buffer(return_data)
142 }
143
144 fn object_call_module(
145 &mut self,
146 receiver: Vec<u8>,
147 module_id: u32,
148 ident: Vec<u8>,
149 args: Vec<u8>,
150 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
151 let receiver = NodeId(
152 TryInto::<[u8; NodeId::LENGTH]>::try_into(receiver.as_ref())
153 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
154 );
155 let ident = String::from_utf8(ident).map_err(|_| WasmRuntimeError::InvalidString)?;
156 let module_id = u8::try_from(module_id)
157 .ok()
158 .and_then(|x| AttachedModuleId::from_repr(x))
159 .ok_or(WasmRuntimeError::InvalidAttachedModuleId(module_id))?;
160
161 let return_data =
162 self.api
163 .call_module_method(&receiver, module_id, ident.as_str(), args)?;
164
165 self.allocate_buffer(return_data)
166 }
167
168 fn object_call_direct(
169 &mut self,
170 receiver: Vec<u8>,
171 ident: Vec<u8>,
172 args: Vec<u8>,
173 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
174 let receiver = NodeId(
175 TryInto::<[u8; NodeId::LENGTH]>::try_into(receiver.as_ref())
176 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
177 );
178 let ident = String::from_utf8(ident).map_err(|_| WasmRuntimeError::InvalidString)?;
179 let return_data = self
180 .api
181 .call_direct_access_method(&receiver, ident.as_str(), args)?;
182
183 self.allocate_buffer(return_data)
184 }
185
186 fn blueprint_call(
187 &mut self,
188 package_address: Vec<u8>,
189 blueprint_name: Vec<u8>,
190 function_ident: Vec<u8>,
191 args: Vec<u8>,
192 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
193 let (package_address, blueprint_name) =
194 Self::parse_blueprint_id(package_address, blueprint_name)?;
195 let function_ident =
196 String::from_utf8(function_ident).map_err(|_| WasmRuntimeError::InvalidString)?;
197
198 let return_data = self.api.call_function(
199 package_address,
200 blueprint_name.as_str(),
201 &function_ident,
202 args,
203 )?;
204
205 self.allocate_buffer(return_data)
206 }
207
208 fn object_new(
209 &mut self,
210 blueprint_name: Vec<u8>,
211 object_states: Vec<u8>,
212 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
213 let blueprint_name =
214 String::from_utf8(blueprint_name).map_err(|_| WasmRuntimeError::InvalidString)?;
215 let object_states = scrypto_decode::<IndexMap<u8, FieldValue>>(&object_states)
216 .map_err(WasmRuntimeError::InvalidObjectStates)?;
217
218 let component_id = self
219 .api
220 .new_simple_object(blueprint_name.as_ref(), object_states)?;
221
222 self.allocate_buffer(component_id.to_vec())
223 }
224
225 fn address_allocate(
226 &mut self,
227 package_address: Vec<u8>,
228 blueprint_name: Vec<u8>,
229 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
230 let (package_address, blueprint_name) =
231 Self::parse_blueprint_id(package_address, blueprint_name)?;
232
233 let address_reservation_and_address = self.api.allocate_global_address(BlueprintId {
234 package_address,
235 blueprint_name,
236 })?;
237 let encoded = scrypto_encode(&address_reservation_and_address)
238 .expect("Failed to encode object address");
239
240 self.allocate_buffer(encoded)
241 }
242
243 fn address_get_reservation_address(
244 &mut self,
245 node_id: Vec<u8>,
246 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
247 let node_id = NodeId(
248 TryInto::<[u8; NodeId::LENGTH]>::try_into(node_id.as_ref())
249 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
250 );
251
252 let address = self.api.get_reservation_address(&node_id)?;
253 let address_encoded = scrypto_encode(&address).expect("Failed to encode address");
254
255 self.allocate_buffer(address_encoded)
256 }
257
258 fn globalize_object(
259 &mut self,
260 node_id: Vec<u8>,
261 modules: Vec<u8>,
262 address_reservation: Vec<u8>,
263 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
264 let node_id = NodeId(
265 TryInto::<[u8; NodeId::LENGTH]>::try_into(node_id.as_ref())
266 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
267 );
268 let modules = scrypto_decode::<IndexMap<AttachedModuleId, NodeId>>(&modules)
269 .map_err(WasmRuntimeError::InvalidModules)?;
270 let address_reservation =
271 scrypto_decode::<Option<GlobalAddressReservation>>(&address_reservation)
272 .map_err(|_| WasmRuntimeError::InvalidGlobalAddressReservation)?;
273
274 let address = self.api.globalize(node_id, modules, address_reservation)?;
275
276 self.allocate_buffer(address.to_vec())
277 }
278
279 fn key_value_store_new(
280 &mut self,
281 schema: Vec<u8>,
282 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
283 let schema = scrypto_decode::<KeyValueStoreDataSchema>(&schema)
284 .map_err(WasmRuntimeError::InvalidKeyValueStoreSchema)?;
285
286 let key_value_store_id = self.api.key_value_store_new(schema)?;
287
288 self.allocate_buffer(key_value_store_id.to_vec())
289 }
290
291 fn key_value_store_open_entry(
292 &mut self,
293 node_id: Vec<u8>,
294 key: Vec<u8>,
295 flags: u32,
296 ) -> Result<SubstateHandle, InvokeError<WasmRuntimeError>> {
297 let node_id = NodeId(
298 TryInto::<[u8; NodeId::LENGTH]>::try_into(node_id.as_ref())
299 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
300 );
301
302 let flags = LockFlags::from_bits(flags).ok_or(WasmRuntimeError::InvalidLockFlags)?;
303 let handle = self.api.key_value_store_open_entry(&node_id, &key, flags)?;
304
305 Ok(handle)
306 }
307
308 fn key_value_entry_get(
309 &mut self,
310 handle: u32,
311 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
312 let value = self.api.key_value_entry_get(handle)?;
313 self.allocate_buffer(value)
314 }
315
316 fn key_value_entry_set(
317 &mut self,
318 handle: u32,
319 data: Vec<u8>,
320 ) -> Result<(), InvokeError<WasmRuntimeError>> {
321 self.api.key_value_entry_set(handle, data)?;
322 Ok(())
323 }
324
325 fn key_value_entry_remove(
326 &mut self,
327 handle: u32,
328 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
329 let value = self.api.key_value_entry_remove(handle)?;
330 self.allocate_buffer(value)
331 }
332
333 fn key_value_entry_close(&mut self, handle: u32) -> Result<(), InvokeError<WasmRuntimeError>> {
334 self.api.key_value_entry_close(handle)?;
335 Ok(())
336 }
337
338 fn key_value_store_remove_entry(
339 &mut self,
340 node_id: Vec<u8>,
341 key: Vec<u8>,
342 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
343 let node_id = NodeId(
344 TryInto::<[u8; NodeId::LENGTH]>::try_into(node_id.as_ref())
345 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
346 );
347 let rtn = self.api.key_value_store_remove_entry(&node_id, &key)?;
348 self.allocate_buffer(rtn)
349 }
350
351 fn actor_open_field(
352 &mut self,
353 object_handle: u32,
354 field: u8,
355 flags: u32,
356 ) -> Result<SubstateHandle, InvokeError<WasmRuntimeError>> {
357 let flags = LockFlags::from_bits(flags).ok_or(WasmRuntimeError::InvalidLockFlags)?;
358 let handle = self.api.actor_open_field(object_handle, field, flags)?;
359
360 Ok(handle)
361 }
362
363 fn field_entry_read(
364 &mut self,
365 handle: SubstateHandle,
366 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
367 let substate = self.api.field_read(handle)?;
368
369 self.allocate_buffer(substate)
370 }
371
372 fn field_entry_write(
373 &mut self,
374 handle: SubstateHandle,
375 data: Vec<u8>,
376 ) -> Result<(), InvokeError<WasmRuntimeError>> {
377 self.api.field_write(handle, data)?;
378
379 Ok(())
380 }
381
382 fn field_entry_close(
383 &mut self,
384 handle: SubstateHandle,
385 ) -> Result<(), InvokeError<WasmRuntimeError>> {
386 self.api.field_close(handle)?;
387
388 Ok(())
389 }
390
391 fn actor_get_node_id(
392 &mut self,
393 actor_ref_handle: ActorRefHandle,
394 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
395 let node_id = self.api.actor_get_node_id(actor_ref_handle)?;
396
397 self.allocate_buffer(node_id.0.to_vec())
398 }
399
400 fn actor_get_package_address(&mut self) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
401 let blueprint_id = self.api.actor_get_blueprint_id()?;
402
403 self.allocate_buffer(blueprint_id.package_address.to_vec())
404 }
405
406 fn actor_get_blueprint_name(&mut self) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
407 let blueprint_id = self.api.actor_get_blueprint_id()?;
408
409 self.allocate_buffer(blueprint_id.blueprint_name.into_bytes())
410 }
411
412 #[inline]
413 fn consume_wasm_execution_units(
414 &mut self,
415 n: u32,
416 ) -> Result<(), InvokeError<WasmRuntimeError>> {
417 let n = n.saturating_add(self.wasm_execution_units_base);
418
419 if n <= self.wasm_execution_units_buffer {
420 self.wasm_execution_units_buffer -= n;
421 Ok(())
422 } else {
423 self.consume_wasm_execution_exceeding_buffer(n)
424 }
425 }
426
427 fn instance_of(
428 &mut self,
429 object_id: Vec<u8>,
430 package_address: Vec<u8>,
431 blueprint_name: Vec<u8>,
432 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
433 let object_id = NodeId(
434 TryInto::<[u8; NodeId::LENGTH]>::try_into(object_id.as_ref())
435 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
436 );
437 let (package_address, blueprint_name) =
438 Self::parse_blueprint_id(package_address, blueprint_name)?;
439 let blueprint_id = self.api.get_blueprint_id(&object_id)?;
440
441 if blueprint_id.package_address.eq(&package_address)
442 && blueprint_id.blueprint_name.eq(&blueprint_name)
443 {
444 Ok(1)
445 } else {
446 Ok(0)
447 }
448 }
449
450 fn blueprint_id(
451 &mut self,
452 object_id: Vec<u8>,
453 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
454 let object_id = NodeId(
455 TryInto::<[u8; NodeId::LENGTH]>::try_into(object_id.as_ref())
456 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
457 );
458 let blueprint_id = self.api.get_blueprint_id(&object_id)?;
459
460 let mut buf = Vec::new();
461 buf.extend(blueprint_id.package_address.as_bytes());
462 buf.extend(blueprint_id.blueprint_name.as_bytes());
463
464 self.allocate_buffer(buf)
465 }
466
467 fn get_outer_object(
468 &mut self,
469 node_id: Vec<u8>,
470 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
471 let node_id = NodeId(
472 TryInto::<[u8; NodeId::LENGTH]>::try_into(node_id.as_ref())
473 .map_err(|_| WasmRuntimeError::InvalidNodeId)?,
474 );
475 let address = self.api.get_outer_object(&node_id)?;
476
477 self.allocate_buffer(address.to_vec())
478 }
479
480 fn actor_emit_event(
481 &mut self,
482 event_name: Vec<u8>,
483 event_payload: Vec<u8>,
484 event_flags: EventFlags,
485 ) -> Result<(), InvokeError<WasmRuntimeError>> {
486 self.api.actor_emit_event(
487 String::from_utf8(event_name).map_err(|_| WasmRuntimeError::InvalidString)?,
488 event_payload,
489 event_flags,
490 )?;
491 Ok(())
492 }
493
494 fn sys_log(
495 &mut self,
496 level: Vec<u8>,
497 message: Vec<u8>,
498 ) -> Result<(), InvokeError<WasmRuntimeError>> {
499 self.api.emit_log(
500 scrypto_decode::<Level>(&level).map_err(WasmRuntimeError::InvalidLogLevel)?,
501 String::from_utf8(message).map_err(|_| WasmRuntimeError::InvalidString)?,
502 )?;
503 Ok(())
504 }
505
506 fn sys_bech32_encode_address(
507 &mut self,
508 address: Vec<u8>,
509 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
510 let address =
511 scrypto_decode::<GlobalAddress>(&address).map_err(WasmRuntimeError::InvalidAddress)?;
512 let encoded = self.api.bech32_encode_address(address)?;
513 self.allocate_buffer(encoded.into_bytes())
514 }
515
516 fn sys_panic(&mut self, message: Vec<u8>) -> Result<(), InvokeError<WasmRuntimeError>> {
517 self.api
518 .panic(String::from_utf8(message).map_err(|_| WasmRuntimeError::InvalidString)?)?;
519 Ok(())
520 }
521
522 fn sys_get_transaction_hash(&mut self) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
523 let hash = self.api.get_transaction_hash()?;
524
525 self.allocate_buffer(hash.to_vec())
526 }
527
528 fn sys_generate_ruid(&mut self) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
529 let ruid = self.api.generate_ruid()?;
530
531 self.allocate_buffer(ruid.to_vec())
532 }
533
534 fn costing_get_execution_cost_unit_limit(
535 &mut self,
536 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
537 let execution_cost_unit_limit = self.api.execution_cost_unit_limit()?;
538
539 Ok(execution_cost_unit_limit)
540 }
541
542 fn costing_get_execution_cost_unit_price(
543 &mut self,
544 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
545 let execution_cost_unit_price = self.api.execution_cost_unit_price()?;
546
547 self.allocate_buffer(
548 scrypto_encode(&execution_cost_unit_price)
549 .expect("Failed to encode execution_cost_unit_price"),
550 )
551 }
552
553 fn costing_get_finalization_cost_unit_limit(
554 &mut self,
555 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
556 let finalization_cost_unit_limit = self.api.finalization_cost_unit_limit()?;
557
558 Ok(finalization_cost_unit_limit)
559 }
560
561 fn costing_get_finalization_cost_unit_price(
562 &mut self,
563 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
564 let finalization_cost_unit_price = self.api.finalization_cost_unit_price()?;
565
566 self.allocate_buffer(
567 scrypto_encode(&finalization_cost_unit_price)
568 .expect("Failed to encode finalization_cost_unit_price"),
569 )
570 }
571
572 fn costing_get_usd_price(&mut self) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
573 let usd_price = self.api.usd_price()?;
574 self.allocate_buffer(
575 scrypto_encode(&usd_price).expect("Failed to encode finalization_cost_unit_price"),
576 )
577 }
578
579 fn costing_get_tip_percentage(&mut self) -> Result<u32, InvokeError<WasmRuntimeError>> {
580 Ok(self.api.tip_percentage_truncated()?)
581 }
582
583 fn costing_get_fee_balance(&mut self) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
584 let fee_balance = self.api.fee_balance()?;
585
586 self.allocate_buffer(scrypto_encode(&fee_balance).expect("Failed to encode fee_balance"))
587 }
588
589 #[trace_resources(log=message.len())]
592 fn crypto_utils_bls12381_v1_verify(
593 &mut self,
594 message: Vec<u8>,
595 public_key: Vec<u8>,
596 signature: Vec<u8>,
597 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
598 let public_key: Bls12381G1PublicKey =
599 scrypto_decode(&public_key).map_err(WasmRuntimeError::InvalidBlsPublicKey)?;
600 let signature: Bls12381G2Signature =
601 scrypto_decode(&signature).map_err(WasmRuntimeError::InvalidBlsSignature)?;
602
603 self.api
604 .consume_cost_units(ClientCostingEntry::Bls12381V1Verify {
605 size: message.len(),
606 })?;
607
608 Ok(verify_bls12381_v1(&message, &public_key, &signature) as u32)
609 }
610
611 #[trace_resources(log=pub_keys_and_msgs.len())]
614 fn crypto_utils_bls12381_v1_aggregate_verify(
615 &mut self,
616 pub_keys_and_msgs: Vec<u8>,
617 signature: Vec<u8>,
618 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
619 let signature: Bls12381G2Signature =
620 scrypto_decode(&signature).map_err(WasmRuntimeError::InvalidBlsSignature)?;
621 let pub_keys_and_msgs: Vec<(Bls12381G1PublicKey, Vec<u8>)> =
622 scrypto_decode(&pub_keys_and_msgs)
623 .map_err(WasmRuntimeError::InvalidBlsPublicKeyOrMessage)?;
624
625 if pub_keys_and_msgs.is_empty() {
626 return Err(InvokeError::SelfError(WasmRuntimeError::InputDataEmpty));
627 }
628
629 let sizes: Vec<usize> = pub_keys_and_msgs.iter().map(|(_, msg)| msg.len()).collect();
630
631 self.api
632 .consume_cost_units(ClientCostingEntry::Bls12381V1AggregateVerify {
633 sizes: sizes.as_slice(),
634 })?;
635
636 Ok(aggregate_verify_bls12381_v1(&pub_keys_and_msgs, &signature) as u32)
637 }
638
639 #[trace_resources(log=message.len(), log=public_keys.len())]
642 fn crypto_utils_bls12381_v1_fast_aggregate_verify(
643 &mut self,
644 message: Vec<u8>,
645 public_keys: Vec<u8>,
646 signature: Vec<u8>,
647 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
648 let public_keys: Vec<Bls12381G1PublicKey> =
649 scrypto_decode(&public_keys).map_err(WasmRuntimeError::InvalidBlsPublicKey)?;
650 let signature: Bls12381G2Signature =
651 scrypto_decode(&signature).map_err(WasmRuntimeError::InvalidBlsSignature)?;
652
653 if public_keys.is_empty() {
654 return Err(InvokeError::SelfError(WasmRuntimeError::InputDataEmpty));
655 }
656
657 self.api
658 .consume_cost_units(ClientCostingEntry::Bls12381V1FastAggregateVerify {
659 size: message.len(),
660 keys_cnt: public_keys.len(),
661 })?;
662
663 if self.scrypto_vm_version == ScryptoVmVersion::crypto_utils_v1() {
664 Ok(
665 fast_aggregate_verify_bls12381_v1_anemone(&message, &public_keys, &signature)
666 as u32,
667 )
668 } else {
669 Ok(fast_aggregate_verify_bls12381_v1(&message, &public_keys, &signature) as u32)
670 }
671 }
672
673 #[trace_resources(log=signatures.len())]
676 fn crypto_utils_bls12381_g2_signature_aggregate(
677 &mut self,
678 signatures: Vec<u8>,
679 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
680 let signatures: Vec<Bls12381G2Signature> =
681 scrypto_decode(&signatures).map_err(WasmRuntimeError::InvalidBlsSignature)?;
682
683 if signatures.is_empty() {
684 return Err(InvokeError::SelfError(WasmRuntimeError::InputDataEmpty));
685 }
686
687 self.api
688 .consume_cost_units(ClientCostingEntry::Bls12381G2SignatureAggregate {
689 signatures_cnt: signatures.len(),
690 })?;
691
692 let agg_sig = if self.scrypto_vm_version == ScryptoVmVersion::crypto_utils_v1() {
693 Bls12381G2Signature::aggregate_anemone(&signatures)
694 } else {
695 Bls12381G2Signature::aggregate(&signatures, true)
696 }
697 .map_err(|err| RuntimeError::SystemError(SystemError::BlsError(err.to_string())))?;
698
699 self.allocate_buffer(
700 scrypto_encode(&agg_sig).expect("Failed to encode Bls12381G2Signature"),
701 )
702 }
703
704 #[trace_resources(log=data.len())]
707 fn crypto_utils_keccak256_hash(
708 &mut self,
709 data: Vec<u8>,
710 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
711 self.api
712 .consume_cost_units(ClientCostingEntry::Keccak256Hash { size: data.len() })?;
713
714 let hash = keccak256_hash(data);
715
716 self.allocate_buffer(hash.to_vec())
717 }
718
719 #[trace_resources(log=data.len())]
722 fn crypto_utils_blake2b_256_hash(
723 &mut self,
724 data: Vec<u8>,
725 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
726 self.api
727 .consume_cost_units(ClientCostingEntry::Blake2b256Hash { size: data.len() })?;
728
729 let hash = blake2b_256_hash(data);
730
731 self.allocate_buffer(hash.to_vec())
732 }
733
734 #[trace_resources(log=message.len())]
737 fn crypto_utils_ed25519_verify(
738 &mut self,
739 message: Vec<u8>,
740 public_key: Vec<u8>,
741 signature: Vec<u8>,
742 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
743 let public_key = Ed25519PublicKey::try_from(public_key.as_ref())
744 .map_err(WasmRuntimeError::InvalidEd25519PublicKey)?;
745 let signature = Ed25519Signature::try_from(signature.as_ref())
746 .map_err(WasmRuntimeError::InvalidEd25519Signature)?;
747
748 self.api
749 .consume_cost_units(ClientCostingEntry::Ed25519Verify {
750 size: message.len(),
751 })?;
752
753 Ok(verify_ed25519(&message, &public_key, &signature) as u32)
754 }
755
756 #[trace_resources(log=message.len())]
759 fn crypto_utils_secp256k1_ecdsa_verify(
760 &mut self,
761 message: Vec<u8>,
762 public_key: Vec<u8>,
763 signature: Vec<u8>,
764 ) -> Result<u32, InvokeError<WasmRuntimeError>> {
765 let public_key = Secp256k1PublicKey::try_from(public_key.as_ref())
766 .map_err(WasmRuntimeError::InvalidSecp256k1PublicKey)?;
767 let signature = Secp256k1Signature::try_from(signature.as_ref())
768 .map_err(WasmRuntimeError::InvalidSecp256k1Signature)?;
769 let hash = Hash::try_from(message.as_slice()).map_err(WasmRuntimeError::InvalidHash)?;
770
771 self.api
772 .consume_cost_units(ClientCostingEntry::Secp256k1EcdsaVerify)?;
773
774 Ok(verify_secp256k1(&hash, &public_key, &signature) as u32)
775 }
776
777 #[trace_resources]
780 fn crypto_utils_secp256k1_ecdsa_verify_and_key_recover(
781 &mut self,
782 message: Vec<u8>,
783 signature: Vec<u8>,
784 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
785 let hash = Hash::try_from(message.as_slice()).map_err(WasmRuntimeError::InvalidHash)?;
786 let signature = Secp256k1Signature::try_from(signature.as_ref())
787 .map_err(WasmRuntimeError::InvalidSecp256k1Signature)?;
788
789 self.api
790 .consume_cost_units(ClientCostingEntry::Secp256k1EcdsaKeyRecover)?;
791
792 let key = verify_and_recover_secp256k1(&hash, &signature)
793 .ok_or(WasmRuntimeError::Secp256k1KeyRecoveryError)?;
794
795 self.allocate_buffer(key.to_vec())
796 }
797
798 #[trace_resources]
801 fn crypto_utils_secp256k1_ecdsa_verify_and_key_recover_uncompressed(
802 &mut self,
803 message: Vec<u8>,
804 signature: Vec<u8>,
805 ) -> Result<Buffer, InvokeError<WasmRuntimeError>> {
806 let hash = Hash::try_from(message.as_slice()).map_err(WasmRuntimeError::InvalidHash)?;
807 let signature = Secp256k1Signature::try_from(signature.as_ref())
808 .map_err(WasmRuntimeError::InvalidSecp256k1Signature)?;
809
810 self.api
811 .consume_cost_units(ClientCostingEntry::Secp256k1EcdsaKeyRecover)?;
812
813 let key = verify_and_recover_secp256k1_uncompressed(&hash, &signature)
814 .ok_or(WasmRuntimeError::Secp256k1KeyRecoveryError)?;
815
816 self.allocate_buffer(key.0.to_vec())
817 }
818}