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