Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: range check halt/commit_deferred_proof operands #986

Merged
merged 8 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions core/src/cpu/air/ecall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::air::{BaseAirBuilder, PublicValues, WordAirBuilder};
use crate::cpu::air::{Word, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS};
use crate::cpu::columns::{CpuCols, OpcodeSelectorCols};
use crate::memory::MemoryCols;
use crate::operations::IsZeroOperation;
use crate::operations::{BabyBearWordRangeChecker, IsZeroOperation};
use crate::runtime::SyscallCode;
use crate::stark::{CpuChip, SP1AirBuilder};

Expand Down Expand Up @@ -88,6 +88,21 @@ impl CpuChip {
.when(is_ecall_instruction.clone())
.when_not(is_enter_unconstrained + is_hint_len)
.assert_word_eq(local.op_a_val(), local.op_a_access.prev_value);

// Verify value of ecall_range_check_operand column.
builder.assert_eq(
local.ecall_range_check_operand,
is_ecall_instruction
* (ecall_cols.is_halt.result + ecall_cols.is_commit_deferred_proofs.result),
);

// Babybear range check the operand_to_check word.
BabyBearWordRangeChecker::<AB::F>::range_check::<AB>(
builder,
ecall_cols.operand_to_check,
ecall_cols.operand_range_check_cols,
local.ecall_range_check_operand.into(),
);
}

/// Constraints related to the COMMIT and COMMIT_DEFERRED_PROOFS instructions.
Expand Down Expand Up @@ -160,13 +175,18 @@ impl CpuChip {
.when(local.selectors.is_ecall * is_commit)
.assert_word_eq(expected_pv_digest_word, *digest_word);

let expected_deferred_proofs_digest_word =
let expected_deferred_proofs_digest_element =
builder.index_array(&deferred_proofs_digest, &ecall_columns.index_bitmap);

// Verify that the operand that was range checked is digest_word.
builder
.when(local.selectors.is_ecall * is_commit_deferred_proofs.clone())
.assert_word_eq(*digest_word, ecall_columns.operand_to_check);

builder
.when(local.selectors.is_ecall * is_commit_deferred_proofs)
.assert_eq(
expected_deferred_proofs_digest_word,
expected_deferred_proofs_digest_element,
digest_word.reduce::<AB>(),
);
}
Expand All @@ -189,6 +209,12 @@ impl CpuChip {

builder.when(is_halt.clone()).assert_zero(local.next_pc);

// Verify that the operand that was range checked is op_b.
let ecall_columns = local.opcode_specific_columns.ecall();
builder
.when(is_halt.clone())
.assert_word_eq(local.op_b_val(), ecall_columns.operand_to_check);

builder.when(is_halt.clone()).assert_eq(
local.op_b_access.value().reduce::<AB>(),
public_values.exit_code.clone(),
Expand Down
11 changes: 10 additions & 1 deletion core/src/cpu/columns/ecall.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use sp1_derive::AlignedBorrow;
use std::mem::size_of;

use crate::{air::PV_DIGEST_NUM_WORDS, operations::IsZeroOperation};
use crate::{
air::{Word, PV_DIGEST_NUM_WORDS},
operations::{BabyBearWordRangeChecker, IsZeroOperation},
};

pub const NUM_ECALL_COLS: usize = size_of::<EcallCols<u8>>();

Expand Down Expand Up @@ -29,4 +32,10 @@ pub struct EcallCols<T> {

/// The nonce of the syscall operation.
pub syscall_nonce: T,

/// Columns to babybear range check the halt/commit_deferred_proofs operand.
pub operand_range_check_cols: BabyBearWordRangeChecker<T>,

/// The operand value to babybear range check.
pub operand_to_check: Word<T>,
}
3 changes: 3 additions & 0 deletions core/src/cpu/columns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ pub struct CpuCols<T: Copy> {
/// The result of selectors.is_ecall * the send_to_table column for the ECALL opcode.
pub ecall_mul_send_to_table: T,

/// The result of selectors.is_ecall * (is_halt || is_commit_deferred_proofs)
pub ecall_range_check_operand: T,

/// This is true for all instructions that are not jumps, branches, and halt. Those instructions
/// may move the program counter to a non sequential instruction.
pub is_sequential_instr: T,
Expand Down
15 changes: 15 additions & 0 deletions core/src/cpu/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,21 @@ impl CpuChip {
);

is_halt = syscall_id == F::from_canonical_u32(SyscallCode::HALT.syscall_id());

// For halt and commit deferred proofs syscalls, we need to baby bear range check one of
// it's operands.
if is_halt {
ecall_cols.operand_to_check = event.b.into();
ecall_cols.operand_range_check_cols.populate(event.b);
cols.ecall_range_check_operand = F::one();
}

if syscall_id == F::from_canonical_u32(SyscallCode::COMMIT_DEFERRED_PROOFS.syscall_id())
{
ecall_cols.operand_to_check = event.c.into();
ecall_cols.operand_range_check_cols.populate(event.c);
cols.ecall_range_check_operand = F::one();
}
}

is_halt
Expand Down
Loading