#![cfg(feature = "polkavm-integration")]
use ligerito::pcvm::polkavm_adapter::PolkaVMRegisters;
use ligerito::pcvm::polkavm_arithmetization::arithmetize_polkavm_trace;
use ligerito::pcvm::polkavm_constraints_v2::{InstructionProof, ProvenTransition};
use ligerito_binary_fields::{BinaryElem128, BinaryElem32, BinaryFieldElement};
use polkavm::program::Instruction;
use polkavm_common::program::{RawReg, Reg};
fn raw_reg(r: Reg) -> RawReg {
RawReg::from(r)
}
#[test]
fn test_reject_forged_register_continuity() {
let mut regs_0 = [0u32; 13];
let mut regs_1 = regs_0;
regs_1[7] = 42;
let step1 = (
ProvenTransition {
pc: 0x1000,
next_pc: 0x1002,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs_0),
regs_after: PolkaVMRegisters::from_array(regs_1),
memory_root_before: [0u8; 32],
memory_root_after: [0u8; 32],
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A0), 42),
);
let mut forged_regs_before = [0u32; 13];
forged_regs_before[7] = 999;
let mut regs_2 = forged_regs_before;
regs_2[8] = 100;
let step2 = (
ProvenTransition {
pc: 0x1002,
next_pc: 0x1004,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(forged_regs_before), regs_after: PolkaVMRegisters::from_array(regs_2),
memory_root_before: [0u8; 32],
memory_root_after: [0u8; 32],
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A1), 100),
);
let trace = vec![step1, step2];
let batching_challenge = BinaryElem128::from(0x12345678u128);
let arith = arithmetize_polkavm_trace(&trace, [0u8; 32], batching_challenge)
.expect("Should arithmetize");
assert_ne!(
arith.constraint_accumulator,
BinaryElem128::zero(),
"Forged register continuity should fail! Accumulator: {:?}",
arith.constraint_accumulator
);
println!("✓ Forged register continuity correctly rejected");
println!(" - Step 1 ends with: a0 = 42");
println!(" - Step 2 claims to start with: a0 = 999");
println!(
" - Constraint accumulator: {:?} (non-zero)",
arith.constraint_accumulator
);
}
#[test]
fn test_reject_forged_memory_continuity() {
let mut regs = [0u32; 13];
let mut memory_root_1 = [0u8; 32];
memory_root_1[0] = 1;
memory_root_1[1] = 2;
let step1 = (
ProvenTransition {
pc: 0x1000,
next_pc: 0x1002,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs),
regs_after: PolkaVMRegisters::from_array(regs),
memory_root_before: [0u8; 32],
memory_root_after: memory_root_1, memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A0), 0),
);
let mut forged_memory_root = [0u8; 32];
forged_memory_root[0] = 99; forged_memory_root[1] = 88;
let step2 = (
ProvenTransition {
pc: 0x1002,
next_pc: 0x1004,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs),
regs_after: PolkaVMRegisters::from_array(regs),
memory_root_before: forged_memory_root, memory_root_after: forged_memory_root,
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A0), 0),
);
let trace = vec![step1, step2];
let batching_challenge = BinaryElem128::from(0xABCDEF01u128);
let arith = arithmetize_polkavm_trace(&trace, [0u8; 32], batching_challenge)
.expect("Should arithmetize");
assert_ne!(
arith.constraint_accumulator,
BinaryElem128::zero(),
"Forged memory continuity should fail!"
);
println!("✓ Forged memory root continuity correctly rejected");
println!(" - Step 1 ends with memory_root: [1, 2, 0, ...]");
println!(" - Step 2 claims to start with: [99, 88, 0, ...]");
println!(
" - Constraint accumulator: {:?} (non-zero)",
arith.constraint_accumulator
);
}
#[test]
fn test_reject_forged_pc_continuity() {
let mut regs = [0u32; 13];
let step1 = (
ProvenTransition {
pc: 0x1000,
next_pc: 0x1002, instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs),
regs_after: PolkaVMRegisters::from_array(regs),
memory_root_before: [0u8; 32],
memory_root_after: [0u8; 32],
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A0), 0),
);
let step2 = (
ProvenTransition {
pc: 0x9999, next_pc: 0x999B,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs),
regs_after: PolkaVMRegisters::from_array(regs),
memory_root_before: [0u8; 32],
memory_root_after: [0u8; 32],
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A0), 0),
);
let trace = vec![step1, step2];
let batching_challenge = BinaryElem128::from(0x11111111u128);
let arith = arithmetize_polkavm_trace(&trace, [0u8; 32], batching_challenge)
.expect("Should arithmetize");
assert_ne!(
arith.constraint_accumulator,
BinaryElem128::zero(),
"Forged PC continuity should fail!"
);
println!("✓ Forged PC continuity correctly rejected");
println!(" - Step 1 next_pc: 0x1002");
println!(" - Step 2 pc: 0x9999 (control flow forgery!)");
println!(
" - Constraint accumulator: {:?} (non-zero)",
arith.constraint_accumulator
);
}
#[test]
fn test_valid_state_continuity_passes() {
let mut regs_0 = [0u32; 13];
let mut regs_1 = regs_0;
regs_1[7] = 10;
let step1 = (
ProvenTransition {
pc: 0x1000,
next_pc: 0x1002,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs_0),
regs_after: PolkaVMRegisters::from_array(regs_1), memory_root_before: [0u8; 32],
memory_root_after: [0u8; 32],
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A0), 10),
);
let mut regs_2 = regs_1;
regs_2[8] = 20;
let step2 = (
ProvenTransition {
pc: 0x1002, next_pc: 0x1004,
instruction_size: 2,
regs_before: PolkaVMRegisters::from_array(regs_1), regs_after: PolkaVMRegisters::from_array(regs_2),
memory_root_before: [0u8; 32], memory_root_after: [0u8; 32],
memory_proof: None,
instruction_proof: InstructionProof {
merkle_path: vec![],
position: 0,
opcode: 0,
operands: [0, 0, 0],
},
},
Instruction::load_imm(raw_reg(Reg::A1), 20),
);
let trace = vec![step1, step2];
let batching_challenge = BinaryElem128::from(0x42424242u128);
let arith = arithmetize_polkavm_trace(&trace, [0u8; 32], batching_challenge)
.expect("Should arithmetize");
assert_eq!(
arith.constraint_accumulator,
BinaryElem128::zero(),
"Valid continuity should pass! Accumulator: {:?}",
arith.constraint_accumulator
);
println!("✓ Valid state continuity correctly accepted");
println!(" - All states chain correctly");
println!(" - Constraint accumulator: ZERO (all satisfied)");
}