1use std::collections::HashMap;
2
3use cairo_lang_utils::extract_matches;
4use num_bigint::BigInt;
5use num_integer::Integer;
6use num_traits::{One, ToPrimitive, Zero};
7use starknet_types_core::felt::{Felt as Felt252, NonZeroFelt as NonZeroFelt252};
8
9use super::LibfuncSimulationError;
10use super::value::CoreValue;
11use crate::extensions::array::ArrayConcreteLibfunc;
12use crate::extensions::boolean::BoolConcreteLibfunc;
13use crate::extensions::core::CoreConcreteLibfunc;
14use crate::extensions::ec::EcConcreteLibfunc;
15use crate::extensions::enm::{EnumConcreteLibfunc, EnumInitConcreteLibfunc};
16use crate::extensions::felt252::{
17 Felt252BinaryOpConcreteLibfunc, Felt252BinaryOperationConcrete, Felt252BinaryOperator,
18 Felt252Concrete, Felt252ConstConcreteLibfunc, Felt252OperationWithConstConcreteLibfunc,
19};
20use crate::extensions::felt252_dict::Felt252DictConcreteLibfunc;
21use crate::extensions::function_call::SignatureAndFunctionConcreteLibfunc;
22use crate::extensions::gas::GasConcreteLibfunc;
23use crate::extensions::int::unsigned::{
24 Uint8Concrete, Uint16Concrete, Uint32Concrete, Uint64Concrete,
25};
26use crate::extensions::int::unsigned128::Uint128Concrete;
27use crate::extensions::int::{IntConstConcreteLibfunc, IntOperator};
28use crate::extensions::mem::MemConcreteLibfunc;
29use crate::extensions::structure::StructConcreteLibfunc;
30use crate::ids::FunctionId;
31
32macro_rules! take_inputs {
39 (let $assigned_value:pat = $inputs:ident) => {
40 let $assigned_value = take_inputs($inputs)? else {
41 return Err(LibfuncSimulationError::WrongArgType);
42 };
43 };
44}
45
46pub fn simulate<
52 GetStatementGasInfo: Fn() -> Option<i64>,
53 SimulateFunction: Fn(&FunctionId, Vec<CoreValue>) -> Result<Vec<CoreValue>, LibfuncSimulationError>,
54>(
55 libfunc: &CoreConcreteLibfunc,
56 inputs: Vec<CoreValue>,
57 get_statement_gas_info: GetStatementGasInfo,
58 simulate_function: SimulateFunction,
59) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
60 Ok(match libfunc {
61 CoreConcreteLibfunc::Drop(_) => {
62 let [_] = take_inputs(inputs)?;
63 (vec![], 0)
64 }
65 CoreConcreteLibfunc::Dup(_) => {
66 let [value] = take_inputs(inputs)?;
67 (vec![value.clone(), value], 0)
68 }
69 CoreConcreteLibfunc::Ec(libfunc) => {
70 match libfunc {
71 EcConcreteLibfunc::TryNew(_) => {
72 take_inputs!(let [CoreValue::Felt252(x), CoreValue::Felt252(y)] = inputs);
73 const BETA: Felt252 = Felt252::from_hex_unchecked(
74 "0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89",
75 );
76 if y * y == x * x * x + x + BETA {
79 (vec![CoreValue::EcPoint(x, y)], 0)
80 } else {
81 (vec![], 1)
82 }
83 }
84 EcConcreteLibfunc::UnwrapPoint(_) => {
85 take_inputs!(let [CoreValue::EcPoint(x, y)] = inputs);
86 (vec![CoreValue::Felt252(x), CoreValue::Felt252(y)], 0)
87 }
88 _ => unimplemented!(),
89 }
90 }
91 CoreConcreteLibfunc::FunctionCall(SignatureAndFunctionConcreteLibfunc {
92 function, ..
93 })
94 | CoreConcreteLibfunc::CouponCall(SignatureAndFunctionConcreteLibfunc {
95 function, ..
96 }) => (simulate_function(&function.id, inputs)?, 0),
97 CoreConcreteLibfunc::Gas(GasConcreteLibfunc::WithdrawGas(_)) => {
98 let count = get_statement_gas_info()
99 .ok_or(LibfuncSimulationError::UnresolvedStatementGasInfo)?;
100 take_inputs!(let [CoreValue::RangeCheck, CoreValue::GasBuiltin(gas_counter)] = inputs);
101 if gas_counter >= count {
102 (vec![CoreValue::RangeCheck, CoreValue::GasBuiltin(gas_counter - count)], 0)
104 } else {
105 (vec![CoreValue::RangeCheck, CoreValue::GasBuiltin(gas_counter)], 1)
107 }
108 }
109 CoreConcreteLibfunc::Gas(GasConcreteLibfunc::RedepositGas(_)) => {
110 let count = get_statement_gas_info()
111 .ok_or(LibfuncSimulationError::UnresolvedStatementGasInfo)?;
112 take_inputs!(let [CoreValue::GasBuiltin(gas_counter)] = inputs);
113 (vec![CoreValue::GasBuiltin(gas_counter + count)], 0)
114 }
115 CoreConcreteLibfunc::Gas(GasConcreteLibfunc::GetAvailableGas(_)) => {
116 take_inputs!(let [CoreValue::GasBuiltin(gas_counter)] = inputs);
117 (vec![CoreValue::GasBuiltin(gas_counter), CoreValue::Uint128(gas_counter as u128)], 0)
118 }
119 CoreConcreteLibfunc::Gas(
120 GasConcreteLibfunc::BuiltinWithdrawGas(_) | GasConcreteLibfunc::GetBuiltinCosts(_),
121 ) => {
122 unimplemented!("Simulation of the builtin cost functionality is not implemented yet.")
123 }
124 CoreConcreteLibfunc::BranchAlign(_) => {
125 let [] = take_inputs(inputs)?;
126 get_statement_gas_info().ok_or(LibfuncSimulationError::UnresolvedStatementGasInfo)?;
127 (vec![], 0)
128 }
129 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::New(_)) => {
130 let [] = take_inputs(inputs)?;
131 (vec![CoreValue::Array(vec![])], 0)
132 }
133 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::SpanFromTuple(_)) => {
134 take_inputs!(let [CoreValue::Struct(members)] = inputs);
135 (vec![CoreValue::Array(members)], 0)
136 }
137 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::TupleFromSpan(_)) => todo!(),
138 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::Append(_)) => {
139 take_inputs!(let [CoreValue::Array(mut arr), element] = inputs);
140 arr.push(element);
141 (vec![CoreValue::Array(arr)], 0)
142 }
143 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::PopFront(_)) => {
144 take_inputs!(let [CoreValue::Array(mut arr)] = inputs);
145 if arr.is_empty() {
146 (vec![CoreValue::Array(arr)], 1)
147 } else {
148 let front = arr.remove(0);
149 (vec![CoreValue::Array(arr), front], 0)
150 }
151 }
152 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::PopFrontConsume(_)) => {
153 take_inputs!(let [CoreValue::Array(mut arr)] = inputs);
154 if arr.is_empty() { (vec![CoreValue::Array(arr)], 1) } else { (vec![arr.remove(0)], 0) }
155 }
156 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::Get(_)) => {
157 take_inputs!(
158 let [CoreValue::RangeCheck, CoreValue::Array(arr), CoreValue::Uint32(idx)] = inputs
159 );
160 match arr.get(idx as usize).cloned() {
161 Some(element) => (vec![CoreValue::RangeCheck, element], 0),
162 None => (vec![CoreValue::RangeCheck], 1),
163 }
164 }
165 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::Slice(_)) => {
166 take_inputs!(let [
167 CoreValue::RangeCheck,
168 CoreValue::Array(arr),
169 CoreValue::Uint32(start),
170 CoreValue::Uint32(length),
171 ] = inputs);
172 match arr.get(start as usize..(start + length) as usize) {
173 Some(elements) => {
174 (vec![CoreValue::RangeCheck, CoreValue::Array(elements.to_vec())], 0)
175 }
176 None => (vec![CoreValue::RangeCheck], 1),
177 }
178 }
179 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::Len(_)) => {
180 take_inputs!(let [CoreValue::Array(arr)] = inputs);
181 (vec![CoreValue::Uint32(arr.len() as u32)], 0)
182 }
183 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::SnapshotPopFront(_)) => todo!(),
184 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::SnapshotPopBack(_)) => todo!(),
185 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::SnapshotMultiPopFront(_)) => todo!(),
186 CoreConcreteLibfunc::Array(ArrayConcreteLibfunc::SnapshotMultiPopBack(_)) => todo!(),
187 CoreConcreteLibfunc::Uint8(libfunc) => simulate_u8_libfunc(libfunc, inputs)?,
188 CoreConcreteLibfunc::Uint16(libfunc) => simulate_u16_libfunc(libfunc, inputs)?,
189 CoreConcreteLibfunc::Uint32(libfunc) => simulate_u32_libfunc(libfunc, inputs)?,
190 CoreConcreteLibfunc::Uint64(libfunc) => simulate_u64_libfunc(libfunc, inputs)?,
191 CoreConcreteLibfunc::Uint128(libfunc) => simulate_u128_libfunc(libfunc, inputs)?,
192 CoreConcreteLibfunc::Sint8(_)
193 | CoreConcreteLibfunc::Sint16(_)
194 | CoreConcreteLibfunc::Sint32(_)
195 | CoreConcreteLibfunc::Sint64(_)
196 | CoreConcreteLibfunc::Sint128(_) => {
197 unimplemented!("Simulation of signed integer libfuncs is not implemented yet.")
198 }
199 CoreConcreteLibfunc::Bool(libfunc) => simulate_bool_libfunc(libfunc, inputs)?,
200 CoreConcreteLibfunc::Felt252(libfunc) => simulate_felt252_libfunc(libfunc, inputs)?,
201 CoreConcreteLibfunc::UnwrapNonZero(_) => (inputs, 0),
202 CoreConcreteLibfunc::Mem(
203 MemConcreteLibfunc::Rename(_) | MemConcreteLibfunc::StoreTemp(_),
204 )
205 | CoreConcreteLibfunc::Box(_) => {
206 let [value] = take_inputs(inputs)?;
207 (vec![value], 0)
208 }
209 CoreConcreteLibfunc::Mem(MemConcreteLibfunc::FinalizeLocals(_))
210 | CoreConcreteLibfunc::UnconditionalJump(_)
211 | CoreConcreteLibfunc::ApTracking(_) => {
212 let [] = take_inputs(inputs)?;
213 (vec![], 0)
214 }
215 CoreConcreteLibfunc::Mem(MemConcreteLibfunc::StoreLocal(_)) => {
216 take_inputs!(let [CoreValue::Uninitialized, value] = inputs);
217 (vec![value], 0)
218 }
219 CoreConcreteLibfunc::Mem(MemConcreteLibfunc::AllocLocal(_)) => {
220 let [] = take_inputs(inputs)?;
221 (vec![CoreValue::Uninitialized], 0)
222 }
223 CoreConcreteLibfunc::Enum(EnumConcreteLibfunc::Init(EnumInitConcreteLibfunc {
224 index,
225 ..
226 })) => {
227 let [value] = take_inputs(inputs)?;
228 (vec![CoreValue::Enum { value: Box::new(value), index: *index }], 0)
230 }
231 CoreConcreteLibfunc::Enum(
232 EnumConcreteLibfunc::Match(_) | EnumConcreteLibfunc::SnapshotMatch(_),
233 ) => {
234 take_inputs!(let [CoreValue::Enum { value, index }] = inputs);
235 (vec![*value], index)
236 }
237 CoreConcreteLibfunc::Enum(EnumConcreteLibfunc::FromBoundedInt(_)) => todo!(),
238 CoreConcreteLibfunc::Struct(StructConcreteLibfunc::Construct(_)) => {
239 (vec![CoreValue::Struct(inputs)], 0)
240 }
241 CoreConcreteLibfunc::Struct(
242 StructConcreteLibfunc::Deconstruct(_) | StructConcreteLibfunc::SnapshotDeconstruct(_),
243 ) => {
244 take_inputs!(let [CoreValue::Struct(members)] = inputs);
245 (members, 0)
246 }
247 CoreConcreteLibfunc::Felt252Dict(Felt252DictConcreteLibfunc::New(_)) => {
248 let [] = take_inputs(inputs)?;
249 (vec![CoreValue::Dict(HashMap::new())], 0)
250 }
251 CoreConcreteLibfunc::Felt252Dict(Felt252DictConcreteLibfunc::Squash(_)) => {
252 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Dict(dict)] = inputs);
253 (vec![CoreValue::RangeCheck, CoreValue::Dict(dict)], 0)
255 }
256 CoreConcreteLibfunc::Pedersen(_) => {
257 unimplemented!("Simulation of the Pedersen hash function is not implemented yet.");
258 }
259 CoreConcreteLibfunc::Poseidon(_) => {
260 unimplemented!("Simulation of the Poseidon hash function is not implemented yet.");
261 }
262 CoreConcreteLibfunc::StarkNet(_) => {
263 unimplemented!("Simulation of the StarkNet functionalities is not implemented yet.")
264 }
265 CoreConcreteLibfunc::Nullable(_) => {
266 unimplemented!("Simulation of nullable is not implemented yet.")
267 }
268 CoreConcreteLibfunc::Debug(_) => {
269 take_inputs!(let [CoreValue::Array(arr)] = inputs);
270 let mut bytes = Vec::new();
271 for limb in arr {
272 let limb = extract_matches!(limb, CoreValue::Felt252);
273 bytes.extend(limb.to_bytes_be());
274 }
275 if let Ok(s) = String::from_utf8(bytes) {
276 print!("{s}");
277 } else {
278 println!("Not utf8");
279 }
280 (vec![], 0)
281 }
282 CoreConcreteLibfunc::SnapshotTake(_) => {
283 let [value] = take_inputs(inputs)?;
284 (vec![value.clone(), value], 0)
285 }
286 CoreConcreteLibfunc::Cast(_) => unimplemented!(),
287 CoreConcreteLibfunc::Felt252DictEntry(_) => unimplemented!(),
288 CoreConcreteLibfunc::Uint256(_) => unimplemented!(),
289 CoreConcreteLibfunc::Uint512(_) => unimplemented!(),
290 CoreConcreteLibfunc::Bytes31(_) => unimplemented!(),
291 CoreConcreteLibfunc::Const(_) => unimplemented!(),
292 CoreConcreteLibfunc::Coupon(_) => unimplemented!(),
293 CoreConcreteLibfunc::BoundedInt(_) => unimplemented!(),
294 CoreConcreteLibfunc::Circuit(_) => unimplemented!(),
295 CoreConcreteLibfunc::IntRange(_) => unimplemented!(),
296 })
297}
298
299fn simulate_bool_libfunc(
301 libfunc: &BoolConcreteLibfunc,
302 inputs: Vec<CoreValue>,
303) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
304 Ok(match libfunc {
305 BoolConcreteLibfunc::And(_) => {
306 take_inputs!(let [
307 CoreValue::Enum { index: a_index, .. },
308 CoreValue::Enum { index: b_index, .. },
309 ] = inputs);
310 (
311 vec![CoreValue::Enum {
312 value: Box::new(CoreValue::Struct(vec![])),
313 index: usize::from(a_index == 1 && b_index == 1),
314 }],
315 0,
316 )
317 }
318 BoolConcreteLibfunc::Not(_) => {
319 take_inputs!(let [CoreValue::Enum { index, .. }] = inputs);
320 (
321 vec![CoreValue::Enum {
322 value: Box::new(CoreValue::Struct(vec![])),
323 index: 1_usize - index,
324 }],
325 0,
326 )
327 }
328 BoolConcreteLibfunc::Xor(_) => {
329 take_inputs!(let [
330 CoreValue::Enum { index: a_index, .. },
331 CoreValue::Enum { index: b_index, .. },
332 ] = inputs);
333 (
334 vec![CoreValue::Enum {
335 value: Box::new(CoreValue::Struct(vec![])),
336 index: usize::from(a_index != b_index),
337 }],
338 0,
339 )
340 }
341 BoolConcreteLibfunc::Or(_) => {
342 take_inputs!(let [
343 CoreValue::Enum { index: a_index, .. },
344 CoreValue::Enum { index: b_index, .. },
345 ] = inputs);
346 (
347 vec![CoreValue::Enum {
348 value: Box::new(CoreValue::Struct(vec![])),
349 index: usize::from(a_index + b_index > 0),
350 }],
351 0,
352 )
353 }
354 BoolConcreteLibfunc::ToFelt252(_) => {
355 take_inputs!(let [CoreValue::Enum { index, .. }] = inputs);
356 (vec![CoreValue::Felt252(Felt252::from(index))], 0)
357 }
358 })
359}
360
361fn simulate_u128_libfunc(
363 libfunc: &Uint128Concrete,
364 inputs: Vec<CoreValue>,
365) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
366 Ok(match libfunc {
367 Uint128Concrete::Const(IntConstConcreteLibfunc { c, .. }) => {
368 let [] = take_inputs(inputs)?;
369 (vec![CoreValue::Uint128(*c)], 0)
370 }
371 Uint128Concrete::FromFelt252(_) => {
372 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Felt252(value)] = inputs);
373 match value.to_u128() {
374 Some(value) => (vec![CoreValue::RangeCheck, CoreValue::Uint128(value)], 0),
375 None => (vec![CoreValue::RangeCheck], 1),
376 }
377 }
378 Uint128Concrete::ToFelt252(_) => {
379 take_inputs!(let [CoreValue::Uint128(value)] = inputs);
380 (vec![CoreValue::Felt252(Felt252::from(value))], 0)
381 }
382 Uint128Concrete::Operation(libfunc) => {
383 take_inputs!(let [
384 CoreValue::RangeCheck, CoreValue::Uint128(lhs), CoreValue::Uint128(rhs)
385 ] = inputs);
386 let (value, overflow) = match libfunc.operator {
387 IntOperator::OverflowingAdd => lhs.overflowing_add(rhs),
388 IntOperator::OverflowingSub => lhs.overflowing_sub(rhs),
389 };
390 (vec![CoreValue::RangeCheck, CoreValue::Uint128(value)], usize::from(overflow))
391 }
392 Uint128Concrete::Divmod(_) => {
393 take_inputs!(let [
394 CoreValue::RangeCheck, CoreValue::Uint128(lhs), CoreValue::Uint128(rhs)
395 ] = inputs);
396 (
397 vec![
398 CoreValue::RangeCheck,
399 CoreValue::Uint128(lhs / rhs),
400 CoreValue::Uint128(lhs % rhs),
401 ],
402 0,
403 )
404 }
405 Uint128Concrete::GuaranteeMul(_) => {
406 take_inputs!(let [CoreValue::Uint128(lhs), CoreValue::Uint128(rhs)] = inputs);
407 let (limb1, limb0) = (BigInt::from(lhs) * rhs).div_rem(&BigInt::one().pow(128));
408 (
409 vec![
410 CoreValue::Uint128(limb0.to_u128().unwrap()),
411 CoreValue::Uint128(limb1.to_u128().unwrap()),
412 CoreValue::U128MulGuarantee,
413 ],
414 0,
415 )
416 }
417 Uint128Concrete::MulGuaranteeVerify(_) => {
418 take_inputs!(let [CoreValue::RangeCheck, CoreValue::U128MulGuarantee] = inputs);
419 (vec![CoreValue::RangeCheck], 0)
420 }
421 Uint128Concrete::IsZero(_) => {
422 take_inputs!(let [CoreValue::Uint128(value)] = inputs);
423 if value.is_zero() { (vec![], 0) } else { (vec![CoreValue::Uint128(value)], 1) }
424 }
425 Uint128Concrete::SquareRoot(_) => {
426 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint128(value)] = inputs);
427 let root = BigInt::from(value).sqrt();
428 (vec![CoreValue::RangeCheck, CoreValue::Uint64(root.to_u64().unwrap())], 0)
429 }
430 Uint128Concrete::Equal(_) => {
431 take_inputs!(let [CoreValue::Uint128(lhs), CoreValue::Uint128(rhs)] = inputs);
432 (vec![], usize::from(lhs == rhs))
435 }
436 Uint128Concrete::ByteReverse(_) => todo!("ByteReverse"),
437 Uint128Concrete::Bitwise(_) => {
438 take_inputs!(let [
439 CoreValue::Bitwise, CoreValue::Uint128(lhs), CoreValue::Uint128(rhs)
440 ] = inputs);
441 (
442 vec![
443 CoreValue::Bitwise,
444 CoreValue::Uint128(lhs & rhs),
445 CoreValue::Uint128(lhs | rhs),
446 CoreValue::Uint128(lhs ^ rhs),
447 ],
448 0,
449 )
450 }
451 })
452}
453
454fn simulate_u8_libfunc(
456 libfunc: &Uint8Concrete,
457 inputs: Vec<CoreValue>,
458) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
459 Ok(match libfunc {
460 Uint8Concrete::Const(IntConstConcreteLibfunc { c, .. }) => {
461 let [] = take_inputs(inputs)?;
462 (vec![CoreValue::Uint8(*c)], 0)
463 }
464 Uint8Concrete::Operation(libfunc) => {
465 take_inputs!(
466 let [CoreValue::RangeCheck, CoreValue::Uint8(lhs), CoreValue::Uint8(rhs)] = inputs
467 );
468 let (value, overflow) = match libfunc.operator {
469 IntOperator::OverflowingAdd => lhs.overflowing_add(rhs),
470 IntOperator::OverflowingSub => lhs.overflowing_sub(rhs),
471 };
472 (vec![CoreValue::RangeCheck, CoreValue::Uint8(value)], usize::from(overflow))
473 }
474 Uint8Concrete::SquareRoot(_) => {
475 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint8(value)] = inputs);
476 let root = BigInt::from(value).sqrt();
477 (vec![CoreValue::RangeCheck, CoreValue::Uint8(root.to_u8().unwrap())], 0)
478 }
479 Uint8Concrete::Equal(_) => {
480 take_inputs!(let [CoreValue::Uint8(lhs), CoreValue::Uint8(rhs)] = inputs);
481 (vec![], usize::from(lhs == rhs))
484 }
485 Uint8Concrete::ToFelt252(_) => {
486 take_inputs!(let [CoreValue::Uint8(value)] = inputs);
487 (vec![CoreValue::Felt252(Felt252::from(value))], 0)
488 }
489 Uint8Concrete::FromFelt252(_) => {
490 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint8(value)] = inputs);
491 match value.to_u8() {
492 Some(value) => (vec![CoreValue::RangeCheck, CoreValue::Uint8(value)], 0),
493 None => (vec![CoreValue::RangeCheck], 1),
494 }
495 }
496 Uint8Concrete::IsZero(_) => unimplemented!(),
497 Uint8Concrete::Divmod(_) => unimplemented!(),
498 Uint8Concrete::Bitwise(_) => unimplemented!(),
499 Uint8Concrete::WideMul(_) => {
500 take_inputs!(let [CoreValue::Uint8(lhs), CoreValue::Uint8(rhs)] = inputs);
501 (vec![CoreValue::Uint16(u16::from(lhs) * u16::from(rhs))], 0)
502 }
503 })
504}
505
506fn simulate_u16_libfunc(
508 libfunc: &Uint16Concrete,
509 inputs: Vec<CoreValue>,
510) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
511 Ok(match libfunc {
512 Uint16Concrete::Const(IntConstConcreteLibfunc { c, .. }) => {
513 let [] = take_inputs(inputs)?;
514 (vec![CoreValue::Uint16(*c)], 0)
515 }
516 Uint16Concrete::Operation(libfunc) => {
517 take_inputs!(let [
518 CoreValue::RangeCheck, CoreValue::Uint16(lhs), CoreValue::Uint16(rhs)
519 ] = inputs);
520 let (value, overflow) = match libfunc.operator {
521 IntOperator::OverflowingAdd => lhs.overflowing_add(rhs),
522 IntOperator::OverflowingSub => lhs.overflowing_sub(rhs),
523 };
524 (vec![CoreValue::RangeCheck, CoreValue::Uint16(value)], usize::from(overflow))
525 }
526 Uint16Concrete::SquareRoot(_) => {
527 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint16(value)] = inputs);
528 let root = BigInt::from(value).sqrt();
529 (vec![CoreValue::RangeCheck, CoreValue::Uint8(root.to_u8().unwrap())], 0)
530 }
531 Uint16Concrete::Equal(_) => {
532 take_inputs!(let [CoreValue::Uint16(lhs), CoreValue::Uint16(rhs)] = inputs);
533 (vec![], usize::from(lhs == rhs))
536 }
537 Uint16Concrete::ToFelt252(_) => {
538 take_inputs!(let [CoreValue::Uint16(value)] = inputs);
539 (vec![CoreValue::Felt252(Felt252::from(value))], 0)
540 }
541 Uint16Concrete::FromFelt252(_) => {
542 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint16(value)] = inputs);
543 match value.to_u16() {
544 Some(value) => (vec![CoreValue::RangeCheck, CoreValue::Uint16(value)], 0),
545 None => (vec![CoreValue::RangeCheck], 1),
546 }
547 }
548 Uint16Concrete::IsZero(_) => unimplemented!(),
549 Uint16Concrete::Divmod(_) => unimplemented!(),
550 Uint16Concrete::Bitwise(_) => unimplemented!(),
551 Uint16Concrete::WideMul(_) => {
552 take_inputs!(let [CoreValue::Uint16(lhs), CoreValue::Uint16(rhs)] = inputs);
553 (vec![CoreValue::Uint32(u32::from(lhs) * u32::from(rhs))], 0)
554 }
555 })
556}
557
558fn simulate_u32_libfunc(
560 libfunc: &Uint32Concrete,
561 inputs: Vec<CoreValue>,
562) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
563 Ok(match libfunc {
564 Uint32Concrete::Const(IntConstConcreteLibfunc { c, .. }) => {
565 let [] = take_inputs(inputs)?;
566 (vec![CoreValue::Uint32(*c)], 0)
567 }
568 Uint32Concrete::Operation(libfunc) => {
569 take_inputs!(let [
570 CoreValue::RangeCheck, CoreValue::Uint32(lhs), CoreValue::Uint32(rhs)
571 ] = inputs);
572 let (value, overflow) = match libfunc.operator {
573 IntOperator::OverflowingAdd => lhs.overflowing_add(rhs),
574 IntOperator::OverflowingSub => lhs.overflowing_sub(rhs),
575 };
576 (vec![CoreValue::RangeCheck, CoreValue::Uint32(value)], usize::from(overflow))
577 }
578 Uint32Concrete::SquareRoot(_) => {
579 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint32(value)] = inputs);
580 let root = BigInt::from(value).sqrt();
581 (vec![CoreValue::RangeCheck, CoreValue::Uint16(root.to_u16().unwrap())], 0)
582 }
583 Uint32Concrete::Equal(_) => {
584 take_inputs!(let [CoreValue::Uint32(lhs), CoreValue::Uint32(rhs)] = inputs);
585 (vec![], usize::from(lhs == rhs))
588 }
589 Uint32Concrete::ToFelt252(_) => {
590 take_inputs!(let [CoreValue::Uint32(value)] = inputs);
591 (vec![CoreValue::Felt252(Felt252::from(value))], 0)
592 }
593 Uint32Concrete::FromFelt252(_) => {
594 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Felt252(value)] = inputs);
595 match value.to_u32() {
596 Some(value) => (vec![CoreValue::RangeCheck, CoreValue::Uint32(value)], 0),
597 None => (vec![CoreValue::RangeCheck], 1),
598 }
599 }
600 Uint32Concrete::IsZero(_) => unimplemented!(),
601 Uint32Concrete::Divmod(_) => unimplemented!(),
602 Uint32Concrete::Bitwise(_) => unimplemented!(),
603 Uint32Concrete::WideMul(_) => {
604 take_inputs!(let [CoreValue::Uint32(lhs), CoreValue::Uint32(rhs)] = inputs);
605 (vec![CoreValue::Uint64(u64::from(lhs) * u64::from(rhs))], 0)
606 }
607 })
608}
609
610fn simulate_u64_libfunc(
612 libfunc: &Uint64Concrete,
613 inputs: Vec<CoreValue>,
614) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
615 Ok(match libfunc {
616 Uint64Concrete::Const(IntConstConcreteLibfunc { c, .. }) => {
617 let [] = take_inputs(inputs)?;
618 (vec![CoreValue::Uint64(*c)], 0)
619 }
620 Uint64Concrete::Operation(libfunc) => {
621 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint64(lhs), CoreValue::Uint64(rhs)] = inputs);
622 let (value, overflow) = match libfunc.operator {
623 IntOperator::OverflowingAdd => lhs.overflowing_add(rhs),
624 IntOperator::OverflowingSub => lhs.overflowing_sub(rhs),
625 };
626 (vec![CoreValue::RangeCheck, CoreValue::Uint64(value)], usize::from(overflow))
627 }
628 Uint64Concrete::SquareRoot(_) => {
629 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint64(value)] = inputs);
630 let root = BigInt::from(value).sqrt();
631 (vec![CoreValue::RangeCheck, CoreValue::Uint32(root.to_u32().unwrap())], 0)
632 }
633 Uint64Concrete::Equal(_) => {
634 take_inputs!(let [CoreValue::Uint64(lhs), CoreValue::Uint64(rhs)] = inputs);
635 (vec![], usize::from(lhs == rhs))
638 }
639 Uint64Concrete::ToFelt252(_) => {
640 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Uint64(value)] = inputs);
641 (vec![CoreValue::Felt252(Felt252::from(value))], 0)
642 }
643 Uint64Concrete::FromFelt252(_) => {
644 take_inputs!(let [CoreValue::RangeCheck, CoreValue::Felt252(value)] = inputs);
645 match value.to_u64() {
646 Some(value) => (vec![CoreValue::RangeCheck, CoreValue::Uint64(value)], 0),
647 None => (vec![CoreValue::RangeCheck], 1),
648 }
649 }
650 Uint64Concrete::IsZero(_) => unimplemented!(),
651 Uint64Concrete::Divmod(_) => unimplemented!(),
652 Uint64Concrete::Bitwise(_) => unimplemented!(),
653 Uint64Concrete::WideMul(_) => {
654 take_inputs!(let [CoreValue::Uint64(lhs), CoreValue::Uint64(rhs)] = inputs);
655 (vec![CoreValue::Uint128(u128::from(lhs) * u128::from(rhs))], 0)
656 }
657 })
658}
659
660fn simulate_felt252_libfunc(
662 libfunc: &Felt252Concrete,
663 inputs: Vec<CoreValue>,
664) -> Result<(Vec<CoreValue>, usize), LibfuncSimulationError> {
665 Ok(match libfunc {
666 Felt252Concrete::Const(Felt252ConstConcreteLibfunc { c, .. }) => {
667 let [] = take_inputs(inputs)?;
668 (vec![CoreValue::Felt252(c.into())], 0)
669 }
670 Felt252Concrete::BinaryOperation(Felt252BinaryOperationConcrete::WithVar(
671 Felt252BinaryOpConcreteLibfunc { operator, .. },
672 )) => {
673 take_inputs!(let [CoreValue::Felt252(lhs), CoreValue::Felt252(rhs)] = inputs);
674 (
675 vec![CoreValue::Felt252(match operator {
676 Felt252BinaryOperator::Add => lhs + rhs,
677 Felt252BinaryOperator::Sub => lhs - rhs,
678 Felt252BinaryOperator::Mul => lhs * rhs,
679 Felt252BinaryOperator::Div => {
680 lhs.field_div(&NonZeroFelt252::from_felt_unchecked(rhs))
681 }
682 })],
683 0,
684 )
685 }
686 Felt252Concrete::BinaryOperation(Felt252BinaryOperationConcrete::WithConst(
687 Felt252OperationWithConstConcreteLibfunc { operator, c, .. },
688 )) => {
689 take_inputs!(let [CoreValue::Felt252(value)] = inputs);
690 (
691 vec![CoreValue::Felt252(match operator {
692 Felt252BinaryOperator::Add => value + Felt252::from(c),
693 Felt252BinaryOperator::Sub => value - Felt252::from(c),
694 Felt252BinaryOperator::Mul => value * Felt252::from(c),
695 Felt252BinaryOperator::Div => {
696 value.field_div(&NonZeroFelt252::from_felt_unchecked(Felt252::from(c)))
697 }
698 })],
699 0,
700 )
701 }
702 Felt252Concrete::IsZero(_) => {
703 take_inputs!(let [CoreValue::Felt252(value)] = inputs);
704 if value.is_zero() {
705 (vec![], 0)
707 } else {
708 (vec![CoreValue::Felt252(value)], 1)
711 }
712 }
713 })
714}
715
716fn take_inputs<const COUNT: usize>(
719 inputs: Vec<CoreValue>,
720) -> Result<[CoreValue; COUNT], LibfuncSimulationError> {
721 TryFrom::try_from(inputs).map_err(|_| LibfuncSimulationError::WrongNumberOfArgs)
722}