-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
_Issue #136 #137_ Depends on #272 (done). --------- Co-authored-by: Aurélien Nicolas <[email protected]>
- Loading branch information
Showing
14 changed files
with
381 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use std::mem::MaybeUninit; | ||
|
||
use ff_ext::ExtensionField; | ||
use goldilocks::SmallField; | ||
|
||
use crate::{ | ||
circuit_builder::CircuitBuilder, | ||
error::ZKVMError, | ||
expression::{Expression, ToExpr, WitIn}, | ||
set_val, | ||
}; | ||
|
||
pub struct IsZeroConfig { | ||
is_zero: WitIn, | ||
inverse: WitIn, | ||
} | ||
|
||
impl IsZeroConfig { | ||
pub fn expr<E: ExtensionField>(&self) -> Expression<E> { | ||
self.is_zero.expr() | ||
} | ||
|
||
pub fn construct_circuit<E: ExtensionField>( | ||
cb: &mut CircuitBuilder<E>, | ||
x: Expression<E>, | ||
) -> Result<Self, ZKVMError> { | ||
let is_zero = cb.create_witin(|| "is_zero")?; | ||
let inverse = cb.create_witin(|| "inv")?; | ||
|
||
// x==0 => is_zero=1 | ||
cb.require_one(|| "is_zero_1", is_zero.expr() + x.clone() * inverse.expr())?; | ||
|
||
// x!=0 => is_zero=0 | ||
cb.require_zero(|| "is_zero_0", is_zero.expr() * x.clone())?; | ||
|
||
Ok(IsZeroConfig { is_zero, inverse }) | ||
} | ||
|
||
pub fn assign_instance<F: SmallField>( | ||
&self, | ||
instance: &mut [MaybeUninit<F>], | ||
x: F, | ||
) -> Result<(), ZKVMError> { | ||
let (is_zero, inverse) = if x.is_zero_vartime() { | ||
(F::ONE, F::ZERO) | ||
} else { | ||
(F::ZERO, x.invert().expect("not zero")) | ||
}; | ||
|
||
set_val!(instance, self.is_zero, is_zero); | ||
set_val!(instance, self.inverse, inverse); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
pub struct IsEqualConfig(IsZeroConfig); | ||
|
||
impl IsEqualConfig { | ||
pub fn expr<E: ExtensionField>(&self) -> Expression<E> { | ||
self.0.expr() | ||
} | ||
|
||
pub fn construct_circuit<E: ExtensionField>( | ||
cb: &mut CircuitBuilder<E>, | ||
a: Expression<E>, | ||
b: Expression<E>, | ||
) -> Result<Self, ZKVMError> { | ||
Ok(IsEqualConfig(IsZeroConfig::construct_circuit(cb, a - b)?)) | ||
} | ||
|
||
pub fn assign_instance<F: SmallField>( | ||
&self, | ||
instance: &mut [MaybeUninit<F>], | ||
a: F, | ||
b: F, | ||
) -> Result<(), ZKVMError> { | ||
self.0.assign_instance(instance, a - b) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mod is_zero; | ||
pub use is_zero::{IsEqualConfig, IsZeroConfig}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
mod beq_circuit; | ||
use super::RIVInstruction; | ||
use beq_circuit::BeqCircuit; | ||
use ceno_emul::InsnKind; | ||
|
||
#[cfg(test)] | ||
mod test; | ||
|
||
pub struct BeqOp; | ||
impl RIVInstruction for BeqOp { | ||
const INST_KIND: InsnKind = InsnKind::BEQ; | ||
} | ||
pub type BeqInstruction<E> = BeqCircuit<E, BeqOp>; | ||
|
||
pub struct BneOp; | ||
impl RIVInstruction for BneOp { | ||
const INST_KIND: InsnKind = InsnKind::BNE; | ||
} | ||
pub type BneInstruction<E> = BeqCircuit<E, BneOp>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use std::{marker::PhantomData, mem::MaybeUninit}; | ||
|
||
use ceno_emul::{InsnKind, StepRecord}; | ||
use ff_ext::ExtensionField; | ||
|
||
use crate::{ | ||
circuit_builder::CircuitBuilder, | ||
error::ZKVMError, | ||
expression::Expression, | ||
gadgets::IsEqualConfig, | ||
instructions::{ | ||
riscv::{b_insn::BInstructionConfig, constants::UInt, RIVInstruction}, | ||
Instruction, | ||
}, | ||
witness::LkMultiplicity, | ||
Value, | ||
}; | ||
|
||
pub struct BeqConfig<E: ExtensionField> { | ||
b_insn: BInstructionConfig, | ||
|
||
// TODO: Limb decomposition is not necessary. Replace with a single witness. | ||
rs1_read: UInt<E>, | ||
rs2_read: UInt<E>, | ||
|
||
equal: IsEqualConfig, | ||
} | ||
|
||
pub struct BeqCircuit<E, I>(PhantomData<(E, I)>); | ||
|
||
impl<E: ExtensionField, I: RIVInstruction> Instruction<E> for BeqCircuit<E, I> { | ||
type InstructionConfig = BeqConfig<E>; | ||
|
||
fn name() -> String { | ||
format!("{:?}", I::INST_KIND) | ||
} | ||
|
||
fn construct_circuit( | ||
circuit_builder: &mut CircuitBuilder<E>, | ||
) -> Result<Self::InstructionConfig, ZKVMError> { | ||
let rs1_read = UInt::new_unchecked(|| "rs1_read", circuit_builder)?; | ||
let rs2_read = UInt::new_unchecked(|| "rs2_read", circuit_builder)?; | ||
|
||
let equal = | ||
IsEqualConfig::construct_circuit(circuit_builder, rs2_read.value(), rs1_read.value())?; | ||
|
||
let branch_taken_bit = match I::INST_KIND { | ||
InsnKind::BEQ => equal.expr(), | ||
InsnKind::BNE => Expression::ONE - equal.expr(), | ||
_ => unreachable!("Unsupported instruction kind {:?}", I::INST_KIND), | ||
}; | ||
|
||
let b_insn = BInstructionConfig::construct_circuit( | ||
circuit_builder, | ||
I::INST_KIND, | ||
rs1_read.register_expr(), | ||
rs2_read.register_expr(), | ||
branch_taken_bit, | ||
)?; | ||
|
||
Ok(BeqConfig { | ||
b_insn, | ||
rs1_read, | ||
rs2_read, | ||
equal, | ||
}) | ||
} | ||
|
||
fn assign_instance( | ||
config: &Self::InstructionConfig, | ||
instance: &mut [MaybeUninit<<E as ExtensionField>::BaseField>], | ||
lk_multiplicity: &mut LkMultiplicity, | ||
step: &StepRecord, | ||
) -> Result<(), ZKVMError> { | ||
config | ||
.b_insn | ||
.assign_instance::<E>(instance, lk_multiplicity, step)?; | ||
|
||
let rs1_read = step.rs1().unwrap().value; | ||
config | ||
.rs1_read | ||
.assign_limbs(instance, Value::new_unchecked(rs1_read).u16_fields()); | ||
|
||
let rs2_read = step.rs2().unwrap().value; | ||
config | ||
.rs2_read | ||
.assign_limbs(instance, Value::new_unchecked(rs2_read).u16_fields()); | ||
|
||
config.equal.assign_instance( | ||
instance, | ||
E::BaseField::from(rs2_read as u64), | ||
E::BaseField::from(rs1_read as u64), | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.