Skip to main content

amaru_uplc/machine/
runtime.rs

1use core::str;
2use std::array::TryFromSliceError;
3
4use crate::{
5    arena::Arena,
6    binder::Eval,
7    bls::{Compressable, SCALAR_PERIOD},
8    builtin::DefaultFunction,
9    constant::{self, Constant, Integer},
10    data::PlutusData,
11    ledger_value::{self, LedgerValue, ValueError},
12    machine::cost_model::builtin_costs::BuiltinCostModel,
13    typ::Type,
14};
15use bumpalo::collections::{CollectIn, String as BumpString, Vec as BumpVec};
16use num::{Integer as NumInteger, Signed, Zero};
17
18use super::{cost_model, value::Value, Machine, MachineError, RuntimeError};
19
20pub const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192;
21
22/// Check that an integer fits in a signed 4096-bit range: [-(2^4095), 2^4095 - 1].
23/// Used by multiScalarMul to limit scalar sizes.
24fn check_multi_scalar_range(int: &Integer) -> Result<(), RuntimeError<'_>> {
25    let bits = int.bits();
26
27    if bits <= 4095 {
28        return Ok(());
29    }
30
31    if bits > 4096 {
32        return Err(RuntimeError::MultiScalarMulScalarOutOfBounds);
33    }
34
35    // bits == 4096: only valid if negative and exactly -(2^4095)
36    if !int.is_negative() {
37        return Err(RuntimeError::MultiScalarMulScalarOutOfBounds);
38    }
39
40    let magnitude = int.magnitude();
41
42    use num::One;
43
44    let two_pow_4095 = num::BigUint::one() << 4095;
45
46    if *magnitude == two_pow_4095 {
47        Ok(())
48    } else {
49        Err(RuntimeError::MultiScalarMulScalarOutOfBounds)
50    }
51}
52
53/// Reduce scalar mod SCALAR_PERIOD, convert to LE bytes, and append to the output buffer.
54/// Caller must validate the scalar range first via `check_multi_scalar_range`.
55fn prepare_msm_scalar(
56    si: &Integer,
57    scalar_buf: &mut blst::blst_scalar,
58    scalar_bytes: &mut Vec<u8>,
59) {
60    let si = si.mod_floor(&SCALAR_PERIOD);
61    let (_, be_bytes) = si.to_bytes_be();
62
63    // Zero-padded big-endian scalar on the stack (always 32 bytes).
64    const SIZE: usize = size_of::<blst::blst_scalar>();
65    let mut padded = [0u8; SIZE];
66    padded[SIZE - be_bytes.len()..].copy_from_slice(&be_bytes);
67
68    unsafe {
69        blst::blst_scalar_from_bendian(scalar_buf as *mut _, padded.as_ptr() as *const _);
70    }
71    scalar_bytes.extend_from_slice(&scalar_buf.b);
72}
73
74pub enum BuiltinSemantics {
75    V1,
76    V2,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum PlutusVersion {
81    V1,
82    V2,
83    V3,
84}
85
86impl From<&PlutusVersion> for BuiltinSemantics {
87    fn from(version: &PlutusVersion) -> Self {
88        match version {
89            PlutusVersion::V1 => BuiltinSemantics::V1,
90            PlutusVersion::V2 => BuiltinSemantics::V1,
91            PlutusVersion::V3 => BuiltinSemantics::V2,
92        }
93    }
94}
95
96#[derive(Debug)]
97pub struct Runtime<'a, V>
98where
99    V: Eval<'a>,
100{
101    pub args: BumpVec<'a, &'a Value<'a, V>>,
102    pub fun: &'a DefaultFunction,
103    pub forces: usize,
104}
105
106impl<'a, V> Runtime<'a, V>
107where
108    V: Eval<'a>,
109{
110    pub fn new(arena: &'a Arena, fun: &'a DefaultFunction) -> &'a Self {
111        arena.alloc(Self {
112            args: BumpVec::new_in(arena.as_bump()),
113            fun,
114            forces: 0,
115        })
116    }
117
118    pub fn force(&self, arena: &'a Arena) -> &'a Self {
119        let new_runtime = arena.alloc(Runtime {
120            args: self.args.clone(),
121            fun: self.fun,
122            forces: self.forces + 1,
123        });
124
125        new_runtime
126    }
127
128    pub fn push(&self, arena: &'a Arena, arg: &'a Value<'a, V>) -> &'a Self {
129        let new_runtime = arena.alloc(Runtime {
130            args: self.args.clone(),
131            fun: self.fun,
132            forces: self.forces,
133        });
134
135        new_runtime.args.push(arg);
136
137        new_runtime
138    }
139
140    pub fn needs_force(&self) -> bool {
141        self.forces < self.fun.force_count()
142    }
143
144    pub fn is_arrow(&self) -> bool {
145        self.args.len() < self.fun.arity()
146    }
147
148    pub fn is_ready(&self) -> bool {
149        self.args.len() == self.fun.arity()
150    }
151}
152
153impl<'a, B: BuiltinCostModel> Machine<'a, B> {
154    pub fn call<V>(
155        &mut self,
156        runtime: &'a Runtime<'a, V>,
157    ) -> Result<&'a Value<'a, V>, MachineError<'a, V>>
158    where
159        V: Eval<'a>,
160    {
161        match runtime.fun {
162            DefaultFunction::AddInteger => {
163                let arg1 = runtime.args[0].unwrap_integer()?;
164                let arg2 = runtime.args[1].unwrap_integer()?;
165
166                let budget = self
167                    .costs
168                    .builtin_costs
169                    .get_cost(
170                        DefaultFunction::AddInteger,
171                        &[
172                            cost_model::integer_ex_mem(arg1),
173                            cost_model::integer_ex_mem(arg2),
174                        ],
175                    )
176                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::AddInteger))?;
177
178                self.spend_budget(budget)?;
179
180                let result = arg1 + arg2;
181                let new = self.arena.alloc_integer(result);
182
183                let value = Value::integer(self.arena, new);
184
185                Ok(value)
186            }
187            DefaultFunction::SubtractInteger => {
188                let arg1 = runtime.args[0].unwrap_integer()?;
189                let arg2 = runtime.args[1].unwrap_integer()?;
190
191                let budget = self
192                    .costs
193                    .builtin_costs
194                    .get_cost(
195                        DefaultFunction::SubtractInteger,
196                        &[
197                            cost_model::integer_ex_mem(arg1),
198                            cost_model::integer_ex_mem(arg2),
199                        ],
200                    )
201                    .ok_or(MachineError::NoCostForBuiltin(
202                        DefaultFunction::SubtractInteger,
203                    ))?;
204
205                self.spend_budget(budget)?;
206
207                let result = arg1 - arg2;
208
209                let new = self.arena.alloc_integer(result);
210
211                let value = Value::integer(self.arena, new);
212
213                Ok(value)
214            }
215            DefaultFunction::EqualsInteger => {
216                let arg1 = runtime.args[0].unwrap_integer()?;
217                let arg2 = runtime.args[1].unwrap_integer()?;
218
219                let budget = self
220                    .costs
221                    .builtin_costs
222                    .get_cost(
223                        DefaultFunction::EqualsInteger,
224                        &[
225                            cost_model::integer_ex_mem(arg1),
226                            cost_model::integer_ex_mem(arg2),
227                        ],
228                    )
229                    .ok_or(MachineError::NoCostForBuiltin(
230                        DefaultFunction::EqualsInteger,
231                    ))?;
232
233                self.spend_budget(budget)?;
234
235                let result = arg1 == arg2;
236
237                let value = Value::bool(self.arena, result);
238
239                Ok(value)
240            }
241            DefaultFunction::LessThanEqualsInteger => {
242                let arg1 = runtime.args[0].unwrap_integer()?;
243                let arg2 = runtime.args[1].unwrap_integer()?;
244
245                let budget = self
246                    .costs
247                    .builtin_costs
248                    .get_cost(
249                        DefaultFunction::LessThanEqualsInteger,
250                        &[
251                            cost_model::integer_ex_mem(arg1),
252                            cost_model::integer_ex_mem(arg2),
253                        ],
254                    )
255                    .ok_or(MachineError::NoCostForBuiltin(
256                        DefaultFunction::LessThanEqualsInteger,
257                    ))?;
258
259                self.spend_budget(budget)?;
260
261                let result = arg1 <= arg2;
262
263                let value = Value::bool(self.arena, result);
264
265                Ok(value)
266            }
267            DefaultFunction::AppendByteString => {
268                let arg1 = runtime.args[0].unwrap_byte_string()?;
269                let arg2 = runtime.args[1].unwrap_byte_string()?;
270
271                let budget = self
272                    .costs
273                    .builtin_costs
274                    .get_cost(
275                        DefaultFunction::AppendByteString,
276                        &[
277                            cost_model::byte_string_ex_mem(arg1),
278                            cost_model::byte_string_ex_mem(arg2),
279                        ],
280                    )
281                    .ok_or(MachineError::NoCostForBuiltin(
282                        DefaultFunction::AppendByteString,
283                    ))?;
284
285                self.spend_budget(budget)?;
286
287                let mut result =
288                    BumpVec::with_capacity_in(arg1.len() + arg2.len(), self.arena.as_bump());
289
290                result.extend_from_slice(arg1);
291                result.extend_from_slice(arg2);
292
293                let result = self.arena.alloc(result);
294
295                let value = Value::byte_string(self.arena, result);
296
297                Ok(value)
298            }
299            DefaultFunction::EqualsByteString => {
300                let arg1 = runtime.args[0].unwrap_byte_string()?;
301                let arg2 = runtime.args[1].unwrap_byte_string()?;
302
303                let budget = self
304                    .costs
305                    .builtin_costs
306                    .get_cost(
307                        DefaultFunction::EqualsByteString,
308                        &[
309                            cost_model::byte_string_ex_mem(arg1),
310                            cost_model::byte_string_ex_mem(arg2),
311                        ],
312                    )
313                    .ok_or(MachineError::NoCostForBuiltin(
314                        DefaultFunction::EqualsByteString,
315                    ))?;
316
317                self.spend_budget(budget)?;
318
319                let result = arg1 == arg2;
320
321                let value = Value::bool(self.arena, result);
322
323                Ok(value)
324            }
325            DefaultFunction::IfThenElse => {
326                let arg1 = runtime.args[0].unwrap_bool()?;
327                let arg2 = runtime.args[1];
328                let arg3 = runtime.args[2];
329                let budget = self
330                    .costs
331                    .builtin_costs
332                    .get_cost(
333                        DefaultFunction::IfThenElse,
334                        &[
335                            cost_model::BOOL_EX_MEM,
336                            cost_model::value_ex_mem(arg2),
337                            cost_model::value_ex_mem(arg3),
338                        ],
339                    )
340                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::IfThenElse))?;
341                self.spend_budget(budget)?;
342
343                if arg1 {
344                    Ok(arg2)
345                } else {
346                    Ok(arg3)
347                }
348            }
349            DefaultFunction::MultiplyInteger => {
350                let arg1 = runtime.args[0].unwrap_integer()?;
351                let arg2 = runtime.args[1].unwrap_integer()?;
352
353                let budget = self
354                    .costs
355                    .builtin_costs
356                    .get_cost(
357                        DefaultFunction::MultiplyInteger,
358                        &[
359                            cost_model::integer_ex_mem(arg1),
360                            cost_model::integer_ex_mem(arg2),
361                        ],
362                    )
363                    .ok_or(MachineError::NoCostForBuiltin(
364                        DefaultFunction::MultiplyInteger,
365                    ))?;
366
367                self.spend_budget(budget)?;
368
369                let result = arg1 * arg2;
370
371                let new = self.arena.alloc_integer(result);
372
373                let value = Value::integer(self.arena, new);
374
375                Ok(value)
376            }
377            DefaultFunction::DivideInteger => {
378                let arg1 = runtime.args[0].unwrap_integer()?;
379                let arg2 = runtime.args[1].unwrap_integer()?;
380
381                let budget = self
382                    .costs
383                    .builtin_costs
384                    .get_cost(
385                        DefaultFunction::DivideInteger,
386                        &[
387                            cost_model::integer_ex_mem(arg1),
388                            cost_model::integer_ex_mem(arg2),
389                        ],
390                    )
391                    .ok_or(MachineError::NoCostForBuiltin(
392                        DefaultFunction::DivideInteger,
393                    ))?;
394
395                self.spend_budget(budget)?;
396
397                if !arg2.is_zero() {
398                    let (result, _) = arg1.div_mod_floor(arg2);
399
400                    let new = self.arena.alloc_integer(result);
401
402                    let value = Value::integer(self.arena, new);
403
404                    Ok(value)
405                } else {
406                    Err(MachineError::division_by_zero(arg1, arg2))
407                }
408            }
409            DefaultFunction::QuotientInteger => {
410                let arg1 = runtime.args[0].unwrap_integer()?;
411                let arg2 = runtime.args[1].unwrap_integer()?;
412
413                let budget = self
414                    .costs
415                    .builtin_costs
416                    .get_cost(
417                        DefaultFunction::QuotientInteger,
418                        &[
419                            cost_model::integer_ex_mem(arg1),
420                            cost_model::integer_ex_mem(arg2),
421                        ],
422                    )
423                    .ok_or(MachineError::NoCostForBuiltin(
424                        DefaultFunction::QuotientInteger,
425                    ))?;
426
427                self.spend_budget(budget)?;
428
429                if !arg2.is_zero() {
430                    let (quotient, _) = arg1.div_rem(arg2);
431                    let q = self.arena.alloc_integer(quotient);
432                    let value = Value::integer(self.arena, q);
433                    Ok(value)
434                } else {
435                    Err(MachineError::division_by_zero(arg1, arg2))
436                }
437            }
438            DefaultFunction::RemainderInteger => {
439                let arg1 = runtime.args[0].unwrap_integer()?;
440                let arg2 = runtime.args[1].unwrap_integer()?;
441
442                let budget = self
443                    .costs
444                    .builtin_costs
445                    .get_cost(
446                        DefaultFunction::RemainderInteger,
447                        &[
448                            cost_model::integer_ex_mem(arg1),
449                            cost_model::integer_ex_mem(arg2),
450                        ],
451                    )
452                    .ok_or(MachineError::NoCostForBuiltin(
453                        DefaultFunction::RemainderInteger,
454                    ))?;
455
456                self.spend_budget(budget)?;
457
458                if !arg2.is_zero() {
459                    let (_, remainder) = arg1.div_rem(arg2);
460                    let r = self.arena.alloc_integer(remainder);
461                    let value = Value::integer(self.arena, r);
462                    Ok(value)
463                } else {
464                    Err(MachineError::division_by_zero(arg1, arg2))
465                }
466            }
467            DefaultFunction::ModInteger => {
468                let arg1 = runtime.args[0].unwrap_integer()?;
469                let arg2 = runtime.args[1].unwrap_integer()?;
470
471                let budget = self
472                    .costs
473                    .builtin_costs
474                    .get_cost(
475                        DefaultFunction::ModInteger,
476                        &[
477                            cost_model::integer_ex_mem(arg1),
478                            cost_model::integer_ex_mem(arg2),
479                        ],
480                    )
481                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ModInteger))?;
482
483                self.spend_budget(budget)?;
484
485                if !arg2.is_zero() {
486                    let (_, result) = arg1.div_mod_floor(arg2);
487                    let result = self.arena.alloc_integer(result);
488                    let value = Value::integer(self.arena, result);
489
490                    Ok(value)
491                } else {
492                    Err(MachineError::division_by_zero(arg1, arg2))
493                }
494            }
495            DefaultFunction::LessThanInteger => {
496                let arg1 = runtime.args[0].unwrap_integer()?;
497                let arg2 = runtime.args[1].unwrap_integer()?;
498
499                let budget = self
500                    .costs
501                    .builtin_costs
502                    .get_cost(
503                        DefaultFunction::LessThanInteger,
504                        &[
505                            cost_model::integer_ex_mem(arg1),
506                            cost_model::integer_ex_mem(arg2),
507                        ],
508                    )
509                    .ok_or(MachineError::NoCostForBuiltin(
510                        DefaultFunction::LessThanInteger,
511                    ))?;
512
513                self.spend_budget(budget)?;
514
515                let result = arg1 < arg2;
516
517                let value = Value::bool(self.arena, result);
518
519                Ok(value)
520            }
521            DefaultFunction::ConsByteString => {
522                let arg1 = runtime.args[0].unwrap_integer()?;
523                let arg2 = runtime.args[1].unwrap_byte_string()?;
524
525                let budget = self
526                    .costs
527                    .builtin_costs
528                    .get_cost(
529                        DefaultFunction::ConsByteString,
530                        &[
531                            cost_model::integer_ex_mem(arg1),
532                            cost_model::byte_string_ex_mem(arg2),
533                        ],
534                    )
535                    .ok_or(MachineError::NoCostForBuiltin(
536                        DefaultFunction::ConsByteString,
537                    ))?;
538
539                self.spend_budget(budget)?;
540
541                let byte: u8 = match &self.semantics {
542                    BuiltinSemantics::V1 => {
543                        let wrap: Integer = arg1 % 256;
544
545                        wrap.try_into().expect("should cast to u64 just fine")
546                    }
547                    BuiltinSemantics::V2 => {
548                        if *arg1 > Integer::from(255) || *arg1 < Integer::from(0) {
549                            return Err(MachineError::byte_string_cons_not_a_byte(arg1));
550                        }
551
552                        arg1.try_into().expect("should cast to u8 just fine")
553                    }
554                };
555
556                let mut ret = BumpVec::with_capacity_in(arg2.len() + 1, self.arena.as_bump());
557
558                ret.push(byte);
559
560                ret.extend_from_slice(arg2);
561
562                let ret = self.arena.alloc(ret);
563
564                let value = Value::byte_string(self.arena, ret);
565
566                Ok(value)
567            }
568            DefaultFunction::SliceByteString => {
569                let arg1 = runtime.args[0].unwrap_integer()?;
570                let arg2 = runtime.args[1].unwrap_integer()?;
571                let arg3 = runtime.args[2].unwrap_byte_string()?;
572
573                let budget = self
574                    .costs
575                    .builtin_costs
576                    .get_cost(
577                        DefaultFunction::SliceByteString,
578                        &[
579                            cost_model::integer_ex_mem(arg1),
580                            cost_model::integer_ex_mem(arg2),
581                            cost_model::byte_string_ex_mem(arg3),
582                        ],
583                    )
584                    .ok_or(MachineError::NoCostForBuiltin(
585                        DefaultFunction::SliceByteString,
586                    ))?;
587
588                self.spend_budget(budget)?;
589
590                let skip: usize = if *arg1 < Integer::ZERO {
591                    0
592                } else if *arg1 > arg3.len().into() {
593                    arg3.len()
594                } else {
595                    arg1.try_into().expect("should cast to usize just fine")
596                };
597
598                let take: usize = if *arg2 < Integer::ZERO {
599                    0
600                } else if *arg2 > arg3.len().into() {
601                    arg3.len()
602                } else {
603                    arg2.try_into().expect("should cast to usize just fine")
604                };
605
606                let skip_take: usize = if skip + take > arg3.len() {
607                    arg3.len()
608                } else {
609                    skip + take
610                };
611
612                let value = Value::byte_string(self.arena, &arg3[skip..(skip_take)]);
613
614                Ok(value)
615            }
616            DefaultFunction::LengthOfByteString => {
617                let arg1 = runtime.args[0].unwrap_byte_string()?;
618
619                let budget = self
620                    .costs
621                    .builtin_costs
622                    .get_cost(
623                        DefaultFunction::LengthOfByteString,
624                        &[cost_model::byte_string_ex_mem(arg1)],
625                    )
626                    .ok_or(MachineError::NoCostForBuiltin(
627                        DefaultFunction::LengthOfByteString,
628                    ))?;
629
630                self.spend_budget(budget)?;
631
632                let result: Integer = arg1.len().into();
633
634                let new = self.arena.alloc_integer(result);
635                let value = Value::integer(self.arena, new);
636
637                Ok(value)
638            }
639            DefaultFunction::IndexByteString => {
640                let arg1 = runtime.args[0].unwrap_byte_string()?;
641                let arg2 = runtime.args[1].unwrap_integer()?;
642
643                let budget = self
644                    .costs
645                    .builtin_costs
646                    .get_cost(
647                        DefaultFunction::IndexByteString,
648                        &[
649                            cost_model::byte_string_ex_mem(arg1),
650                            cost_model::integer_ex_mem(arg2),
651                        ],
652                    )
653                    .ok_or(MachineError::NoCostForBuiltin(
654                        DefaultFunction::IndexByteString,
655                    ))?;
656
657                self.spend_budget(budget)?;
658
659                let index: i128 = arg2.try_into().unwrap();
660
661                if 0 <= index && (index as usize) < arg1.len() {
662                    let result: Integer = arg1[index as usize].into();
663                    let new = self.arena.alloc_integer(result);
664                    let value = Value::integer(self.arena, new);
665
666                    Ok(value)
667                } else {
668                    Err(MachineError::byte_string_out_of_bounds(arg1, arg2))
669                }
670            }
671            DefaultFunction::LessThanByteString => {
672                let arg1 = runtime.args[0].unwrap_byte_string()?;
673                let arg2 = runtime.args[1].unwrap_byte_string()?;
674
675                let budget = self
676                    .costs
677                    .builtin_costs
678                    .get_cost(
679                        DefaultFunction::LessThanByteString,
680                        &[
681                            cost_model::byte_string_ex_mem(arg1),
682                            cost_model::byte_string_ex_mem(arg2),
683                        ],
684                    )
685                    .ok_or(MachineError::NoCostForBuiltin(
686                        DefaultFunction::LessThanByteString,
687                    ))?;
688
689                self.spend_budget(budget)?;
690
691                let result = arg1 < arg2;
692
693                let value = Value::bool(self.arena, result);
694
695                Ok(value)
696            }
697            DefaultFunction::LessThanEqualsByteString => {
698                let arg1 = runtime.args[0].unwrap_byte_string()?;
699                let arg2 = runtime.args[1].unwrap_byte_string()?;
700
701                let budget = self
702                    .costs
703                    .builtin_costs
704                    .get_cost(
705                        DefaultFunction::LessThanEqualsByteString,
706                        &[
707                            cost_model::byte_string_ex_mem(arg1),
708                            cost_model::byte_string_ex_mem(arg2),
709                        ],
710                    )
711                    .ok_or(MachineError::NoCostForBuiltin(
712                        DefaultFunction::LessThanEqualsByteString,
713                    ))?;
714
715                self.spend_budget(budget)?;
716
717                let result = arg1 <= arg2;
718
719                let value = Value::bool(self.arena, result);
720
721                Ok(value)
722            }
723            DefaultFunction::Sha2_256 => {
724                use cryptoxide::{digest::Digest, sha2::Sha256};
725
726                let arg1 = runtime.args[0].unwrap_byte_string()?;
727
728                let budget = self
729                    .costs
730                    .builtin_costs
731                    .get_cost(
732                        DefaultFunction::Sha2_256,
733                        &[cost_model::byte_string_ex_mem(arg1)],
734                    )
735                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Sha2_256))?;
736
737                self.spend_budget(budget)?;
738
739                let mut hasher = Sha256::new();
740
741                hasher.input(arg1);
742
743                let mut bytes =
744                    BumpVec::with_capacity_in(hasher.output_bytes(), self.arena.as_bump());
745
746                unsafe {
747                    bytes.set_len(hasher.output_bytes());
748                }
749
750                hasher.result(&mut bytes);
751
752                let bytes = self.arena.alloc(bytes);
753
754                let value = Value::byte_string(self.arena, bytes);
755
756                Ok(value)
757            }
758            DefaultFunction::Sha3_256 => {
759                use cryptoxide::{digest::Digest, sha3::Sha3_256};
760
761                let arg1 = runtime.args[0].unwrap_byte_string()?;
762
763                let budget = self
764                    .costs
765                    .builtin_costs
766                    .get_cost(
767                        DefaultFunction::Sha3_256,
768                        &[cost_model::byte_string_ex_mem(arg1)],
769                    )
770                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Sha3_256))?;
771
772                self.spend_budget(budget)?;
773
774                let mut hasher = Sha3_256::new();
775
776                hasher.input(arg1);
777
778                let mut bytes =
779                    BumpVec::with_capacity_in(hasher.output_bytes(), self.arena.as_bump());
780
781                unsafe {
782                    bytes.set_len(hasher.output_bytes());
783                }
784
785                hasher.result(&mut bytes);
786
787                let bytes = self.arena.alloc(bytes);
788
789                let value = Value::byte_string(self.arena, bytes);
790
791                Ok(value)
792            }
793            DefaultFunction::Blake2b_256 => {
794                use cryptoxide::{blake2b::Blake2b, digest::Digest};
795
796                let arg1 = runtime.args[0].unwrap_byte_string()?;
797
798                let budget = self
799                    .costs
800                    .builtin_costs
801                    .get_cost(
802                        DefaultFunction::Blake2b_256,
803                        &[cost_model::byte_string_ex_mem(arg1)],
804                    )
805                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Blake2b_256))?;
806
807                self.spend_budget(budget)?;
808
809                let mut digest = BumpVec::with_capacity_in(32, self.arena.as_bump());
810
811                unsafe {
812                    digest.set_len(32);
813                }
814
815                let mut context = Blake2b::new(32);
816
817                context.input(arg1);
818                context.result(&mut digest);
819
820                let digest = self.arena.alloc(digest);
821
822                let value = Value::byte_string(self.arena, digest);
823
824                Ok(value)
825            }
826            DefaultFunction::Keccak_256 => {
827                use cryptoxide::{digest::Digest, sha3::Keccak256};
828
829                let arg1 = runtime.args[0].unwrap_byte_string()?;
830
831                let budget = self
832                    .costs
833                    .builtin_costs
834                    .get_cost(
835                        DefaultFunction::Keccak_256,
836                        &[cost_model::byte_string_ex_mem(arg1)],
837                    )
838                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Keccak_256))?;
839
840                self.spend_budget(budget)?;
841
842                let mut hasher = Keccak256::new();
843
844                hasher.input(arg1);
845
846                let mut bytes =
847                    BumpVec::with_capacity_in(hasher.output_bytes(), self.arena.as_bump());
848
849                unsafe {
850                    bytes.set_len(hasher.output_bytes());
851                }
852
853                hasher.result(&mut bytes);
854
855                let bytes = self.arena.alloc(bytes);
856
857                let value = Value::byte_string(self.arena, bytes);
858
859                Ok(value)
860            }
861            DefaultFunction::Blake2b_224 => {
862                use cryptoxide::{blake2b::Blake2b, digest::Digest};
863
864                let arg1 = runtime.args[0].unwrap_byte_string()?;
865
866                let budget = self
867                    .costs
868                    .builtin_costs
869                    .get_cost(
870                        DefaultFunction::Blake2b_224,
871                        &[cost_model::byte_string_ex_mem(arg1)],
872                    )
873                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Blake2b_224))?;
874
875                self.spend_budget(budget)?;
876
877                let mut digest = BumpVec::with_capacity_in(28, self.arena.as_bump());
878
879                unsafe {
880                    digest.set_len(28);
881                }
882
883                let mut context = Blake2b::new(28);
884
885                context.input(arg1);
886                context.result(&mut digest);
887
888                let digest = self.arena.alloc(digest);
889
890                let value = Value::byte_string(self.arena, digest);
891
892                Ok(value)
893            }
894            DefaultFunction::VerifyEd25519Signature => {
895                use cryptoxide::ed25519;
896
897                let public_key = runtime.args[0].unwrap_byte_string()?;
898                let message = runtime.args[1].unwrap_byte_string()?;
899                let signature = runtime.args[2].unwrap_byte_string()?;
900
901                let budget = self
902                    .costs
903                    .builtin_costs
904                    .get_cost(
905                        DefaultFunction::VerifyEd25519Signature,
906                        &[
907                            cost_model::byte_string_ex_mem(public_key),
908                            cost_model::byte_string_ex_mem(message),
909                            cost_model::byte_string_ex_mem(signature),
910                        ],
911                    )
912                    .ok_or(MachineError::NoCostForBuiltin(
913                        DefaultFunction::VerifyEd25519Signature,
914                    ))?;
915
916                self.spend_budget(budget)?;
917
918                let public_key: [u8; 32] =
919                    public_key.try_into().map_err(|e: TryFromSliceError| {
920                        MachineError::unexpected_ed25519_public_key_length(e)
921                    })?;
922
923                let signature: [u8; 64] =
924                    signature.try_into().map_err(|e: TryFromSliceError| {
925                        MachineError::unexpected_ed25519_signature_length(e)
926                    })?;
927
928                let valid = ed25519::verify(message, &public_key, &signature);
929
930                let value = Value::bool(self.arena, valid);
931
932                Ok(value)
933            }
934            DefaultFunction::VerifyEcdsaSecp256k1Signature => {
935                use secp256k1::{ecdsa::Signature, Message, PublicKey, Secp256k1};
936
937                let public_key = runtime.args[0].unwrap_byte_string()?;
938                let message = runtime.args[1].unwrap_byte_string()?;
939                let signature = runtime.args[2].unwrap_byte_string()?;
940
941                let budget = self
942                    .costs
943                    .builtin_costs
944                    .get_cost(
945                        DefaultFunction::VerifyEcdsaSecp256k1Signature,
946                        &[
947                            cost_model::byte_string_ex_mem(public_key),
948                            cost_model::byte_string_ex_mem(message),
949                            cost_model::byte_string_ex_mem(signature),
950                        ],
951                    )
952                    .ok_or(MachineError::NoCostForBuiltin(
953                        DefaultFunction::VerifyEcdsaSecp256k1Signature,
954                    ))?;
955
956                self.spend_budget(budget)?;
957
958                let secp = Secp256k1::verification_only();
959
960                let public_key =
961                    PublicKey::from_slice(public_key).map_err(MachineError::secp256k1)?;
962
963                let signature =
964                    Signature::from_compact(signature).map_err(MachineError::secp256k1)?;
965
966                let message =
967                    Message::from_digest_slice(message).map_err(MachineError::secp256k1)?;
968
969                let valid = secp.verify_ecdsa(&message, &signature, &public_key);
970
971                let value = Value::bool(self.arena, valid.is_ok());
972
973                Ok(value)
974            }
975            DefaultFunction::VerifySchnorrSecp256k1Signature => {
976                use secp256k1::{schnorr::Signature, Secp256k1, XOnlyPublicKey};
977
978                let public_key = runtime.args[0].unwrap_byte_string()?;
979                let message = runtime.args[1].unwrap_byte_string()?;
980                let signature = runtime.args[2].unwrap_byte_string()?;
981
982                let budget = self
983                    .costs
984                    .builtin_costs
985                    .get_cost(
986                        DefaultFunction::VerifySchnorrSecp256k1Signature,
987                        &[
988                            cost_model::byte_string_ex_mem(public_key),
989                            cost_model::byte_string_ex_mem(message),
990                            cost_model::byte_string_ex_mem(signature),
991                        ],
992                    )
993                    .ok_or(MachineError::NoCostForBuiltin(
994                        DefaultFunction::VerifySchnorrSecp256k1Signature,
995                    ))?;
996
997                self.spend_budget(budget)?;
998
999                let secp = Secp256k1::verification_only();
1000
1001                let public_key =
1002                    XOnlyPublicKey::from_slice(public_key).map_err(MachineError::secp256k1)?;
1003
1004                let signature =
1005                    Signature::from_slice(signature).map_err(MachineError::secp256k1)?;
1006
1007                let valid = secp.verify_schnorr(&signature, message, &public_key);
1008
1009                let value = Value::bool(self.arena, valid.is_ok());
1010
1011                Ok(value)
1012            }
1013            DefaultFunction::AppendString => {
1014                let arg1 = runtime.args[0].unwrap_string()?;
1015                let arg2 = runtime.args[1].unwrap_string()?;
1016
1017                let budget = self
1018                    .costs
1019                    .builtin_costs
1020                    .get_cost(
1021                        DefaultFunction::AppendString,
1022                        &[
1023                            cost_model::string_ex_mem(arg1),
1024                            cost_model::string_ex_mem(arg2),
1025                        ],
1026                    )
1027                    .ok_or(MachineError::NoCostForBuiltin(
1028                        DefaultFunction::AppendString,
1029                    ))?;
1030
1031                self.spend_budget(budget)?;
1032
1033                let mut new = BumpString::new_in(self.arena.as_bump());
1034
1035                new.push_str(arg1);
1036                new.push_str(arg2);
1037
1038                let new = self.arena.alloc(new);
1039
1040                let value = Value::string(self.arena, new);
1041
1042                Ok(value)
1043            }
1044            DefaultFunction::EqualsString => {
1045                let arg1 = runtime.args[0].unwrap_string()?;
1046                let arg2 = runtime.args[1].unwrap_string()?;
1047
1048                let budget = self
1049                    .costs
1050                    .builtin_costs
1051                    .get_cost(
1052                        DefaultFunction::EqualsString,
1053                        &[
1054                            cost_model::string_ex_mem(arg1),
1055                            cost_model::string_ex_mem(arg2),
1056                        ],
1057                    )
1058                    .ok_or(MachineError::NoCostForBuiltin(
1059                        DefaultFunction::EqualsString,
1060                    ))?;
1061
1062                self.spend_budget(budget)?;
1063
1064                let value = Value::bool(self.arena, arg1 == arg2);
1065
1066                Ok(value)
1067            }
1068            DefaultFunction::EncodeUtf8 => {
1069                let arg1 = runtime.args[0].unwrap_string()?;
1070
1071                let budget = self
1072                    .costs
1073                    .builtin_costs
1074                    .get_cost(
1075                        DefaultFunction::EncodeUtf8,
1076                        &[cost_model::string_ex_mem(arg1)],
1077                    )
1078                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::EncodeUtf8))?;
1079
1080                self.spend_budget(budget)?;
1081
1082                let s_bytes = arg1.as_bytes();
1083
1084                let mut bytes = BumpVec::with_capacity_in(s_bytes.len(), self.arena.as_bump());
1085
1086                bytes.extend_from_slice(s_bytes);
1087
1088                let bytes = self.arena.alloc(bytes);
1089
1090                let value = Value::byte_string(self.arena, bytes);
1091
1092                Ok(value)
1093            }
1094            DefaultFunction::DecodeUtf8 => {
1095                let arg1 = runtime.args[0].unwrap_byte_string()?;
1096
1097                let budget = self
1098                    .costs
1099                    .builtin_costs
1100                    .get_cost(
1101                        DefaultFunction::DecodeUtf8,
1102                        &[cost_model::byte_string_ex_mem(arg1)],
1103                    )
1104                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::DecodeUtf8))?;
1105
1106                self.spend_budget(budget)?;
1107
1108                let string = str::from_utf8(arg1).map_err(|e| MachineError::decode_utf8(e))?;
1109
1110                let value = Value::string(self.arena, string);
1111
1112                Ok(value)
1113            }
1114            DefaultFunction::ChooseUnit => {
1115                runtime.args[0].unwrap_unit()?;
1116                let arg2 = runtime.args[1];
1117
1118                let budget = self
1119                    .costs
1120                    .builtin_costs
1121                    .get_cost(
1122                        DefaultFunction::ChooseUnit,
1123                        &[cost_model::UNIT_EX_MEM, cost_model::value_ex_mem(arg2)],
1124                    )
1125                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ChooseUnit))?;
1126
1127                self.spend_budget(budget)?;
1128
1129                Ok(arg2)
1130            }
1131            DefaultFunction::Trace => {
1132                let arg1 = runtime.args[0].unwrap_string()?;
1133                let arg2 = runtime.args[1];
1134
1135                let budget = self
1136                    .costs
1137                    .builtin_costs
1138                    .get_cost(
1139                        DefaultFunction::Trace,
1140                        &[
1141                            cost_model::string_ex_mem(arg1),
1142                            cost_model::value_ex_mem(arg2),
1143                        ],
1144                    )
1145                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Trace))?;
1146
1147                self.spend_budget(budget)?;
1148
1149                self.logs.push(arg1.to_string());
1150
1151                Ok(arg2)
1152            }
1153            DefaultFunction::FstPair => {
1154                let (_, _, first, second) = runtime.args[0].unwrap_pair()?;
1155
1156                let budget = self
1157                    .costs
1158                    .builtin_costs
1159                    .get_cost(
1160                        DefaultFunction::FstPair,
1161                        &[cost_model::pair_ex_mem(first, second)],
1162                    )
1163                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::FstPair))?;
1164
1165                self.spend_budget(budget)?;
1166
1167                let value = Value::con(self.arena, first);
1168
1169                Ok(value)
1170            }
1171            DefaultFunction::SndPair => {
1172                let (_, _, first, second) = runtime.args[0].unwrap_pair()?;
1173
1174                let budget = self
1175                    .costs
1176                    .builtin_costs
1177                    .get_cost(
1178                        DefaultFunction::SndPair,
1179                        &[cost_model::pair_ex_mem(first, second)],
1180                    )
1181                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::SndPair))?;
1182
1183                self.spend_budget(budget)?;
1184
1185                let value = Value::con(self.arena, second);
1186
1187                Ok(value)
1188            }
1189            DefaultFunction::ChooseList => {
1190                let (_, list) = runtime.args[0].unwrap_list()?;
1191                let arg2 = runtime.args[1];
1192                let arg3 = runtime.args[2];
1193
1194                let budget = self
1195                    .costs
1196                    .builtin_costs
1197                    .get_cost(
1198                        DefaultFunction::ChooseList,
1199                        &[
1200                            cost_model::proto_list_ex_mem(list),
1201                            cost_model::value_ex_mem(arg2),
1202                            cost_model::value_ex_mem(arg3),
1203                        ],
1204                    )
1205                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ChooseList))?;
1206
1207                self.spend_budget(budget)?;
1208
1209                if list.is_empty() {
1210                    Ok(arg2)
1211                } else {
1212                    Ok(arg3)
1213                }
1214            }
1215            DefaultFunction::MkCons => {
1216                let item = runtime.args[0].unwrap_constant()?;
1217                let (typ, list) = runtime.args[1].unwrap_list()?;
1218
1219                let budget = self
1220                    .costs
1221                    .builtin_costs
1222                    .get_cost(
1223                        DefaultFunction::MkCons,
1224                        &[
1225                            cost_model::constant_ex_mem(item),
1226                            cost_model::proto_list_ex_mem(list),
1227                        ],
1228                    )
1229                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::MkCons))?;
1230
1231                self.spend_budget(budget)?;
1232
1233                if item.type_of(self.arena) != typ {
1234                    return Err(MachineError::mk_cons_type_mismatch(item));
1235                }
1236
1237                let mut new_list = BumpVec::with_capacity_in(list.len() + 1, self.arena.as_bump());
1238
1239                new_list.push(item);
1240
1241                new_list.extend_from_slice(list);
1242
1243                let new_list = self.arena.alloc(new_list);
1244
1245                let constant = Constant::proto_list(self.arena, typ, new_list);
1246
1247                let value = constant.value(self.arena);
1248
1249                Ok(value)
1250            }
1251            DefaultFunction::HeadList => {
1252                let (_, list) = runtime.args[0].unwrap_list()?;
1253
1254                let budget = self
1255                    .costs
1256                    .builtin_costs
1257                    .get_cost(
1258                        DefaultFunction::HeadList,
1259                        &[cost_model::proto_list_ex_mem(list)],
1260                    )
1261                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::HeadList))?;
1262
1263                self.spend_budget(budget)?;
1264
1265                if list.is_empty() {
1266                    Err(MachineError::empty_list(list))
1267                } else {
1268                    let value = Value::con(self.arena, list[0]);
1269
1270                    Ok(value)
1271                }
1272            }
1273            DefaultFunction::TailList => {
1274                let (t1, list) = runtime.args[0].unwrap_list()?;
1275
1276                let budget = self
1277                    .costs
1278                    .builtin_costs
1279                    .get_cost(
1280                        DefaultFunction::TailList,
1281                        &[cost_model::proto_list_ex_mem(list)],
1282                    )
1283                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::TailList))?;
1284
1285                self.spend_budget(budget)?;
1286
1287                if list.is_empty() {
1288                    Err(MachineError::empty_list(list))
1289                } else {
1290                    let constant = Constant::proto_list(self.arena, t1, &list[1..]);
1291
1292                    let value = Value::con(self.arena, constant);
1293
1294                    Ok(value)
1295                }
1296            }
1297            DefaultFunction::NullList => {
1298                let (_, list) = runtime.args[0].unwrap_list()?;
1299
1300                let budget = self
1301                    .costs
1302                    .builtin_costs
1303                    .get_cost(
1304                        DefaultFunction::NullList,
1305                        &[cost_model::proto_list_ex_mem(list)],
1306                    )
1307                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::NullList))?;
1308
1309                self.spend_budget(budget)?;
1310
1311                let value = Value::bool(self.arena, list.is_empty());
1312
1313                Ok(value)
1314            }
1315            DefaultFunction::ChooseData => {
1316                let arg1 = runtime.args[0].unwrap_constant()?.unwrap_data()?;
1317                let arg2 = runtime.args[1];
1318                let arg3 = runtime.args[2];
1319                let arg4 = runtime.args[3];
1320                let arg5 = runtime.args[4];
1321                let arg6 = runtime.args[5];
1322
1323                let budget = self
1324                    .costs
1325                    .builtin_costs
1326                    .get_cost(
1327                        DefaultFunction::ChooseData,
1328                        &[
1329                            cost_model::data_ex_mem(arg1),
1330                            cost_model::value_ex_mem(arg2),
1331                            cost_model::value_ex_mem(arg3),
1332                            cost_model::value_ex_mem(arg4),
1333                            cost_model::value_ex_mem(arg5),
1334                            cost_model::value_ex_mem(arg6),
1335                        ],
1336                    )
1337                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ChooseData))?;
1338
1339                self.spend_budget(budget)?;
1340
1341                match arg1 {
1342                    PlutusData::Constr { .. } => Ok(arg2),
1343                    PlutusData::Map(_) => Ok(arg3),
1344                    PlutusData::List(_) => Ok(arg4),
1345                    PlutusData::Integer(_) => Ok(arg5),
1346                    PlutusData::ByteString(_) => Ok(arg6),
1347                }
1348            }
1349            DefaultFunction::ConstrData => {
1350                let tag = runtime.args[0].unwrap_integer()?;
1351                let (typ, fields) = runtime.args[1].unwrap_list()?;
1352
1353                let budget = self
1354                    .costs
1355                    .builtin_costs
1356                    .get_cost(
1357                        DefaultFunction::ConstrData,
1358                        &[
1359                            cost_model::integer_ex_mem(tag),
1360                            cost_model::proto_list_ex_mem(fields),
1361                        ],
1362                    )
1363                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ConstrData))?;
1364
1365                self.spend_budget(budget)?;
1366
1367                if *typ != Type::Data {
1368                    return Err(MachineError::type_mismatch(
1369                        Type::Data,
1370                        runtime.args[1].unwrap_constant()?,
1371                    ));
1372                }
1373
1374                let tag = tag.try_into().expect("should cast to u64 just fine");
1375                let fields: BumpVec<'_, _> = fields
1376                    .iter()
1377                    .map(|d| match d {
1378                        Constant::Data(d) => *d,
1379                        _ => unreachable!(),
1380                    })
1381                    .collect_in(self.arena.as_bump());
1382                let fields = self.arena.alloc(fields);
1383
1384                let data = PlutusData::constr(self.arena, tag, fields);
1385
1386                let constant = Constant::data(self.arena, data);
1387
1388                let value = Value::con(self.arena, constant);
1389
1390                Ok(value)
1391            }
1392            DefaultFunction::MapData => {
1393                let (r#type, list) = runtime.args[0].unwrap_list()?;
1394
1395                if !matches!(r#type, Type::Pair(Type::Data, Type::Data)) {
1396                    return Err(MachineError::type_mismatch(
1397                        Type::List(Type::pair(
1398                            self.arena,
1399                            Type::data(self.arena),
1400                            Type::data(self.arena),
1401                        )),
1402                        runtime.args[0].unwrap_constant()?,
1403                    ));
1404                }
1405
1406                let budget = self
1407                    .costs
1408                    .builtin_costs
1409                    .get_cost(
1410                        DefaultFunction::MapData,
1411                        &[cost_model::proto_list_ex_mem(list)],
1412                    )
1413                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::MapData))?;
1414
1415                self.spend_budget(budget)?;
1416
1417                let mut map = BumpVec::new_in(self.arena.as_bump());
1418
1419                for item in list {
1420                    let Constant::ProtoPair(Type::Data, Type::Data, left, right) = item else {
1421                        unreachable!("is this really unreachable?")
1422                    };
1423
1424                    let Constant::Data(key) = left else {
1425                        unreachable!()
1426                    };
1427
1428                    let Constant::Data(value) = right else {
1429                        unreachable!()
1430                    };
1431
1432                    map.push((*key, *value));
1433                }
1434
1435                let map = self.arena.alloc(map);
1436
1437                let value = PlutusData::map(self.arena, map)
1438                    .constant(self.arena)
1439                    .value(self.arena);
1440
1441                Ok(value)
1442            }
1443            DefaultFunction::ListData => {
1444                let (typ, fields) = runtime.args[0].unwrap_list()?;
1445
1446                let budget = self
1447                    .costs
1448                    .builtin_costs
1449                    .get_cost(
1450                        DefaultFunction::ListData,
1451                        &[cost_model::proto_list_ex_mem(fields)],
1452                    )
1453                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ListData))?;
1454
1455                self.spend_budget(budget)?;
1456
1457                if *typ != Type::Data {
1458                    return Err(MachineError::type_mismatch(
1459                        Type::Data,
1460                        runtime.args[0].unwrap_constant()?,
1461                    ));
1462                }
1463
1464                let fields: BumpVec<'_, _> = fields
1465                    .iter()
1466                    .map(|d| match d {
1467                        Constant::Data(d) => *d,
1468                        _ => unreachable!(),
1469                    })
1470                    .collect_in(self.arena.as_bump());
1471                let fields = self.arena.alloc(fields);
1472
1473                let value = PlutusData::list(self.arena, fields)
1474                    .constant(self.arena)
1475                    .value(self.arena);
1476
1477                Ok(value)
1478            }
1479            DefaultFunction::IData => {
1480                let i = runtime.args[0].unwrap_integer()?;
1481
1482                let budget = self
1483                    .costs
1484                    .builtin_costs
1485                    .get_cost(DefaultFunction::IData, &[cost_model::integer_ex_mem(i)])
1486                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::IData))?;
1487
1488                self.spend_budget(budget)?;
1489
1490                let i = PlutusData::integer(self.arena, i);
1491
1492                let value = i.constant(self.arena).value(self.arena);
1493
1494                Ok(value)
1495            }
1496            DefaultFunction::BData => {
1497                let b = runtime.args[0].unwrap_byte_string()?;
1498
1499                let budget = self
1500                    .costs
1501                    .builtin_costs
1502                    .get_cost(DefaultFunction::BData, &[cost_model::byte_string_ex_mem(b)])
1503                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::BData))?;
1504
1505                self.spend_budget(budget)?;
1506
1507                let b = PlutusData::byte_string(self.arena, b);
1508
1509                let value = b.constant(self.arena).value(self.arena);
1510
1511                Ok(value)
1512            }
1513            DefaultFunction::UnConstrData => {
1514                let (tag, fields) = runtime.args[0]
1515                    .unwrap_constant()?
1516                    .unwrap_data()?
1517                    .unwrap_constr()?;
1518
1519                let budget = self
1520                    .costs
1521                    .builtin_costs
1522                    .get_cost(
1523                        DefaultFunction::UnConstrData,
1524                        &[cost_model::data_list_ex_mem(fields)],
1525                    )
1526                    .ok_or(MachineError::NoCostForBuiltin(
1527                        DefaultFunction::UnConstrData,
1528                    ))?;
1529
1530                self.spend_budget(budget)?;
1531
1532                let list: BumpVec<'_, _> = fields
1533                    .iter()
1534                    .map(|d| Constant::data(self.arena, d))
1535                    .collect_in(self.arena.as_bump());
1536                let list = self.arena.alloc(list);
1537
1538                let constant = Constant::proto_pair(
1539                    self.arena,
1540                    Type::integer(self.arena),
1541                    Type::list(self.arena, Type::data(self.arena)),
1542                    Constant::integer_from(self.arena, *tag as i128),
1543                    Constant::proto_list(self.arena, Type::data(self.arena), list),
1544                );
1545
1546                let value = Value::con(self.arena, constant);
1547
1548                Ok(value)
1549            }
1550            DefaultFunction::UnMapData => {
1551                let map = runtime.args[0]
1552                    .unwrap_constant()?
1553                    .unwrap_data()?
1554                    .unwrap_map()?;
1555
1556                let budget = self
1557                    .costs
1558                    .builtin_costs
1559                    .get_cost(
1560                        DefaultFunction::UnMapData,
1561                        &[cost_model::data_map_ex_mem(map)],
1562                    )
1563                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::UnMapData))?;
1564
1565                self.spend_budget(budget)?;
1566
1567                let list: BumpVec<'_, _> = map
1568                    .iter()
1569                    .map(|(k, v)| {
1570                        Constant::proto_pair(
1571                            self.arena,
1572                            Type::data(self.arena),
1573                            Type::data(self.arena),
1574                            Constant::data(self.arena, k),
1575                            Constant::data(self.arena, v),
1576                        )
1577                    })
1578                    .collect_in(self.arena.as_bump());
1579                let list = self.arena.alloc(list);
1580
1581                let constant = Constant::proto_list(
1582                    self.arena,
1583                    Type::pair(self.arena, Type::data(self.arena), Type::data(self.arena)),
1584                    list,
1585                );
1586
1587                let value = Value::con(self.arena, constant);
1588
1589                Ok(value)
1590            }
1591            DefaultFunction::UnListData => {
1592                let list = runtime.args[0]
1593                    .unwrap_constant()?
1594                    .unwrap_data()?
1595                    .unwrap_list()?;
1596
1597                let budget = self
1598                    .costs
1599                    .builtin_costs
1600                    .get_cost(
1601                        DefaultFunction::UnListData,
1602                        &[cost_model::data_list_ex_mem(list)],
1603                    )
1604                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::UnListData))?;
1605
1606                self.spend_budget(budget)?;
1607
1608                let list: BumpVec<'_, _> = list
1609                    .iter()
1610                    .map(|d| Constant::data(self.arena, d))
1611                    .collect_in(self.arena.as_bump());
1612                let list = self.arena.alloc(list);
1613
1614                let constant = Constant::proto_list(self.arena, Type::data(self.arena), list);
1615
1616                let value = Value::con(self.arena, constant);
1617
1618                Ok(value)
1619            }
1620            DefaultFunction::UnIData => {
1621                let i = runtime.args[0]
1622                    .unwrap_constant()?
1623                    .unwrap_data()?
1624                    .unwrap_integer()?;
1625
1626                let budget = self
1627                    .costs
1628                    .builtin_costs
1629                    .get_cost(
1630                        DefaultFunction::UnIData,
1631                        &[cost_model::data_integer_ex_mem(i)],
1632                    )
1633                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::UnIData))?;
1634
1635                self.spend_budget(budget)?;
1636
1637                let value = Value::integer(self.arena, i);
1638
1639                Ok(value)
1640            }
1641            DefaultFunction::UnBData => {
1642                let bs = runtime.args[0]
1643                    .unwrap_constant()?
1644                    .unwrap_data()?
1645                    .unwrap_byte_string()?;
1646
1647                let budget = self
1648                    .costs
1649                    .builtin_costs
1650                    .get_cost(
1651                        DefaultFunction::UnBData,
1652                        &[cost_model::data_byte_string_ex_mem(bs)],
1653                    )
1654                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::UnBData))?;
1655
1656                self.spend_budget(budget)?;
1657
1658                let value = Value::byte_string(self.arena, bs);
1659
1660                Ok(value)
1661            }
1662            DefaultFunction::EqualsData => {
1663                let d1 = runtime.args[0].unwrap_constant()?.unwrap_data()?;
1664                let d2 = runtime.args[1].unwrap_constant()?.unwrap_data()?;
1665
1666                let budget = self
1667                    .costs
1668                    .builtin_costs
1669                    .get_cost(
1670                        DefaultFunction::EqualsData,
1671                        &[cost_model::data_ex_mem(d1), cost_model::data_ex_mem(d2)],
1672                    )
1673                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::EqualsData))?;
1674
1675                self.spend_budget(budget)?;
1676
1677                let value = Value::bool(self.arena, d1.eq(d2));
1678
1679                Ok(value)
1680            }
1681            DefaultFunction::SerialiseData => {
1682                let arg1 = runtime.args[0].unwrap_constant()?.unwrap_data()?;
1683
1684                let budget = self
1685                    .costs
1686                    .builtin_costs
1687                    .get_cost(
1688                        DefaultFunction::SerialiseData,
1689                        &[cost_model::data_ex_mem(arg1)],
1690                    )
1691                    .ok_or(MachineError::NoCostForBuiltin(
1692                        DefaultFunction::SerialiseData,
1693                    ))?;
1694
1695                self.spend_budget(budget)?;
1696
1697                let bytes = arg1.to_bytes(self.arena)?;
1698                let value = Value::byte_string(self.arena, bytes);
1699
1700                Ok(value)
1701            }
1702            DefaultFunction::MkPairData => {
1703                let d1 = runtime.args[0].unwrap_constant()?.unwrap_data()?;
1704                let d2 = runtime.args[1].unwrap_constant()?.unwrap_data()?;
1705
1706                let budget = self
1707                    .costs
1708                    .builtin_costs
1709                    .get_cost(
1710                        DefaultFunction::MkPairData,
1711                        &[cost_model::data_ex_mem(d1), cost_model::data_ex_mem(d2)],
1712                    )
1713                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::MkPairData))?;
1714
1715                self.spend_budget(budget)?;
1716
1717                let constant = Constant::proto_pair(
1718                    self.arena,
1719                    Type::data(self.arena),
1720                    Type::data(self.arena),
1721                    Constant::data(self.arena, d1),
1722                    Constant::data(self.arena, d2),
1723                );
1724
1725                let value = Value::con(self.arena, constant);
1726
1727                Ok(value)
1728            }
1729            DefaultFunction::MkNilData => {
1730                runtime.args[0].unwrap_unit()?;
1731
1732                let budget = self
1733                    .costs
1734                    .builtin_costs
1735                    .get_cost(DefaultFunction::MkNilData, &[cost_model::UNIT_EX_MEM])
1736                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::MkNilData))?;
1737
1738                self.spend_budget(budget)?;
1739
1740                let list = BumpVec::new_in(self.arena.as_bump());
1741                let list = self.arena.alloc(list);
1742
1743                let constant = Constant::proto_list(self.arena, Type::data(self.arena), list);
1744
1745                let value = Value::con(self.arena, constant);
1746
1747                Ok(value)
1748            }
1749            DefaultFunction::MkNilPairData => {
1750                runtime.args[0].unwrap_unit()?;
1751
1752                let budget = self
1753                    .costs
1754                    .builtin_costs
1755                    .get_cost(DefaultFunction::MkNilPairData, &[cost_model::UNIT_EX_MEM])
1756                    .ok_or(MachineError::NoCostForBuiltin(
1757                        DefaultFunction::MkNilPairData,
1758                    ))?;
1759
1760                self.spend_budget(budget)?;
1761
1762                let list = BumpVec::new_in(self.arena.as_bump());
1763                let list = self.arena.alloc(list);
1764
1765                let constant = Constant::proto_list(
1766                    self.arena,
1767                    Type::pair(self.arena, Type::data(self.arena), Type::data(self.arena)),
1768                    list,
1769                );
1770
1771                let value = Value::con(self.arena, constant);
1772
1773                Ok(value)
1774            }
1775            DefaultFunction::Bls12_381_G1_Add => {
1776                let arg1 = runtime.args[0].unwrap_bls12_381_g1_element()?;
1777                let arg2 = runtime.args[1].unwrap_bls12_381_g1_element()?;
1778
1779                let budget = self
1780                    .costs
1781                    .builtin_costs
1782                    .get_cost(
1783                        DefaultFunction::Bls12_381_G1_Add,
1784                        &[
1785                            cost_model::g1_element_ex_mem(),
1786                            cost_model::g1_element_ex_mem(),
1787                        ],
1788                    )
1789                    .ok_or(MachineError::NoCostForBuiltin(
1790                        DefaultFunction::Bls12_381_G1_Add,
1791                    ))?;
1792
1793                self.spend_budget(budget)?;
1794
1795                let out = self.arena.alloc(blst::blst_p1::default());
1796
1797                unsafe {
1798                    blst::blst_p1_add_or_double(out as *mut _, arg1 as *const _, arg2 as *const _);
1799                }
1800
1801                let constant = Constant::g1(self.arena, out);
1802
1803                let value = Value::con(self.arena, constant);
1804
1805                Ok(value)
1806            }
1807            DefaultFunction::Bls12_381_G1_Neg => {
1808                let arg1 = runtime.args[0].unwrap_bls12_381_g1_element()?;
1809
1810                let budget = self
1811                    .costs
1812                    .builtin_costs
1813                    .get_cost(
1814                        DefaultFunction::Bls12_381_G1_Neg,
1815                        &[cost_model::g1_element_ex_mem()],
1816                    )
1817                    .ok_or(MachineError::NoCostForBuiltin(
1818                        DefaultFunction::Bls12_381_G1_Neg,
1819                    ))?;
1820
1821                self.spend_budget(budget)?;
1822
1823                let out = self.arena.alloc(*arg1);
1824
1825                unsafe {
1826                    // second arg was true in the Cardano code
1827                    blst::blst_p1_cneg(out as *mut _, true);
1828                }
1829
1830                let constant = Constant::g1(self.arena, out);
1831
1832                let value = Value::con(self.arena, constant);
1833
1834                Ok(value)
1835            }
1836            DefaultFunction::Bls12_381_G1_ScalarMul => {
1837                let arg1 = runtime.args[0].unwrap_integer()?;
1838                let arg2 = runtime.args[1].unwrap_bls12_381_g1_element()?;
1839
1840                let budget = self
1841                    .costs
1842                    .builtin_costs
1843                    .get_cost(
1844                        DefaultFunction::Bls12_381_G1_ScalarMul,
1845                        &[
1846                            cost_model::integer_ex_mem(arg1),
1847                            cost_model::g1_element_ex_mem(),
1848                        ],
1849                    )
1850                    .ok_or(MachineError::NoCostForBuiltin(
1851                        DefaultFunction::Bls12_381_G1_ScalarMul,
1852                    ))?;
1853
1854                self.spend_budget(budget)?;
1855
1856                let size_scalar = size_of::<blst::blst_scalar>();
1857
1858                let arg1 = arg1.mod_floor(&SCALAR_PERIOD);
1859                let (_, mut arg1) = arg1.to_bytes_be();
1860
1861                if size_scalar > arg1.len() {
1862                    let diff = size_scalar - arg1.len();
1863
1864                    let mut new_vec = vec![0; diff];
1865
1866                    new_vec.append(&mut arg1);
1867
1868                    arg1 = new_vec;
1869                }
1870
1871                let out = self.arena.alloc(blst::blst_p1::default());
1872                let scalar = self.arena.alloc(blst::blst_scalar::default());
1873
1874                unsafe {
1875                    blst::blst_scalar_from_bendian(scalar as *mut _, arg1.as_ptr() as *const _);
1876
1877                    blst::blst_p1_mult(
1878                        out as *mut _,
1879                        arg2 as *const _,
1880                        scalar.b.as_ptr() as *const _,
1881                        size_scalar * 8,
1882                    );
1883                }
1884
1885                let constant = Constant::g1(self.arena, out);
1886
1887                let value = Value::con(self.arena, constant);
1888
1889                Ok(value)
1890            }
1891            DefaultFunction::Bls12_381_G1_Equal => {
1892                let arg1 = runtime.args[0].unwrap_bls12_381_g1_element()?;
1893                let arg2 = runtime.args[1].unwrap_bls12_381_g1_element()?;
1894
1895                let budget = self
1896                    .costs
1897                    .builtin_costs
1898                    .get_cost(
1899                        DefaultFunction::Bls12_381_G1_Equal,
1900                        &[
1901                            cost_model::g1_element_ex_mem(),
1902                            cost_model::g1_element_ex_mem(),
1903                        ],
1904                    )
1905                    .ok_or(MachineError::NoCostForBuiltin(
1906                        DefaultFunction::Bls12_381_G1_Equal,
1907                    ))?;
1908
1909                self.spend_budget(budget)?;
1910
1911                let is_equal = unsafe { blst::blst_p1_is_equal(arg1, arg2) };
1912
1913                let value = Value::bool(self.arena, is_equal);
1914
1915                Ok(value)
1916            }
1917            DefaultFunction::Bls12_381_G1_Compress => {
1918                let arg1 = runtime.args[0].unwrap_bls12_381_g1_element()?;
1919
1920                let budget = self
1921                    .costs
1922                    .builtin_costs
1923                    .get_cost(
1924                        DefaultFunction::Bls12_381_G1_Compress,
1925                        &[cost_model::g1_element_ex_mem()],
1926                    )
1927                    .ok_or(MachineError::NoCostForBuiltin(
1928                        DefaultFunction::Bls12_381_G1_Compress,
1929                    ))?;
1930
1931                self.spend_budget(budget)?;
1932
1933                let out = arg1.compress(self.arena);
1934
1935                let value = Value::byte_string(self.arena, out);
1936
1937                Ok(value)
1938            }
1939            DefaultFunction::Bls12_381_G1_Uncompress => {
1940                let arg1 = runtime.args[0].unwrap_byte_string()?;
1941
1942                let budget = self
1943                    .costs
1944                    .builtin_costs
1945                    .get_cost(
1946                        DefaultFunction::Bls12_381_G1_Uncompress,
1947                        &[cost_model::byte_string_ex_mem(arg1)],
1948                    )
1949                    .ok_or(MachineError::NoCostForBuiltin(
1950                        DefaultFunction::Bls12_381_G1_Uncompress,
1951                    ))?;
1952
1953                self.spend_budget(budget)?;
1954
1955                let out = blst::blst_p1::uncompress(self.arena, arg1).map_err(MachineError::bls)?;
1956
1957                let constant = Constant::g1(self.arena, out);
1958
1959                let value = Value::con(self.arena, constant);
1960
1961                Ok(value)
1962            }
1963            DefaultFunction::Bls12_381_G1_HashToGroup => {
1964                let arg1 = runtime.args[0].unwrap_byte_string()?;
1965                let arg2 = runtime.args[1].unwrap_byte_string()?;
1966
1967                let budget = self
1968                    .costs
1969                    .builtin_costs
1970                    .get_cost(
1971                        DefaultFunction::Bls12_381_G1_HashToGroup,
1972                        &[
1973                            cost_model::byte_string_ex_mem(arg1),
1974                            cost_model::byte_string_ex_mem(arg2),
1975                        ],
1976                    )
1977                    .ok_or(MachineError::NoCostForBuiltin(
1978                        DefaultFunction::Bls12_381_G1_HashToGroup,
1979                    ))?;
1980
1981                self.spend_budget(budget)?;
1982
1983                if arg2.len() > 255 {
1984                    return Err(MachineError::hash_to_curve_dst_too_big());
1985                }
1986
1987                let out = self.arena.alloc(blst::blst_p1::default());
1988                let aug = [];
1989
1990                unsafe {
1991                    blst::blst_hash_to_g1(
1992                        out as *mut _,
1993                        arg1.as_ptr(),
1994                        arg1.len(),
1995                        arg2.as_ptr(),
1996                        arg2.len(),
1997                        aug.as_ptr(),
1998                        0,
1999                    );
2000                };
2001
2002                let constant = Constant::g1(self.arena, out);
2003
2004                let value = Value::con(self.arena, constant);
2005
2006                Ok(value)
2007            }
2008            DefaultFunction::Bls12_381_G2_Add => {
2009                let arg1 = runtime.args[0].unwrap_bls12_381_g2_element()?;
2010                let arg2 = runtime.args[1].unwrap_bls12_381_g2_element()?;
2011
2012                let budget = self
2013                    .costs
2014                    .builtin_costs
2015                    .get_cost(
2016                        DefaultFunction::Bls12_381_G2_Add,
2017                        &[
2018                            cost_model::g2_element_ex_mem(),
2019                            cost_model::g2_element_ex_mem(),
2020                        ],
2021                    )
2022                    .ok_or(MachineError::NoCostForBuiltin(
2023                        DefaultFunction::Bls12_381_G2_Add,
2024                    ))?;
2025
2026                self.spend_budget(budget)?;
2027
2028                let out = self.arena.alloc(blst::blst_p2::default());
2029
2030                unsafe {
2031                    blst::blst_p2_add_or_double(out as *mut _, arg1 as *const _, arg2 as *const _);
2032                }
2033
2034                let constant = Constant::g2(self.arena, out);
2035
2036                let value = Value::con(self.arena, constant);
2037
2038                Ok(value)
2039            }
2040            DefaultFunction::Bls12_381_G2_Neg => {
2041                let arg1 = runtime.args[0].unwrap_bls12_381_g2_element()?;
2042
2043                let budget = self
2044                    .costs
2045                    .builtin_costs
2046                    .get_cost(
2047                        DefaultFunction::Bls12_381_G2_Neg,
2048                        &[cost_model::g2_element_ex_mem()],
2049                    )
2050                    .ok_or(MachineError::NoCostForBuiltin(
2051                        DefaultFunction::Bls12_381_G2_Neg,
2052                    ))?;
2053
2054                self.spend_budget(budget)?;
2055
2056                let out = self.arena.alloc(*arg1);
2057
2058                unsafe {
2059                    // second arg was true in the Cardano code
2060                    blst::blst_p2_cneg(out as *mut _, true);
2061                }
2062
2063                let constant = Constant::g2(self.arena, out);
2064
2065                let value = Value::con(self.arena, constant);
2066
2067                Ok(value)
2068            }
2069            DefaultFunction::Bls12_381_G2_ScalarMul => {
2070                let arg1 = runtime.args[0].unwrap_integer()?;
2071                let arg2 = runtime.args[1].unwrap_bls12_381_g2_element()?;
2072
2073                let budget = self
2074                    .costs
2075                    .builtin_costs
2076                    .get_cost(
2077                        DefaultFunction::Bls12_381_G2_ScalarMul,
2078                        &[
2079                            cost_model::integer_ex_mem(arg1),
2080                            cost_model::g2_element_ex_mem(),
2081                        ],
2082                    )
2083                    .ok_or(MachineError::NoCostForBuiltin(
2084                        DefaultFunction::Bls12_381_G2_ScalarMul,
2085                    ))?;
2086
2087                self.spend_budget(budget)?;
2088
2089                let size_scalar = size_of::<blst::blst_scalar>();
2090
2091                let arg1 = arg1.mod_floor(&SCALAR_PERIOD);
2092
2093                let (_, mut arg1) = arg1.to_bytes_be();
2094
2095                if size_scalar > arg1.len() {
2096                    let diff = size_scalar - arg1.len();
2097
2098                    let mut new_vec = vec![0; diff];
2099                    unsafe {
2100                        new_vec.set_len(diff);
2101                    }
2102
2103                    new_vec.append(&mut arg1);
2104
2105                    arg1 = new_vec;
2106                }
2107
2108                let out = self.arena.alloc(blst::blst_p2::default());
2109                let scalar = self.arena.alloc(blst::blst_scalar::default());
2110
2111                unsafe {
2112                    blst::blst_scalar_from_bendian(scalar as *mut _, arg1.as_ptr() as *const _);
2113
2114                    blst::blst_p2_mult(
2115                        out as *mut _,
2116                        arg2 as *const _,
2117                        scalar.b.as_ptr() as *const _,
2118                        size_scalar * 8,
2119                    );
2120                }
2121
2122                let constant = Constant::g2(self.arena, out);
2123
2124                let value = Value::con(self.arena, constant);
2125
2126                Ok(value)
2127            }
2128            DefaultFunction::Bls12_381_G2_Equal => {
2129                let arg1 = runtime.args[0].unwrap_bls12_381_g2_element()?;
2130                let arg2 = runtime.args[1].unwrap_bls12_381_g2_element()?;
2131
2132                let budget = self
2133                    .costs
2134                    .builtin_costs
2135                    .get_cost(
2136                        DefaultFunction::Bls12_381_G2_Equal,
2137                        &[
2138                            cost_model::g2_element_ex_mem(),
2139                            cost_model::g2_element_ex_mem(),
2140                        ],
2141                    )
2142                    .ok_or(MachineError::NoCostForBuiltin(
2143                        DefaultFunction::Bls12_381_G2_Equal,
2144                    ))?;
2145
2146                self.spend_budget(budget)?;
2147
2148                let is_equal = unsafe { blst::blst_p2_is_equal(arg1, arg2) };
2149
2150                let value = Value::bool(self.arena, is_equal);
2151
2152                Ok(value)
2153            }
2154            DefaultFunction::Bls12_381_G2_Compress => {
2155                let arg1 = runtime.args[0].unwrap_bls12_381_g2_element()?;
2156
2157                let budget = self
2158                    .costs
2159                    .builtin_costs
2160                    .get_cost(
2161                        DefaultFunction::Bls12_381_G2_Compress,
2162                        &[cost_model::g2_element_ex_mem()],
2163                    )
2164                    .ok_or(MachineError::NoCostForBuiltin(
2165                        DefaultFunction::Bls12_381_G2_Compress,
2166                    ))?;
2167
2168                self.spend_budget(budget)?;
2169
2170                let out = arg1.compress(self.arena);
2171
2172                let value = Value::byte_string(self.arena, out);
2173
2174                Ok(value)
2175            }
2176            DefaultFunction::Bls12_381_G2_Uncompress => {
2177                let arg1 = runtime.args[0].unwrap_byte_string()?;
2178
2179                let budget = self
2180                    .costs
2181                    .builtin_costs
2182                    .get_cost(
2183                        DefaultFunction::Bls12_381_G2_Uncompress,
2184                        &[cost_model::byte_string_ex_mem(arg1)],
2185                    )
2186                    .ok_or(MachineError::NoCostForBuiltin(
2187                        DefaultFunction::Bls12_381_G2_Uncompress,
2188                    ))?;
2189
2190                self.spend_budget(budget)?;
2191
2192                let out = blst::blst_p2::uncompress(self.arena, arg1).map_err(MachineError::bls)?;
2193
2194                let constant = Constant::g2(self.arena, out);
2195
2196                let value = Value::con(self.arena, constant);
2197
2198                Ok(value)
2199            }
2200            DefaultFunction::Bls12_381_G2_HashToGroup => {
2201                let arg1 = runtime.args[0].unwrap_byte_string()?;
2202                let arg2 = runtime.args[1].unwrap_byte_string()?;
2203
2204                let budget = self
2205                    .costs
2206                    .builtin_costs
2207                    .get_cost(
2208                        DefaultFunction::Bls12_381_G2_HashToGroup,
2209                        &[
2210                            cost_model::byte_string_ex_mem(arg1),
2211                            cost_model::byte_string_ex_mem(arg2),
2212                        ],
2213                    )
2214                    .ok_or(MachineError::NoCostForBuiltin(
2215                        DefaultFunction::Bls12_381_G2_HashToGroup,
2216                    ))?;
2217
2218                self.spend_budget(budget)?;
2219
2220                if arg2.len() > 255 {
2221                    return Err(MachineError::hash_to_curve_dst_too_big());
2222                }
2223
2224                let out = self.arena.alloc(blst::blst_p2::default());
2225                let aug = [];
2226
2227                unsafe {
2228                    blst::blst_hash_to_g2(
2229                        out as *mut _,
2230                        arg1.as_ptr(),
2231                        arg1.len(),
2232                        arg2.as_ptr(),
2233                        arg2.len(),
2234                        aug.as_ptr(),
2235                        0,
2236                    );
2237                };
2238
2239                let constant = Constant::g2(self.arena, out);
2240
2241                let value = Value::con(self.arena, constant);
2242
2243                Ok(value)
2244            }
2245            DefaultFunction::Bls12_381_MillerLoop => {
2246                let arg1 = runtime.args[0].unwrap_bls12_381_g1_element()?;
2247                let arg2 = runtime.args[1].unwrap_bls12_381_g2_element()?;
2248
2249                let budget = self
2250                    .costs
2251                    .builtin_costs
2252                    .get_cost(
2253                        DefaultFunction::Bls12_381_MillerLoop,
2254                        &[
2255                            cost_model::g1_element_ex_mem(),
2256                            cost_model::g2_element_ex_mem(),
2257                        ],
2258                    )
2259                    .ok_or(MachineError::NoCostForBuiltin(
2260                        DefaultFunction::Bls12_381_MillerLoop,
2261                    ))?;
2262
2263                self.spend_budget(budget)?;
2264
2265                let out = self.arena.alloc(blst::blst_fp12::default());
2266
2267                let affine1 = self.arena.alloc(blst::blst_p1_affine::default());
2268                let affine2 = self.arena.alloc(blst::blst_p2_affine::default());
2269
2270                unsafe {
2271                    blst::blst_p1_to_affine(affine1 as *mut _, arg1);
2272                    blst::blst_p2_to_affine(affine2 as *mut _, arg2);
2273
2274                    blst::blst_miller_loop(out as *mut _, affine2, affine1);
2275                }
2276
2277                let constant = Constant::ml_result(self.arena, out);
2278
2279                let value = Value::con(self.arena, constant);
2280
2281                Ok(value)
2282            }
2283            DefaultFunction::Bls12_381_MulMlResult => {
2284                let arg1 = runtime.args[0].unwrap_bls12_381_ml_result()?;
2285                let arg2 = runtime.args[1].unwrap_bls12_381_ml_result()?;
2286
2287                let budget = self
2288                    .costs
2289                    .builtin_costs
2290                    .get_cost(
2291                        DefaultFunction::Bls12_381_MulMlResult,
2292                        &[
2293                            cost_model::ml_result_ex_mem(),
2294                            cost_model::ml_result_ex_mem(),
2295                        ],
2296                    )
2297                    .ok_or(MachineError::NoCostForBuiltin(
2298                        DefaultFunction::Bls12_381_MulMlResult,
2299                    ))?;
2300
2301                self.spend_budget(budget)?;
2302
2303                let out = self.arena.alloc(blst::blst_fp12::default());
2304
2305                unsafe {
2306                    blst::blst_fp12_mul(out as *mut _, arg1, arg2);
2307                }
2308
2309                let constant = Constant::ml_result(self.arena, out);
2310
2311                let value = Value::con(self.arena, constant);
2312
2313                Ok(value)
2314            }
2315            DefaultFunction::Bls12_381_FinalVerify => {
2316                let arg1 = runtime.args[0].unwrap_bls12_381_ml_result()?;
2317                let arg2 = runtime.args[1].unwrap_bls12_381_ml_result()?;
2318
2319                let budget = self
2320                    .costs
2321                    .builtin_costs
2322                    .get_cost(
2323                        DefaultFunction::Bls12_381_FinalVerify,
2324                        &[
2325                            cost_model::ml_result_ex_mem(),
2326                            cost_model::ml_result_ex_mem(),
2327                        ],
2328                    )
2329                    .ok_or(MachineError::NoCostForBuiltin(
2330                        DefaultFunction::Bls12_381_FinalVerify,
2331                    ))?;
2332
2333                self.spend_budget(budget)?;
2334
2335                let verified = unsafe { blst::blst_fp12_finalverify(arg1, arg2) };
2336
2337                let value = Value::bool(self.arena, verified);
2338
2339                Ok(value)
2340            }
2341            DefaultFunction::IntegerToByteString => {
2342                let endianness = runtime.args[0].unwrap_bool()?;
2343                let size = runtime.args[1].unwrap_integer()?;
2344                let input = runtime.args[2].unwrap_integer()?;
2345
2346                if size.is_negative() {
2347                    return Err(MachineError::integer_to_byte_string_negative_size(size));
2348                }
2349
2350                if *size > INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() {
2351                    return Err(MachineError::integer_to_byte_string_size_too_big(
2352                        size,
2353                        INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
2354                    ));
2355                }
2356
2357                let arg1: i64 = i64::try_from(size).unwrap();
2358
2359                let arg1_exmem = if arg1 == 0 { 0 } else { ((arg1 - 1) / 8) + 1 };
2360
2361                let budget = self
2362                    .costs
2363                    .builtin_costs
2364                    .get_cost(
2365                        DefaultFunction::IntegerToByteString,
2366                        &[
2367                            cost_model::BOOL_EX_MEM,
2368                            arg1_exmem,
2369                            cost_model::integer_ex_mem(input),
2370                        ],
2371                    )
2372                    .ok_or(MachineError::NoCostForBuiltin(
2373                        DefaultFunction::IntegerToByteString,
2374                    ))?;
2375
2376                self.spend_budget(budget)?;
2377
2378                // NOTE:
2379                // We ought to also check for negative size and too large sizes. These checks
2380                // however happens prior to calling the builtin as part of the costing step. So by
2381                // the time we reach this builtin call, the size can be assumed to be
2382                //
2383                // >= 0 && < INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH
2384
2385                if size.is_zero()
2386                    && cost_model::integer_log2_x(input)
2387                        >= 8 * INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH
2388                {
2389                    let required = cost_model::integer_log2_x(input) / 8 + 1;
2390
2391                    return Err(MachineError::integer_to_byte_string_size_too_big(
2392                        constant::integer_from(self.arena, required as i128),
2393                        INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
2394                    ));
2395                }
2396
2397                if input.is_negative() {
2398                    return Err(MachineError::integer_to_byte_string_negative_input(input));
2399                }
2400
2401                let size_unwrapped: usize = size.try_into().unwrap();
2402
2403                if input.is_zero() {
2404                    let mut new_bytes =
2405                        BumpVec::with_capacity_in(size_unwrapped, self.arena.as_bump());
2406
2407                    unsafe {
2408                        new_bytes.set_len(size_unwrapped);
2409                    }
2410
2411                    new_bytes.fill(0);
2412
2413                    let new_bytes = self.arena.alloc(new_bytes);
2414
2415                    let value = Value::byte_string(self.arena, new_bytes);
2416
2417                    return Ok(value);
2418                }
2419
2420                let mut bytes = if endianness {
2421                    integer_to_bytes(self.arena, input, true)
2422                } else {
2423                    integer_to_bytes(self.arena, input, false)
2424                };
2425
2426                if !size.is_zero() && bytes.len() > size_unwrapped {
2427                    return Err(MachineError::integer_to_byte_string_size_too_small(
2428                        size,
2429                        bytes.len(),
2430                    ));
2431                }
2432
2433                if size_unwrapped > 0 {
2434                    let padding_size = size_unwrapped - bytes.len();
2435
2436                    let mut padding = BumpVec::with_capacity_in(padding_size, self.arena.as_bump());
2437
2438                    unsafe {
2439                        padding.set_len(padding_size);
2440                    }
2441
2442                    padding.fill(0);
2443
2444                    if endianness {
2445                        padding.append(&mut bytes);
2446
2447                        bytes = padding;
2448                    } else {
2449                        bytes.append(&mut padding);
2450                    }
2451                };
2452
2453                let bytes = self.arena.alloc(bytes);
2454
2455                let value = Value::byte_string(self.arena, bytes);
2456
2457                Ok(value)
2458            }
2459            DefaultFunction::ByteStringToInteger => {
2460                let endianness = runtime.args[0].unwrap_bool()?;
2461                let bytes = runtime.args[1].unwrap_byte_string()?;
2462
2463                let budget = self
2464                    .costs
2465                    .builtin_costs
2466                    .get_cost(
2467                        DefaultFunction::ByteStringToInteger,
2468                        &[
2469                            cost_model::BOOL_EX_MEM,
2470                            cost_model::byte_string_ex_mem(bytes),
2471                        ],
2472                    )
2473                    .ok_or(MachineError::NoCostForBuiltin(
2474                        DefaultFunction::ByteStringToInteger,
2475                    ))?;
2476
2477                self.spend_budget(budget)?;
2478
2479                let number = self.arena.alloc_integer(if endianness {
2480                    Integer::from_bytes_be(num_bigint::Sign::Plus, bytes)
2481                } else {
2482                    Integer::from_bytes_le(num_bigint::Sign::Plus, bytes)
2483                });
2484
2485                let value = Value::integer(self.arena, number);
2486
2487                Ok(value)
2488            }
2489            DefaultFunction::AndByteString => {
2490                let should_pad = runtime.args[0].unwrap_bool()?;
2491                let left_bytes = runtime.args[1].unwrap_byte_string()?;
2492                let right_bytes = runtime.args[2].unwrap_byte_string()?;
2493
2494                let budget = self
2495                    .costs
2496                    .builtin_costs
2497                    .get_cost(
2498                        DefaultFunction::AndByteString,
2499                        &[
2500                            cost_model::BOOL_EX_MEM,
2501                            cost_model::byte_string_ex_mem(left_bytes),
2502                            cost_model::byte_string_ex_mem(right_bytes),
2503                        ],
2504                    )
2505                    .ok_or(MachineError::NoCostForBuiltin(
2506                        DefaultFunction::AndByteString,
2507                    ))?;
2508
2509                self.spend_budget(budget)?;
2510
2511                let bytes_result: Vec<u8> = if should_pad {
2512                    let max_len = left_bytes.len().max(right_bytes.len());
2513                    (0..max_len)
2514                        .map(|index| {
2515                            let left_byte = left_bytes.get(index).copied().unwrap_or(0xFF);
2516                            let right_byte = right_bytes.get(index).copied().unwrap_or(0xFF);
2517                            left_byte & right_byte
2518                        })
2519                        .collect()
2520                } else {
2521                    left_bytes
2522                        .iter()
2523                        .zip(right_bytes)
2524                        .map(|(b1, b2)| b1 & b2)
2525                        .collect()
2526                };
2527                let result = self.arena.alloc(bytes_result);
2528                let value = Value::byte_string(self.arena, result);
2529                Ok(value)
2530            }
2531            DefaultFunction::OrByteString => {
2532                let should_pad = runtime.args[0].unwrap_bool()?;
2533                let left_bytes = runtime.args[1].unwrap_byte_string()?;
2534                let right_bytes = runtime.args[2].unwrap_byte_string()?;
2535
2536                let budget = self
2537                    .costs
2538                    .builtin_costs
2539                    .get_cost(
2540                        DefaultFunction::OrByteString,
2541                        &[
2542                            cost_model::BOOL_EX_MEM,
2543                            cost_model::byte_string_ex_mem(left_bytes),
2544                            cost_model::byte_string_ex_mem(right_bytes),
2545                        ],
2546                    )
2547                    .ok_or(MachineError::NoCostForBuiltin(
2548                        DefaultFunction::OrByteString,
2549                    ))?;
2550
2551                self.spend_budget(budget)?;
2552
2553                let bytes_result: Vec<u8> = if should_pad {
2554                    let max_len = left_bytes.len().max(right_bytes.len());
2555                    (0..max_len)
2556                        .map(|index| {
2557                            let left_byte = left_bytes.get(index).copied().unwrap_or(0x00);
2558                            let right_byte = right_bytes.get(index).copied().unwrap_or(0x00);
2559                            left_byte | right_byte
2560                        })
2561                        .collect()
2562                } else {
2563                    left_bytes
2564                        .iter()
2565                        .zip(right_bytes)
2566                        .map(|(b1, b2)| b1 | b2)
2567                        .collect()
2568                };
2569
2570                let result = self.arena.alloc(bytes_result);
2571                let value = Value::byte_string(self.arena, result);
2572
2573                Ok(value)
2574            }
2575            DefaultFunction::XorByteString => {
2576                let should_pad = runtime.args[0].unwrap_bool()?;
2577                let left_bytes = runtime.args[1].unwrap_byte_string()?;
2578                let right_bytes = runtime.args[2].unwrap_byte_string()?;
2579
2580                let budget = self
2581                    .costs
2582                    .builtin_costs
2583                    .get_cost(
2584                        DefaultFunction::XorByteString,
2585                        &[
2586                            cost_model::BOOL_EX_MEM,
2587                            cost_model::byte_string_ex_mem(left_bytes),
2588                            cost_model::byte_string_ex_mem(right_bytes),
2589                        ],
2590                    )
2591                    .ok_or(MachineError::NoCostForBuiltin(
2592                        DefaultFunction::XorByteString,
2593                    ))?;
2594
2595                self.spend_budget(budget)?;
2596
2597                let bytes_result: Vec<u8> = if should_pad {
2598                    let max_len = left_bytes.len().max(right_bytes.len());
2599                    (0..max_len)
2600                        .map(|index| {
2601                            let left_byte = left_bytes.get(index).copied().unwrap_or(0x00);
2602                            let right_byte = right_bytes.get(index).copied().unwrap_or(0x00);
2603                            left_byte ^ right_byte
2604                        })
2605                        .collect()
2606                } else {
2607                    left_bytes
2608                        .iter()
2609                        .zip(right_bytes)
2610                        .map(|(b1, b2)| b1 ^ b2)
2611                        .collect()
2612                };
2613
2614                let result = self.arena.alloc(bytes_result);
2615                let value = Value::byte_string(self.arena, result);
2616
2617                Ok(value)
2618            }
2619            DefaultFunction::ComplementByteString => {
2620                let bytes = runtime.args[0].unwrap_byte_string()?;
2621
2622                let budget = self
2623                    .costs
2624                    .builtin_costs
2625                    .get_cost(
2626                        DefaultFunction::ComplementByteString,
2627                        &[cost_model::byte_string_ex_mem(bytes)],
2628                    )
2629                    .ok_or(MachineError::NoCostForBuiltin(
2630                        DefaultFunction::ComplementByteString,
2631                    ))?;
2632                self.spend_budget(budget)?;
2633
2634                let result = self
2635                    .arena
2636                    .alloc(bytes.iter().map(|b| b ^ 255).collect::<Vec<_>>());
2637
2638                Ok(Value::byte_string(self.arena, result))
2639            }
2640            DefaultFunction::ReadBit => {
2641                let bytes = runtime.args[0].unwrap_byte_string()?;
2642                let bit_index = runtime.args[1].unwrap_integer()?;
2643
2644                let budget = self
2645                    .costs
2646                    .builtin_costs
2647                    .get_cost(
2648                        DefaultFunction::ReadBit,
2649                        &[
2650                            cost_model::byte_string_ex_mem(bytes),
2651                            cost_model::integer_ex_mem(bit_index),
2652                        ],
2653                    )
2654                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ReadBit))?;
2655
2656                self.spend_budget(budget)?;
2657
2658                if bytes.is_empty() {
2659                    return Err(MachineError::empty_byte_array());
2660                }
2661
2662                if bit_index < &Integer::ZERO || bit_index >= &Integer::from(bytes.len() * 8) {
2663                    return Err(MachineError::read_bit_out_of_bounds(
2664                        bit_index,
2665                        bytes.len() * 8,
2666                    ));
2667                }
2668
2669                let (byte_index, bit_offset) = bit_index.div_rem(&8.into());
2670                let bit_offset = usize::try_from(bit_offset).unwrap();
2671
2672                let flipped_index = bytes.len() - 1 - usize::try_from(byte_index).unwrap();
2673                let byte = bytes[flipped_index];
2674
2675                let bit_test = (byte >> bit_offset) & 1 == 1;
2676
2677                Ok(Value::bool(self.arena, bit_test))
2678            }
2679            DefaultFunction::WriteBits => {
2680                let mut bytes = runtime.args[0].unwrap_byte_string()?.to_vec();
2681                let indices = runtime.args[1].unwrap_int_list()?;
2682                let set_bit = runtime.args[2].unwrap_bool()?;
2683
2684                let budget = self
2685                    .costs
2686                    .builtin_costs
2687                    .get_cost(
2688                        DefaultFunction::WriteBits,
2689                        &[
2690                            cost_model::byte_string_ex_mem(bytes.as_slice()),
2691                            cost_model::proto_list_ex_mem(indices),
2692                            cost_model::BOOL_EX_MEM,
2693                        ],
2694                    )
2695                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::WriteBits))?;
2696
2697                self.spend_budget(budget)?;
2698
2699                for index in indices {
2700                    let Constant::Integer(bit_index) = index else {
2701                        unreachable!("bit_index must be an integer")
2702                    };
2703
2704                    if *bit_index < &Integer::ZERO || *bit_index >= &Integer::from(bytes.len() * 8)
2705                    {
2706                        return Err(MachineError::write_bits_out_of_bounds(
2707                            bit_index,
2708                            bytes.len() * 8,
2709                        ));
2710                    }
2711
2712                    let (byte_index, bit_offset) = bit_index.div_rem(&8.into());
2713                    let bit_offset = usize::try_from(bit_offset).unwrap();
2714                    let flipped_index = bytes.len() - 1 - usize::try_from(byte_index).unwrap();
2715                    let bit_mask: u8 = 1 << bit_offset;
2716
2717                    if set_bit {
2718                        bytes[flipped_index] |= bit_mask;
2719                    } else {
2720                        bytes[flipped_index] &= !bit_mask;
2721                    }
2722                }
2723
2724                let result = self.arena.alloc(bytes);
2725                Ok(Value::byte_string(self.arena, result))
2726            }
2727            DefaultFunction::ReplicateByte => {
2728                let size = runtime.args[0].unwrap_integer()?;
2729                let byte = runtime.args[1].unwrap_integer()?;
2730
2731                if size.is_negative() {
2732                    return Err(MachineError::replicate_byte_negative_size(size));
2733                }
2734
2735                if *size > INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() {
2736                    return Err(MachineError::replicate_byte_size_too_big(
2737                        size,
2738                        INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
2739                    ));
2740                }
2741
2742                let arg0: i64 = i64::try_from(size).unwrap();
2743
2744                let arg0_ex_mem = if arg0 == 0 { 0 } else { ((arg0 - 1) / 8) + 1 };
2745
2746                let budget = self
2747                    .costs
2748                    .builtin_costs
2749                    .get_cost(
2750                        DefaultFunction::ReplicateByte,
2751                        &[arg0_ex_mem, cost_model::integer_ex_mem(byte)],
2752                    )
2753                    .ok_or(MachineError::NoCostForBuiltin(
2754                        DefaultFunction::ReplicateByte,
2755                    ))?;
2756
2757                self.spend_budget(budget)?;
2758
2759                if size.is_zero()
2760                    && cost_model::integer_log2_x(byte)
2761                        >= 8 * INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH
2762                {
2763                    let required = cost_model::integer_log2_x(byte) / 8 + 1;
2764
2765                    return Err(MachineError::replicate_byte_size_too_big(
2766                        constant::integer_from(self.arena, required as i128),
2767                        INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH,
2768                    ));
2769                }
2770
2771                if byte.is_negative() {
2772                    return Err(MachineError::replicate_byte_negative_input(byte));
2773                }
2774
2775                let size: usize = size.try_into().unwrap();
2776
2777                let Ok(byte) = u8::try_from(byte) else {
2778                    return Err(MachineError::outside_byte_bounds(byte));
2779                };
2780
2781                let result = if size == 0 {
2782                    self.arena.alloc(vec![])
2783                } else {
2784                    self.arena.alloc([byte].repeat(size))
2785                };
2786
2787                Ok(Value::byte_string(self.arena, result))
2788            }
2789            DefaultFunction::ShiftByteString => {
2790                let bytes = runtime.args[0].unwrap_byte_string()?;
2791                let shift = runtime.args[1].unwrap_integer()?;
2792
2793                let arg1: i64 = i64::try_from(shift)
2794                    .map_err(|_| MachineError::outside_usize_bounds(shift))?
2795                    .saturating_abs();
2796
2797                let budget = self
2798                    .costs
2799                    .builtin_costs
2800                    .get_cost(
2801                        DefaultFunction::ShiftByteString,
2802                        &[cost_model::byte_string_ex_mem(bytes), arg1],
2803                    )
2804                    .ok_or(MachineError::NoCostForBuiltin(
2805                        DefaultFunction::ShiftByteString,
2806                    ))?;
2807                self.spend_budget(budget)?;
2808
2809                let length = bytes.len();
2810                let result = self.arena.alloc(vec![0; length]);
2811
2812                if Integer::from(length) * 8 <= shift.abs() {
2813                    return Ok(Value::byte_string(self.arena, result));
2814                }
2815
2816                let is_shift_left = shift >= &Integer::ZERO;
2817                let byte_shift = usize::try_from(shift.abs() / 8).unwrap();
2818                let bit_shift = usize::try_from(shift.abs() % 8).unwrap();
2819
2820                if is_shift_left {
2821                    if bit_shift == 0 {
2822                        // If we can shift entire bytes, that's much simpler
2823                        let copy_len = length - bit_shift;
2824                        // For example, consider the following byte array [1,0,1,0,1] being shifted 8 bits (1 byte)
2825                        // Result: [0,1,0,1,0]
2826                        result[..copy_len].copy_from_slice(&bytes[byte_shift..]);
2827                    } else {
2828                        // This case is a bit trickier, so let's walk through an example:
2829                        // say we are shifting the following byte string by 12 bits:
2830                        // [AB CD EF 12]
2831                        // We know we want to skip the first byte, and shift results 4 bits
2832                        // In order to shift partial bytes, we need to get the "overflow" from the next byte
2833                        // That is the complement_shift (in this case 4)
2834                        // i=0:
2835                        // src_idx = 0 + 1 = 1
2836                        // result[0] = CD << 4 = D0
2837                        // result[0] |= EF >> 4 = D0 | 0E = DE
2838                        // i=1
2839                        // src_idx = 1 + 1 = 2
2840                        // result[1] = EF << 4 = F0
2841                        // reuslt[1] |= 12 >> 4 = F0 | 01 = F1
2842                        // i=2
2843                        // src_idx = 2 + 1 = 3
2844                        // result[2] = 12 << 4 = 20
2845                        // 3 + 1  < length = false
2846                        // So our result is:
2847                        // [DE F1 20 00]
2848                        let complement_shift = 8 - bit_shift;
2849                        #[allow(clippy::needless_range_loop)]
2850                        for i in 0..(length - byte_shift) {
2851                            let src_idx = i + byte_shift;
2852
2853                            result[i] = bytes[src_idx] << bit_shift;
2854                            if src_idx + 1 < length {
2855                                result[i] |= bytes[src_idx + 1] >> complement_shift;
2856                            }
2857                        }
2858                    }
2859                } else {
2860                    // Right shift has the same logic as left shift with the inverse operations
2861                    if bit_shift == 0 {
2862                        let copy_len = length - byte_shift;
2863                        result[byte_shift..].copy_from_slice(&bytes[..copy_len]);
2864                    } else {
2865                        // See left shift case for explanation, but invert all operations
2866                        let complement_shift = 8 - bit_shift;
2867                        #[allow(clippy::needless_range_loop)]
2868                        for i in 0..(length - byte_shift) {
2869                            let dst_idx = i + byte_shift;
2870                            result[dst_idx] = bytes[i] >> bit_shift;
2871
2872                            if i > 0 {
2873                                result[dst_idx] |= bytes[i - 1] << complement_shift;
2874                            }
2875                        }
2876                    }
2877                }
2878
2879                Ok(Value::byte_string(self.arena, result))
2880            }
2881            DefaultFunction::RotateByteString => {
2882                let bytes = runtime.args[0].unwrap_byte_string()?;
2883                let shift = runtime.args[1].unwrap_integer()?;
2884
2885                let arg1: i64 = i64::try_from(shift)
2886                    .map_err(|_| MachineError::outside_usize_bounds(shift))?
2887                    .saturating_abs();
2888
2889                let budget = self
2890                    .costs
2891                    .builtin_costs
2892                    .get_cost(
2893                        DefaultFunction::RotateByteString,
2894                        &[cost_model::byte_string_ex_mem(bytes), arg1],
2895                    )
2896                    .ok_or(MachineError::NoCostForBuiltin(
2897                        DefaultFunction::RotateByteString,
2898                    ))?;
2899                self.spend_budget(budget)?;
2900
2901                let length = bytes.len();
2902                let result = self.arena.alloc(bytes.to_vec());
2903
2904                if bytes.is_empty() {
2905                    return Ok(Value::byte_string(self.arena, result));
2906                }
2907
2908                let shift = shift.mod_floor(&(length * 8).into());
2909                if shift == Integer::ZERO {
2910                    return Ok(Value::byte_string(self.arena, result));
2911                }
2912                let byte_shift = usize::try_from(&shift / 8).unwrap();
2913                let bit_shift = usize::try_from(shift % 8).unwrap();
2914
2915                if bit_shift == 0 {
2916                    // left rotation is the same as shift left
2917                    // except the overflowed bits are brought to the right
2918                    let copy_len = length - byte_shift;
2919
2920                    result[..copy_len].copy_from_slice(&bytes[byte_shift..(copy_len + byte_shift)]);
2921                    result[copy_len..].copy_from_slice(&bytes[..byte_shift]);
2922                } else {
2923                    let complement_shift = 8 - bit_shift;
2924                    let wraparound_bits = bytes[0] >> complement_shift;
2925                    #[allow(clippy::needless_range_loop)]
2926                    for i in 0..(length - byte_shift) {
2927                        let src_idx = i + byte_shift;
2928
2929                        result[i] = bytes[src_idx] << bit_shift;
2930
2931                        if src_idx + 1 < length {
2932                            result[i] |= bytes[src_idx + 1] >> complement_shift;
2933                        } else if byte_shift > 0 {
2934                            result[i] |= bytes[0] >> complement_shift;
2935                        } else {
2936                            // In the case we're doing less than a full byte shift
2937                            // we still need to wrap the bit
2938                            result[i] |= wraparound_bits;
2939                        }
2940                    }
2941
2942                    for i in 0..byte_shift {
2943                        let dst_idx = length - byte_shift + i;
2944                        result[dst_idx] = bytes[i] << bit_shift;
2945
2946                        if i + 1 < byte_shift {
2947                            result[dst_idx] |= bytes[i + 1] >> complement_shift;
2948                        } else {
2949                            result[dst_idx] |= bytes[byte_shift] >> complement_shift;
2950                        }
2951                    }
2952                }
2953
2954                Ok(Value::byte_string(self.arena, result))
2955            }
2956            DefaultFunction::CountSetBits => {
2957                let bytes = runtime.args[0].unwrap_byte_string()?;
2958
2959                let budget = self
2960                    .costs
2961                    .builtin_costs
2962                    .get_cost(
2963                        DefaultFunction::CountSetBits,
2964                        &[cost_model::byte_string_ex_mem(bytes)],
2965                    )
2966                    .ok_or(MachineError::NoCostForBuiltin(
2967                        DefaultFunction::CountSetBits,
2968                    ))?;
2969                self.spend_budget(budget)?;
2970
2971                let weight: Integer = hamming::weight(bytes).into();
2972                let result = self.arena.alloc_integer(weight);
2973                Ok(Value::integer(self.arena, result))
2974            }
2975            DefaultFunction::FindFirstSetBit => {
2976                let bytes = runtime.args[0].unwrap_byte_string()?;
2977
2978                let budget = self
2979                    .costs
2980                    .builtin_costs
2981                    .get_cost(
2982                        DefaultFunction::FindFirstSetBit,
2983                        &[cost_model::byte_string_ex_mem(bytes)],
2984                    )
2985                    .ok_or(MachineError::NoCostForBuiltin(
2986                        DefaultFunction::FindFirstSetBit,
2987                    ))?;
2988                self.spend_budget(budget)?;
2989
2990                let first_bit = bytes
2991                    .iter()
2992                    .rev()
2993                    .enumerate()
2994                    .find_map(|(byte_index, &byte)| {
2995                        let reversed_byte = byte.reverse_bits();
2996                        if reversed_byte == 0 {
2997                            None
2998                        } else {
2999                            let bit_index = reversed_byte.leading_zeros() as usize;
3000                            Some(isize::try_from(bit_index + byte_index * 8).unwrap())
3001                        }
3002                    });
3003
3004                let first_bit: Integer = first_bit.unwrap_or(-1).into();
3005                let result = self.arena.alloc_integer(first_bit);
3006                Ok(Value::integer(self.arena, result))
3007            }
3008            DefaultFunction::Ripemd_160 => {
3009                use cryptoxide::{digest::Digest, ripemd160::Ripemd160};
3010                let input = runtime.args[0].unwrap_byte_string()?;
3011                let budget = self
3012                    .costs
3013                    .builtin_costs
3014                    .get_cost(
3015                        DefaultFunction::Ripemd_160,
3016                        &[cost_model::byte_string_ex_mem(input)],
3017                    )
3018                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::Ripemd_160))?;
3019                self.spend_budget(budget)?;
3020
3021                let mut hasher = Ripemd160::new();
3022                hasher.input(input);
3023                let result = self.arena.alloc(vec![0; hasher.output_bytes()]);
3024                hasher.result(result);
3025
3026                Ok(Value::byte_string(self.arena, result))
3027            }
3028            DefaultFunction::ExpModInteger => {
3029                let base = runtime.args[0].unwrap_integer()?;
3030                let exponent = runtime.args[1].unwrap_integer()?;
3031                let modulus = runtime.args[2].unwrap_integer()?;
3032
3033                let budget = self
3034                    .costs
3035                    .builtin_costs
3036                    .get_cost(
3037                        DefaultFunction::ExpModInteger,
3038                        &[
3039                            cost_model::integer_ex_mem(base),
3040                            cost_model::integer_ex_mem(exponent),
3041                            cost_model::integer_ex_mem(modulus),
3042                        ],
3043                    )
3044                    .ok_or(MachineError::NoCostForBuiltin(
3045                        DefaultFunction::ExpModInteger,
3046                    ))?;
3047                self.spend_budget(budget)?;
3048
3049                if modulus <= &Integer::ZERO {
3050                    return Err(MachineError::division_by_zero(base, modulus));
3051                }
3052
3053                let result = if exponent.is_negative() {
3054                    match base.modinv(modulus) {
3055                        Some(inv) => inv.modpow(&exponent.abs(), modulus),
3056                        None => return Err(MachineError::ExplicitErrorTerm),
3057                    }
3058                } else {
3059                    base.modpow(exponent, modulus)
3060                };
3061
3062                let value = Value::integer(self.arena, self.arena.alloc_integer(result));
3063                Ok(value)
3064            }
3065            DefaultFunction::DropList => {
3066                let elements_to_drop = runtime.args[0].unwrap_integer()?;
3067                let (list_type, list) = runtime.args[1].unwrap_list()?;
3068
3069                let arg0: i64 = u64::try_from(elements_to_drop.abs())
3070                    .unwrap()
3071                    .try_into()
3072                    .unwrap_or(i64::MAX);
3073
3074                let budget = self
3075                    .costs
3076                    .builtin_costs
3077                    .get_cost(
3078                        DefaultFunction::DropList,
3079                        &[arg0, cost_model::proto_list_ex_mem(list)],
3080                    )
3081                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::DropList))?;
3082
3083                self.spend_budget(budget)?;
3084
3085                if elements_to_drop.is_negative() {
3086                    let constant = Constant::proto_list(self.arena, list_type, list);
3087                    let value = Value::con(self.arena, constant);
3088                    return Ok(value);
3089                }
3090
3091                let elements_to_drop_usize = if *elements_to_drop > (usize::MAX as i128).into() {
3092                    list.len()
3093                } else {
3094                    usize::try_from(elements_to_drop).unwrap_or(0)
3095                };
3096
3097                let remaining_list = if elements_to_drop_usize >= list.len() {
3098                    &[]
3099                } else {
3100                    &list[elements_to_drop_usize..]
3101                };
3102
3103                let constant = Constant::proto_list(self.arena, list_type, remaining_list);
3104                let value = Value::con(self.arena, constant);
3105
3106                Ok(value)
3107            }
3108            DefaultFunction::LengthOfArray => {
3109                let (_, array) = runtime.args[0].unwrap_array()?;
3110
3111                let budget = self
3112                    .costs
3113                    .builtin_costs
3114                    .get_cost(
3115                        DefaultFunction::LengthOfArray,
3116                        &[cost_model::proto_list_ex_mem(array)],
3117                    )
3118                    .ok_or(MachineError::NoCostForBuiltin(
3119                        DefaultFunction::LengthOfArray,
3120                    ))?;
3121
3122                self.spend_budget(budget)?;
3123
3124                let result: Integer = array.len().into();
3125                let new = self.arena.alloc_integer(result);
3126                let value = Value::integer(self.arena, new);
3127
3128                Ok(value)
3129            }
3130            DefaultFunction::ListToArray => {
3131                let (list_type, list) = runtime.args[0].unwrap_list()?;
3132
3133                let budget = self
3134                    .costs
3135                    .builtin_costs
3136                    .get_cost(
3137                        DefaultFunction::ListToArray,
3138                        &[
3139                            cost_model::proto_list_ex_mem(list),
3140                            cost_model::proto_list_ex_mem(list),
3141                        ],
3142                    )
3143                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ListToArray))?;
3144
3145                self.spend_budget(budget)?;
3146
3147                let constant = Constant::proto_array(self.arena, list_type, list);
3148
3149                let value = Value::con(self.arena, constant);
3150
3151                Ok(value)
3152            }
3153            DefaultFunction::IndexArray => {
3154                let (_, array) = runtime.args[0].unwrap_array()?;
3155                let arg1 = runtime.args[1].unwrap_integer()?;
3156
3157                let budget = self
3158                    .costs
3159                    .builtin_costs
3160                    .get_cost(
3161                        DefaultFunction::IndexArray,
3162                        &[
3163                            cost_model::proto_list_ex_mem(array),
3164                            cost_model::integer_ex_mem(arg1),
3165                        ],
3166                    )
3167                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::IndexArray))?;
3168                self.spend_budget(budget)?;
3169
3170                let index: i128 = arg1.try_into().unwrap();
3171
3172                if 0 <= index && (index as usize) < array.len() {
3173                    let element = array[index as usize];
3174                    let value = Value::con(self.arena, element);
3175                    Ok(value)
3176                } else {
3177                    Err(MachineError::index_array_out_of_bounds(arg1, array.len()))
3178                }
3179            }
3180            DefaultFunction::Bls12_381_G1_MultiScalarMul => {
3181                let (_, scalars) = runtime.args[0].unwrap_list()?;
3182                let (_, points) = runtime.args[1].unwrap_list()?;
3183
3184                let budget = self
3185                    .costs
3186                    .builtin_costs
3187                    .get_cost(
3188                        DefaultFunction::Bls12_381_G1_MultiScalarMul,
3189                        &[scalars.len() as i64, points.len() as i64],
3190                    )
3191                    .ok_or(MachineError::NoCostForBuiltin(
3192                        DefaultFunction::Bls12_381_G1_MultiScalarMul,
3193                    ))?;
3194
3195                self.spend_budget(budget)?;
3196
3197                let n = scalars.len().min(points.len());
3198                let size_scalar = size_of::<blst::blst_scalar>();
3199
3200                let mut scalar_bytes = Vec::with_capacity(n * size_scalar);
3201                let mut proj_points = Vec::with_capacity(n);
3202                let mut scalar_buf = blst::blst_scalar::default();
3203
3204                for i in 0..n {
3205                    let Constant::Integer(si) = scalars[i] else {
3206                        return Err(MachineError::type_mismatch(Type::Integer, scalars[i]));
3207                    };
3208
3209                    let Constant::Bls12_381G1Element(pi) = points[i] else {
3210                        return Err(MachineError::type_mismatch(
3211                            Type::Bls12_381G1Element,
3212                            points[i],
3213                        ));
3214                    };
3215
3216                    // Validate range even for infinity points.
3217                    check_multi_scalar_range(si).map_err(MachineError::runtime)?;
3218
3219                    // Skip infinity points: scalar * infinity = identity,
3220                    // and infinity poisons the batch affine conversion.
3221                    if unsafe { blst::blst_p1_is_inf(*pi) } {
3222                        continue;
3223                    }
3224
3225                    prepare_msm_scalar(si, &mut scalar_buf, &mut scalar_bytes);
3226
3227                    proj_points.push(**pi);
3228                }
3229
3230                let result = if proj_points.is_empty() {
3231                    let compressed: [u8; 48] = {
3232                        let mut buf = [0u8; 48];
3233                        buf[0] = 0xc0;
3234                        buf
3235                    };
3236
3237                    *blst::blst_p1::uncompress(self.arena, &compressed)
3238                        .map_err(MachineError::bls)?
3239                } else {
3240                    let affines = blst::p1_affines::from(&proj_points);
3241                    affines.mult(&scalar_bytes, size_scalar * 8)
3242                };
3243
3244                let out = self.arena.alloc(result);
3245
3246                let constant = Constant::g1(self.arena, out);
3247
3248                Ok(Value::con(self.arena, constant))
3249            }
3250            DefaultFunction::Bls12_381_G2_MultiScalarMul => {
3251                let (_, scalars) = runtime.args[0].unwrap_list()?;
3252                let (_, points) = runtime.args[1].unwrap_list()?;
3253
3254                let budget = self
3255                    .costs
3256                    .builtin_costs
3257                    .get_cost(
3258                        DefaultFunction::Bls12_381_G2_MultiScalarMul,
3259                        &[scalars.len() as i64, points.len() as i64],
3260                    )
3261                    .ok_or(MachineError::NoCostForBuiltin(
3262                        DefaultFunction::Bls12_381_G2_MultiScalarMul,
3263                    ))?;
3264
3265                self.spend_budget(budget)?;
3266
3267                let n = scalars.len().min(points.len());
3268                let size_scalar = size_of::<blst::blst_scalar>();
3269
3270                let mut scalar_bytes = Vec::with_capacity(n * size_scalar);
3271                let mut proj_points = Vec::with_capacity(n);
3272                let mut scalar_buf = blst::blst_scalar::default();
3273
3274                for i in 0..n {
3275                    let Constant::Integer(si) = scalars[i] else {
3276                        return Err(MachineError::type_mismatch(Type::Integer, scalars[i]));
3277                    };
3278
3279                    let Constant::Bls12_381G2Element(pi) = points[i] else {
3280                        return Err(MachineError::type_mismatch(
3281                            Type::Bls12_381G2Element,
3282                            points[i],
3283                        ));
3284                    };
3285
3286                    // Validate range even for infinity points.
3287                    check_multi_scalar_range(si).map_err(MachineError::runtime)?;
3288
3289                    // Skip infinity points: scalar * infinity = identity,
3290                    // and infinity poisons the batch affine conversion.
3291                    if unsafe { blst::blst_p2_is_inf(*pi) } {
3292                        continue;
3293                    }
3294
3295                    prepare_msm_scalar(si, &mut scalar_buf, &mut scalar_bytes);
3296
3297                    proj_points.push(**pi);
3298                }
3299
3300                let result = if proj_points.is_empty() {
3301                    let compressed: [u8; 96] = {
3302                        let mut buf = [0u8; 96];
3303                        buf[0] = 0xc0;
3304                        buf
3305                    };
3306
3307                    *blst::blst_p2::uncompress(self.arena, &compressed)
3308                        .map_err(MachineError::bls)?
3309                } else {
3310                    let affines = blst::p2_affines::from(&proj_points);
3311                    affines.mult(&scalar_bytes, size_scalar * 8)
3312                };
3313
3314                let out = self.arena.alloc(result);
3315
3316                let constant = Constant::g2(self.arena, out);
3317
3318                Ok(Value::con(self.arena, constant))
3319            }
3320
3321            DefaultFunction::InsertCoin => {
3322                let ccy = runtime.args[0].unwrap_byte_string()?;
3323                let tok = runtime.args[1].unwrap_byte_string()?;
3324                let qty = runtime.args[2].unwrap_integer()?;
3325                let v = runtime.args[3].unwrap_ledger_value()?;
3326
3327                let budget = self
3328                    .costs
3329                    .builtin_costs
3330                    .get_cost(
3331                        DefaultFunction::InsertCoin,
3332                        &[ledger_value::value_max_depth(v)],
3333                    )
3334                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::InsertCoin))?;
3335
3336                self.spend_budget(budget)?;
3337
3338                // Validate quantity in 128-bit signed range
3339                if !qty.is_zero() {
3340                    ledger_value::check_quantity_range(qty)
3341                        .map_err(|e| MachineError::runtime(e.into()))?;
3342                }
3343
3344                // Validate key lengths (> 32 only allowed when qty=0, which is a no-op)
3345                if ccy.len() > 32 || tok.len() > 32 {
3346                    if qty.is_zero() {
3347                        let constant = Constant::ledger_value(self.arena, v);
3348                        return Ok(Value::con(self.arena, constant));
3349                    }
3350
3351                    let err = if ccy.len() > 32 {
3352                        ValueError::InsertCoinInvalidCurrency
3353                    } else {
3354                        ValueError::InsertCoinInvalidToken
3355                    };
3356
3357                    return Err(MachineError::runtime(err.into()));
3358                }
3359
3360                let result = LedgerValue::insert_coin(self.arena, ccy, tok, qty, v);
3361
3362                let constant = Constant::ledger_value(self.arena, result);
3363
3364                Ok(Value::con(self.arena, constant))
3365            }
3366            DefaultFunction::LookupCoin => {
3367                let ccy = runtime.args[0].unwrap_byte_string()?;
3368                let tok = runtime.args[1].unwrap_byte_string()?;
3369                let v = runtime.args[2].unwrap_ledger_value()?;
3370
3371                let budget = self
3372                    .costs
3373                    .builtin_costs
3374                    .get_cost(
3375                        DefaultFunction::LookupCoin,
3376                        &[
3377                            cost_model::byte_string_ex_mem(ccy),
3378                            cost_model::byte_string_ex_mem(tok),
3379                            ledger_value::value_max_depth(v),
3380                        ],
3381                    )
3382                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::LookupCoin))?;
3383
3384                self.spend_budget(budget)?;
3385
3386                let qty = v.lookup_coin(self.arena, ccy, tok);
3387
3388                Ok(Value::integer(self.arena, qty))
3389            }
3390            DefaultFunction::UnionValue => {
3391                let v1 = runtime.args[0].unwrap_ledger_value()?;
3392                let v2 = runtime.args[1].unwrap_ledger_value()?;
3393
3394                let budget = self
3395                    .costs
3396                    .builtin_costs
3397                    .get_cost(
3398                        DefaultFunction::UnionValue,
3399                        &[v1.size as i64, v2.size as i64],
3400                    )
3401                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::UnionValue))?;
3402
3403                self.spend_budget(budget)?;
3404
3405                let result = LedgerValue::union_value(self.arena, v1, v2)
3406                    .map_err(|e| MachineError::runtime(e.into()))?;
3407
3408                let constant = Constant::ledger_value(self.arena, result);
3409
3410                Ok(Value::con(self.arena, constant))
3411            }
3412            DefaultFunction::ValueContains => {
3413                let v1 = runtime.args[0].unwrap_ledger_value()?;
3414                let v2 = runtime.args[1].unwrap_ledger_value()?;
3415
3416                let budget = self
3417                    .costs
3418                    .builtin_costs
3419                    .get_cost(
3420                        DefaultFunction::ValueContains,
3421                        &[v1.size as i64, v2.size as i64],
3422                    )
3423                    .ok_or(MachineError::NoCostForBuiltin(
3424                        DefaultFunction::ValueContains,
3425                    ))?;
3426
3427                self.spend_budget(budget)?;
3428
3429                let result = LedgerValue::value_contains(v1, v2)
3430                    .map_err(|e| MachineError::runtime(e.into()))?;
3431
3432                Ok(Value::bool(self.arena, result))
3433            }
3434            DefaultFunction::ValueData => {
3435                let v = runtime.args[0].unwrap_ledger_value()?;
3436
3437                let budget = self
3438                    .costs
3439                    .builtin_costs
3440                    .get_cost(DefaultFunction::ValueData, &[v.size as i64])
3441                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ValueData))?;
3442
3443                self.spend_budget(budget)?;
3444
3445                let data = LedgerValue::value_data(self.arena, v)
3446                    .map_err(|e| MachineError::runtime(e.into()))?;
3447
3448                let constant = Constant::data(self.arena, data);
3449
3450                Ok(Value::con(self.arena, constant))
3451            }
3452            DefaultFunction::UnValueData => {
3453                let data = runtime.args[0].unwrap_constant()?.unwrap_data()?;
3454
3455                let budget = self
3456                    .costs
3457                    .builtin_costs
3458                    .get_cost(
3459                        DefaultFunction::UnValueData,
3460                        &[ledger_value::data_node_count(data)],
3461                    )
3462                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::UnValueData))?;
3463
3464                self.spend_budget(budget)?;
3465
3466                let result = LedgerValue::un_value_data(self.arena, data)
3467                    .map_err(|e| MachineError::runtime(e.into()))?;
3468
3469                let constant = Constant::ledger_value(self.arena, result);
3470
3471                Ok(Value::con(self.arena, constant))
3472            }
3473            DefaultFunction::ScaleValue => {
3474                let scalar = runtime.args[0].unwrap_integer()?;
3475                let v = runtime.args[1].unwrap_ledger_value()?;
3476
3477                let budget = self
3478                    .costs
3479                    .builtin_costs
3480                    .get_cost(
3481                        DefaultFunction::ScaleValue,
3482                        &[cost_model::integer_ex_mem(scalar), v.size as i64],
3483                    )
3484                    .ok_or(MachineError::NoCostForBuiltin(DefaultFunction::ScaleValue))?;
3485
3486                self.spend_budget(budget)?;
3487
3488                let result = LedgerValue::scale_value(self.arena, scalar, v)
3489                    .map_err(|e| MachineError::runtime(e.into()))?;
3490
3491                let constant = Constant::ledger_value(self.arena, result);
3492
3493                Ok(Value::con(self.arena, constant))
3494            }
3495        }
3496    }
3497}
3498
3499fn integer_to_bytes<'a>(arena: &'a Arena, num: &'a Integer, big_endian: bool) -> BumpVec<'a, u8> {
3500    let bytes = if big_endian {
3501        num.magnitude().to_bytes_be()
3502    } else {
3503        num.magnitude().to_bytes_le()
3504    };
3505
3506    let mut result = BumpVec::with_capacity_in(bytes.len(), arena.as_bump());
3507    result.extend_from_slice(&bytes);
3508    result
3509}