Skip to content

Commit

Permalink
fix memory lookup collisions
Browse files Browse the repository at this point in the history
  • Loading branch information
tamirhemo committed Jan 12, 2024
1 parent eb7c261 commit 11f8c3e
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 41 deletions.
4 changes: 2 additions & 2 deletions curta/src/chip/memory/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ impl<L: AirParameters> AirBuilder<L> {

#[inline]
pub(crate) fn uninit<V: MemoryValue>(&mut self) -> Pointer<V> {
let ptr_challenge = self.alloc_challenge();
let ptr_challenge_powers = self.challenge_powers(3);
let compression_challenges = self.challenge_powers(V::num_challenges());
Pointer::from_challenges(ptr_challenge, compression_challenges)
Pointer::from_challenges(ptr_challenge_powers, compression_challenges)
}

/// Frees the memory at location `ptr` with value `value` and write time given by `time`.
Expand Down
48 changes: 30 additions & 18 deletions curta/src/chip/memory/pointer/accumulate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::marker::PhantomData;

use plonky2::field::ops::Square;
use serde::{Deserialize, Serialize};

use super::raw::RawPointer;
Expand All @@ -21,10 +22,17 @@ pub enum CompressedValue<F> {
Element(ArithmeticExpression<F>),
}

/// Accumulating the pointer value for lookup.
///
/// Given a raw pointer consisting of a challenge `gamma` and a shift, the accumulated value is
/// given by `value + gamma * shift + gamma^2`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PointerAccumulator<F, E> {
/// The raw pointer to be accumulated.
ptr: RawPointer,
/// The value in compressed form, consisting of the value and a timestamp.
value: CompressedValue<F>,
/// The final digest which is inserted into the bus.
pub(crate) digest: CubicRegister,
_marker: PhantomData<E>,
}
Expand Down Expand Up @@ -60,22 +68,27 @@ impl<E: CubicParameters<AP::Field>, AP: CubicParser<E>> AirConstraint<AP>
for PointerAccumulator<AP::Field, E>
{
fn eval(&self, parser: &mut AP) {
let challenge = self.ptr.eval(parser);
let digest = self.digest.eval(parser);
let (powers, shift) = self.ptr.eval(parser);
let shift = parser.element_from_base_field(shift);

let expected_value = match self.value.clone() {
CompressedValue::Cubic(cubic) => {
let value = CubicElement(cubic.0.map(|e| e.eval(parser)[0]));
parser.mul_extension(challenge, value)
}
CompressedValue::Element(element) => {
let value_base = element.eval(parser)[0];
let value = parser.element_from_base_field(value_base);
parser.mul_extension(challenge, value)
let value = match self.value.clone() {
CompressedValue::Element(e) => {
let value = e.eval(parser)[0];
parser.element_from_base_field(value)
}
CompressedValue::Cubic(e) => CubicElement(e.0.map(|e| e.eval(parser)[0])),
};

parser.assert_eq_extension(expected_value, digest);
let mut expected_digest = value;
let shift_times_challenge = parser.mul_extension(shift, powers[1]);
// Expected digest is now value + gamma * shift.
expected_digest = parser.add_extension(expected_digest, shift_times_challenge);
// Expected digest is now value + gamma * shift + gamma^2.
expected_digest = parser.add_extension(expected_digest, powers[2]);

// Compare expected digest with actual digest.
let digest = self.digest.eval(parser);
parser.assert_eq_extension(expected_digest, digest);
}
}

Expand All @@ -87,19 +100,18 @@ impl<F: Field> TraceWriter<F> {
) {
let ptr_key = accumulator.ptr.read(self, row_index);
let ptr_challenge = self.read(&ptr_key.challenge, row_index);
let ptr_value = ptr_challenge + CubicElement::from_base(ptr_key.shift, F::ZERO);

let value = match accumulator.value.clone() {
CompressedValue::Cubic(cubic) => {
let value = CubicElement(cubic.0.map(|e| self.read_expression(&e, row_index)[0]));
value * ptr_value
CubicElement(cubic.0.map(|e| self.read_expression(&e, row_index)[0]))
}
CompressedValue::Element(element) => {
let value = self.read_expression(&element, row_index)[0];
ptr_value * CubicElement::from_base(value, F::ZERO)
CubicElement::from_base(value, F::ZERO)
}
};

self.write(&accumulator.digest, &value, row_index);
let digest = value + ptr_challenge * ptr_key.shift + ptr_challenge.square();

self.write(&accumulator.digest, &digest, row_index);
}
}
38 changes: 25 additions & 13 deletions curta/src/chip/memory/pointer/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::key::RawPointerKey;
use crate::air::extension::cubic::CubicParser;
use crate::chip::arithmetic::expression::ArithmeticExpression;
use crate::chip::builder::AirBuilder;
use crate::chip::register::array::ArrayRegister;
use crate::chip::register::cubic::CubicRegister;
use crate::chip::register::element::ElementRegister;
use crate::chip::register::{Register, RegisterSerializable};
Expand All @@ -16,27 +17,28 @@ use crate::math::prelude::CubicParameters;

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct RawPointer {
challenge: CubicRegister,
/// The powers `1, gamma, gamma^2, ...` of the challenge identifying the unique pointer.
powers: ArrayRegister<CubicRegister>,
element_shift: Option<ElementRegister>,
constant_shift: Option<i32>,
}

impl RawPointer {
pub(crate) fn new(
challenge: CubicRegister,
powers: ArrayRegister<CubicRegister>,
element_shift: Option<ElementRegister>,
constant_shift: Option<i32>,
) -> Self {
Self {
challenge,
powers,
element_shift,
constant_shift,
}
}

pub(crate) fn from_challenge(challenge: CubicRegister) -> Self {
pub(crate) fn from_challenge(powers: ArrayRegister<CubicRegister>) -> Self {
Self {
challenge,
powers,
element_shift: None,
constant_shift: None,
}
Expand Down Expand Up @@ -84,8 +86,8 @@ impl RawPointer {
pub fn eval<E: CubicParameters<AP::Field>, AP: CubicParser<E>>(
&self,
parser: &mut AP,
) -> CubicElement<AP::Var> {
let challenge = self.challenge.eval(parser);
) -> ([CubicElement<AP::Var>; 3], AP::Var) {
let challenges = self.powers.eval_array::<_, 3>(parser);

let shift = match (self.element_shift, self.constant_shift) {
(Some(e), None) => Some(e.eval(parser)),
Expand All @@ -98,10 +100,20 @@ impl RawPointer {
(None, None) => None,
};

let shift_ext = shift.map(|e| parser.element_from_base_field(e));
shift_ext
.map(|e| parser.add_extension(challenge, e))
.unwrap_or(challenge)
(challenges, shift.unwrap_or(parser.zero()))
}

pub fn shift_expr<F: Field>(&self) -> ArithmeticExpression<F> {
match (self.element_shift, self.constant_shift) {
(Some(e), None) => e.expr(),
(None, Some(c)) => ArithmeticExpression::from_constant(i32_to_field(c)),
(Some(e), Some(c)) => {
let element = e.expr::<F>();
let constant = i32_to_field::<F>(c);
element + constant
}
(None, None) => ArithmeticExpression::zero(),
}
}

pub fn read<F: Field>(&self, writer: &TraceWriter<F>, row_index: usize) -> RawPointerKey<F> {
Expand All @@ -111,7 +123,7 @@ impl RawPointer {
.unwrap_or(F::ZERO);
let constant_shift = self.constant_shift.map(i32_to_field).unwrap_or(F::ZERO);
let shift = element_shift + constant_shift;
RawPointerKey::new(self.challenge, shift)
RawPointerKey::new(self.powers.get(1), shift)
}

pub fn read_from_air<F: Field>(&self, writer: &impl AirWriter<Field = F>) -> RawPointerKey<F> {
Expand All @@ -121,7 +133,7 @@ impl RawPointer {
.unwrap_or(F::ZERO);
let constant_shift = self.constant_shift.map(i32_to_field).unwrap_or(F::ZERO);
let shift = element_shift + constant_shift;
RawPointerKey::new(self.challenge, shift)
RawPointerKey::new(self.powers.get(1), shift)
}
}

Expand Down
12 changes: 6 additions & 6 deletions curta/src/chip/memory/pointer/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::chip::AirParameters;

#[derive(Clone, Debug)]
pub struct RawSlice {
challenge: CubicRegister,
powers: ArrayRegister<CubicRegister>,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -49,20 +49,20 @@ impl<V: MemoryValue> Slice<V> {
impl RawSlice {
pub(crate) fn get(&self, idx: usize) -> RawPointer {
assert!(idx <= i32::MAX as usize);
RawPointer::new(self.challenge, None, Some(idx as i32))
RawPointer::new(self.powers, None, Some(idx as i32))
}

pub(crate) fn new<L: AirParameters>(builder: &mut AirBuilder<L>) -> Self {
let challenge = builder.alloc_challenge();
let powers = builder.challenge_powers(3);

Self { challenge }
Self { powers }
}

pub(crate) fn get_at(&self, idx: ElementRegister) -> RawPointer {
RawPointer::new(self.challenge, Some(idx), None)
RawPointer::new(self.powers, Some(idx), None)
}

pub(crate) fn get_at_shifted(&self, idx: ElementRegister, shift: i32) -> RawPointer {
RawPointer::new(self.challenge, Some(idx), Some(shift))
RawPointer::new(self.powers, Some(idx), Some(shift))
}
}
4 changes: 2 additions & 2 deletions curta/src/chip/memory/pointer/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ impl<T> Pointer<T> {
}

pub(crate) fn from_challenges(
raw_ptr_challenge: CubicRegister,
raw_ptr_challenge_powers: ArrayRegister<CubicRegister>,
compression_challenges: ArrayRegister<CubicRegister>,
) -> Self {
Self::new(
RawPointer::from_challenge(raw_ptr_challenge),
RawPointer::from_challenge(raw_ptr_challenge_powers),
compression_challenges,
)
}
Expand Down

0 comments on commit 11f8c3e

Please sign in to comment.