use air_codegen_masm::constants;
use miden_assembly::Assembler;
use miden_processor::{
math::{Felt, FieldElement},
AdviceInputs, Kernel, MemAdviceProvider, Process, QuadExtension, StackInputs,
};
mod utils;
use utils::{codegen, test_code, to_stack_order, Data};
static SIMPLE_BOUNDARY_AIR: &str = "
def SimpleBoundary
trace_columns:
main: [a, b, len]
public_inputs:
target: [1]
boundary_constraints:
enf a.first = 1
enf b.first = 1
enf len.first = 0
enf len.last = target[0]
integrity_constraints:
enf a' = a + b
enf b' = a
";
#[test]
fn test_simple_boundary() {
let code = codegen(SIMPLE_BOUNDARY_AIR);
let trace_len = 32u64;
let one = QuadExtension::ONE;
let z = one.clone();
let a = QuadExtension::new(Felt::new(514229), Felt::ZERO);
let b = QuadExtension::new(Felt::new(317811), Felt::ZERO);
let len = QuadExtension::new(Felt::new(27), Felt::ZERO);
let a_prime = QuadExtension::new(Felt::new(514229 + 317811), Felt::ZERO);
let b_prime = a.clone();
let code = test_code(
code,
vec![
Data {
data: to_stack_order(&[a, a_prime, b, b_prime, len.clone(), len.clone()]),
address: constants::OOD_FRAME_ADDRESS,
descriptor: "main_trace",
},
Data {
data: to_stack_order(&[one; 6]),
address: constants::COMPOSITION_COEF_ADDRESS,
descriptor: "composition_coefficients",
},
Data {
data: to_stack_order(&[len]),
address: constants::PUBLIC_INPUTS_ADDRESS,
descriptor: "public_inputs",
},
],
trace_len,
z,
&[
"compute_boundary_constraints_main_first",
"compute_boundary_constraints_main_last",
],
);
let program = Assembler::default().compile(code).unwrap();
let mut process: Process<MemAdviceProvider> = Process::new(
Kernel::new(&[]),
StackInputs::new(vec![]),
AdviceInputs::default().into(),
);
let program_outputs = process.execute(&program).expect("execution failed");
let result_stack = program_outputs.stack();
#[rustfmt::skip]
let expected = to_stack_order(&[
QuadExtension::ZERO, len, b - QuadExtension::ONE, a - QuadExtension::ONE, ]);
assert!(
result_stack
.iter()
.zip(expected.iter())
.all(|(l, r)| l == r),
"results don't match result={:?} expected={:?}",
result_stack,
expected,
);
}
static COMPLEX_BOUNDARY_AIR: &str = "
def ComplexBoundary
const A = 1
const B = [0, 1]
const C = [[1, 2], [2, 0]]
trace_columns:
main: [a, b, c, d, e[2]]
aux: [f]
public_inputs:
stack_inputs: [2]
stack_outputs: [2]
random_values:
rand: [2]
boundary_constraints:
enf a.first = stack_inputs[0]
enf b.first = stack_inputs[1]
enf a.last = stack_outputs[0]
enf b.last = stack_outputs[1]
enf c.first = (B[0] - C[1][1]) * A
enf d.first = 1
enf e[0].first = 0
enf e[1].first = 1
enf f.first = $rand[0]
enf f.last = 1
integrity_constraints:
enf a + b = 0
";
#[test]
fn test_complex_boundary() {
let code = codegen(COMPLEX_BOUNDARY_AIR);
let trace_len = 32u64;
let one = QuadExtension::new(Felt::new(1), Felt::ZERO);
let z = one.clone();
let public_inputs = [
QuadExtension::new(Felt::new(2), Felt::ZERO),
QuadExtension::new(Felt::new(3), Felt::ZERO),
QuadExtension::new(Felt::new(5), Felt::ZERO),
QuadExtension::new(Felt::new(7), Felt::ZERO),
];
let a = QuadExtension::new(Felt::new(11), Felt::ZERO);
let b = QuadExtension::new(Felt::new(13), Felt::ZERO);
let c = QuadExtension::new(Felt::new(17), Felt::ZERO);
let d = QuadExtension::new(Felt::new(19), Felt::ZERO);
let e = [
QuadExtension::new(Felt::new(23), Felt::ZERO),
QuadExtension::new(Felt::new(29), Felt::ZERO),
];
let f = QuadExtension::new(Felt::new(31), Felt::ZERO);
let rand = [
QuadExtension::new(Felt::new(37), Felt::ZERO),
QuadExtension::new(Felt::new(41), Felt::ZERO),
];
let a_prime = a + one;
let b_prime = b + one;
let c_prime = c + one;
let d_prime = d + one;
let e_prime = [e[0] + one, e[1] + one];
let f_prime = f + one;
let code = test_code(
code,
vec![
Data {
data: to_stack_order(&[
a, a_prime, b, b_prime, c, c_prime, d, d_prime, e[0], e_prime[0], e[1],
e_prime[1],
]),
address: constants::OOD_FRAME_ADDRESS,
descriptor: "main_trace",
},
Data {
data: to_stack_order(&[f, f_prime]),
address: constants::OOD_AUX_FRAME_ADDRESS,
descriptor: "aux_trace",
},
Data {
data: to_stack_order(&public_inputs),
address: constants::PUBLIC_INPUTS_ADDRESS,
descriptor: "public_inputs",
},
Data {
data: to_stack_order(&[one; 11]),
address: constants::COMPOSITION_COEF_ADDRESS,
descriptor: "composition_coefficients",
},
Data {
data: to_stack_order(&rand),
address: constants::AUX_RAND_ELEM_PTR,
descriptor: "aux_random_elements",
},
],
trace_len,
z,
&[
"compute_boundary_constraints_main_first",
"compute_boundary_constraints_main_last",
"compute_boundary_constraints_aux_first",
"compute_boundary_constraints_aux_last",
],
);
let program = Assembler::default().compile(code).unwrap();
let mut process: Process<MemAdviceProvider> = Process::new(
Kernel::new(&[]),
StackInputs::new(vec![]),
AdviceInputs::default().into(),
);
let program_outputs = process.execute(&program).expect("execution failed");
let result_stack = program_outputs.stack();
#[rustfmt::skip]
let expected = to_stack_order(&[
f - one,
f - rand[0],
b - public_inputs[3], a - public_inputs[2],
e[1] - one, e[0],
d - one, c,
b - public_inputs[1], a - public_inputs[0], ]);
assert!(
result_stack
.iter()
.zip(expected.iter())
.all(|(l, r)| l == r),
"results don't match result={:?} expected={:?}",
result_stack,
expected,
);
}