use super::*;
#[rstest]
#[case(Some("export.foo add end"), "begin push.1 syscall.foo swap.8 drop end", vec![16_u32.into(); 16])]
#[case(Some("export.foo caller end"), "begin syscall.foo end", vec![16_u32.into(); 16])]
#[case(Some("export.foo caller end"), "proc.bar syscall.foo end begin call.bar end", vec![16_u32.into(); 16])]
#[case(Some("export.foo clk add end"), "begin syscall.foo end", vec![16_u32.into(); 16])]
#[case(Some("export.foo.2 locaddr.0 locaddr.1 swap.8 drop swap.8 drop end"), "proc.bar syscall.foo end begin call.bar end", vec![16_u32.into(); 16])]
#[case(Some("export.foo add end"), "proc.bar push.100 mem_store.44 syscall.foo mem_load.44 swap.8 drop end begin call.bar end", vec![16_u32.into(); 16])]
#[case(Some("export.foo push.100 mem_store.44 end export.baz mem_load.44 swap.8 drop end"),
"proc.bar
syscall.foo syscall.baz
end
begin call.bar end",
vec![16_u32.into(); 16]
)]
#[case(None, "proc.foo add end begin push.1 call.foo swap.8 drop end", vec![16_u32.into(); 16])]
#[case(None, "
proc.foo clk add end
begin push.1
if.true call.foo else swap end
clk swap.8 drop
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo.2 locaddr.0 locaddr.1 swap.8 drop swap.8 drop end
begin call.foo end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo push.100 mem_store.44 end
proc.bar mem_load.44 assertz end
begin call.foo mem_load.44 assertz call.bar end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo mem_load.44 assertz end
proc.bar push.100 mem_store.44 call.foo mem_load.44 swap.8 drop end
begin call.bar end",
vec![16_u32.into(); 16]
)]
#[case(None, "
proc.foo add end
begin
procref.foo mem_storew_be.100 dropw push.100
dyncall swap.8 drop
end",
vec![16_u32.into(); 16]
)]
#[case(None, "
proc.foo clk add end
begin
push.1
if.true
procref.foo mem_storew_be.100 dropw
push.100 dyncall
push.100 dyncall
else
swap
end
clk swap.8 drop
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo.2 locaddr.0 locaddr.1 swap.8 drop swap.8 drop end
begin
procref.foo mem_storew_be.100 dropw push.100
dyncall
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo push.100 mem_store.44 end
proc.bar mem_load.44 assertz end
begin
procref.foo mem_storew_be.100 dropw push.100 dyncall
mem_load.44 assertz
procref.bar mem_storew_be.104 dropw push.104 dyncall
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo mem_load.44 assertz end
proc.bar
push.100 mem_store.44
procref.foo mem_storew_be.104 dropw push.104 dyncall
mem_load.44 swap.8 drop
end
begin
procref.bar mem_storew_be.104 dropw push.104 dyncall
end",
vec![16_u32.into(); 16]
)]
#[case(None, "
proc.foo add end
begin
procref.foo mem_storew_be.100 dropw push.100
dynexec swap.8 drop
end",
vec![16_u32.into(); 16]
)]
#[case(None, "
proc.foo clk add end
begin
push.1
if.true
procref.foo mem_storew_be.100 dropw
push.100 dynexec
push.100 dynexec
else
swap
end
clk swap.8 drop
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo.2 locaddr.0 locaddr.1 swap.8 drop swap.8 drop end
begin
procref.foo mem_storew_be.100 dropw push.100
dynexec
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
proc.foo push.100 mem_store.44 end
proc.bar mem_load.44 sub.100 assertz end
begin
procref.foo mem_storew_be.104 dropw push.104 dynexec
mem_load.44 sub.100 assertz
procref.bar mem_storew_be.108 dropw push.108 dynexec
end",
vec![16_u32.into(); 16]
)]
#[case(None, "begin while.true push.1 assertz end clk swap.8 drop end", vec![3_u32.into(), 2_u32.into(), 1_u32.into(), ZERO])]
#[case(None,
"begin
while.true
clk swap.15 drop
end
clk swap.8 drop
end",
vec![42_u32.into(), ZERO, ONE, ONE, ONE, ONE]
)]
#[case(None,
"begin
push.1.2.3.4 mem_storew_be.40 dropw
horner_eval_base
end",
// first 3 addresses in the vec are the alpha_ptr, acc_high and acc_low, respectively.
vec![100_u32.into(), 4_u32.into(), 40_u32.into(), 4_u32.into(), 5_u32.into(), 6_u32.into(), 7_u32.into(),
8_u32.into(), 9_u32.into(), 10_u32.into(), 11_u32.into(), 12_u32.into(), 13_u32.into(),
14_u32.into(), 15_u32.into(), 16_u32.into()]
)]
#[case(None,
"begin
log_precompile
end",
vec![1_u32.into(), 2_u32.into(), 3_u32.into(), 4_u32.into(),
5_u32.into(), 6_u32.into(), 7_u32.into(), 8_u32.into()],
)]
#[case(None,
"begin
push.1.2.3.4 mem_storew_be.40 dropw
horner_eval_ext
end",
// first 3 addresses in the vec are the alpha_ptr, acc_high and acc_low, respectively.
vec![100_u32.into(), 4_u32.into(), 40_u32.into(), 4_u32.into(), 5_u32.into(), 6_u32.into(), 7_u32.into(),
8_u32.into(), 9_u32.into(), 10_u32.into(), 11_u32.into(), 12_u32.into(), 13_u32.into(),
14_u32.into(), 15_u32.into(), 16_u32.into()]
)]
#[case(None,"
begin
u32divmod
end",
vec![6_u32.into(), 3_u32.into()]
)]
#[case(None,"
begin
u32overflowing_add sub.1 assertz
end",
vec![Felt::from(u32::MAX), ONE]
)]
fn test_masm_consistency(
#[case] kernel_source: Option<&'static str>,
#[case] program_source: &'static str,
#[case] stack_inputs: Vec<Felt>,
) {
let (program, kernel_lib) = {
let source_manager = Arc::new(DefaultSourceManager::default());
match kernel_source {
Some(kernel_source) => {
let kernel_lib =
Assembler::new(source_manager.clone()).assemble_kernel(kernel_source).unwrap();
let program = Assembler::with_kernel(source_manager, kernel_lib.clone())
.assemble_program(program_source)
.unwrap();
(program, Some(kernel_lib))
},
None => {
let program =
Assembler::new(source_manager).assemble_program(program_source).unwrap();
(program, None)
},
}
};
let mut host = DefaultHost::default();
if let Some(kernel_lib) = &kernel_lib {
host.load_library(kernel_lib.mast_forest()).unwrap();
}
let processor = FastProcessor::new(&stack_inputs);
let fast_stack_outputs = processor.execute_sync(&program, &mut host).unwrap();
let mut slow_processor = Process::new(
kernel_lib.map(|k| k.kernel().clone()).unwrap_or_default(),
StackInputs::new(stack_inputs).unwrap(),
AdviceInputs::default(),
ExecutionOptions::default(),
);
let slow_stack_outputs = slow_processor.execute(&program, &mut host).unwrap();
assert_eq!(fast_stack_outputs, slow_stack_outputs);
}
#[rstest]
#[case(None, "begin while.true swap end end", vec![2_u32.into(); 16])]
#[case(None, "begin while.true push.100 end end", vec![ONE; 16])]
#[case(None,"
begin
dyncall
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
begin
dynexec
end",
vec![16_u32.into(); 16]
)]
#[case(None,"
begin
u32divmod
end",
vec![ZERO; 16]
)]
#[case(None,"
begin
u32overflowing_add
end",
vec![Felt::from(u32::MAX) + ONE, ZERO]
)]
fn test_masm_errors_consistency(
#[case] kernel_source: Option<&'static str>,
#[case] program_source: &'static str,
#[case] stack_inputs: Vec<Felt>,
) {
let (program, kernel_lib) = {
let source_manager = Arc::new(DefaultSourceManager::default());
match kernel_source {
Some(kernel_source) => {
let kernel_lib =
Assembler::new(source_manager.clone()).assemble_kernel(kernel_source).unwrap();
let program = Assembler::with_kernel(source_manager, kernel_lib.clone())
.assemble_program(program_source)
.unwrap();
(program, Some(kernel_lib))
},
None => {
let program =
Assembler::new(source_manager).assemble_program(program_source).unwrap();
(program, None)
},
}
};
let mut host = DefaultHost::default();
if let Some(kernel_lib) = &kernel_lib {
host.load_library(kernel_lib.mast_forest()).unwrap();
}
let processor = FastProcessor::new(&stack_inputs);
let fast_stack_outputs = processor.execute_sync(&program, &mut host).unwrap_err();
let mut slow_processor = Process::new(
kernel_lib.map(|k| k.kernel().clone()).unwrap_or_default(),
StackInputs::new(stack_inputs).unwrap(),
AdviceInputs::default(),
ExecutionOptions::default(),
);
let slow_stack_outputs = slow_processor.execute(&program, &mut host).unwrap_err();
assert_eq!(fast_stack_outputs.to_string(), slow_stack_outputs.to_string());
}
#[test]
fn test_log_precompile_correctness() {
use miden_core::crypto::hash::Rpo256;
let stack_inputs = [1, 2, 3, 4, 5, 6, 7, 8].map(Felt::new);
let cap_prev = Word::empty();
let tag: Word = [1, 2, 3, 4].map(Felt::new).into();
let comm_calldata: Word = [5, 6, 7, 8].map(Felt::new).into();
let mut hasher_state = [ZERO; 12];
hasher_state[0..4].copy_from_slice(cap_prev.as_slice());
hasher_state[4..8].copy_from_slice(tag.as_slice());
hasher_state[8..12].copy_from_slice(comm_calldata.as_slice());
Rpo256::apply_permutation(&mut hasher_state);
let program_source = "begin log_precompile end";
let program = {
let source_manager = Arc::new(DefaultSourceManager::default());
Assembler::new(source_manager).assemble_program(program_source).unwrap()
};
let mut host = DefaultHost::default();
let processor = FastProcessor::new(&stack_inputs);
let stack_outputs = processor.execute_sync(&program, &mut host).unwrap();
let r1 = stack_outputs.get_stack_word_be(0).unwrap();
let r0 = stack_outputs.get_stack_word_be(4).unwrap();
let cap_next = stack_outputs.get_stack_word_be(8).unwrap();
assert_eq!(&hasher_state[0..4], cap_next.as_slice(), "CAP_NEXT on stack mismatch");
assert_eq!(&hasher_state[4..8], r0.as_slice(), "R0 on stack mismatch");
assert_eq!(&hasher_state[8..12], r1.as_slice(), "R1 on stack mismatch");
}