(&mut self, num: &BigUint) -> FieldRegister {
11 | let poly =
12 | Polynomial::::from_biguint_field(num, P::NB_BITS_PER_LIMB, P::NB_LIMBS);
13 |
14 | self.constant(&poly)
15 | }
16 |
17 | pub fn fp_zero(&mut self) -> FieldRegister {
18 | self.fp_constant(&BigUint::zero())
19 | }
20 |
21 | pub fn fp_one(&mut self) -> FieldRegister {
22 | self.fp_constant(&BigUint::one())
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/starkyx/src/chip/field/mod.rs:
--------------------------------------------------------------------------------
1 | //! Implements field arithmetic for any field, using a technique from Polygon Zero.
2 | //! Reference: https://github.com/mir-protocol/plonky2/blob/main/evm/src/arithmetic/addcy.rs
3 | //!
4 | //! We want to compute a + b = result mod p. In the integers, this is equivalent to witnessing some
5 | //! carry such that:
6 | //!
7 | //! a + b - result - carry * p = 0.
8 | //!
9 | //! Let us encode the integers as polynomials in the Goldilocks field, where each coefficient is
10 | //! at most 16 bits. In other words, the integers are encoded as an array of little-endian base 16
11 | //! limbs. We can then write the above equation as:
12 | //!
13 | //! a(x) + b(x) - result(x) - carry(x) * p(x)
14 | //!
15 | //! where the polynomial should evaluate to 0 if x = 2^16. To prove that the polynomial has a root
16 | //! at 2^16, we can have the prover witness a polynomial `w(x)` such that the above polynomial
17 | //! is divisble by (x - 2^16):
18 | //!
19 | //! a(x) + b(x) - result(x) - carry(x) * p(x) - (x - 2^16) * w(x) = 0
20 | //!
21 | //! Thus, if we can prove that above polynomial is 0, we can conclude that the addition has been
22 | //! computed correctly. Note that this relies on the fact that any quadratic sum of a sufficiently
23 | //! small number of terms (i.e., less than 2^32 terms) will not overflow in the Goldilocks field.
24 | //! Furthermore, one must be careful to ensure that all polynomials except w(x) are range checked
25 | //! in [0, 2^16).
26 | //!
27 | //! This technique generalizes for any quadratic sum with a "small" number of terms to avoid
28 | //! overflow.
29 |
30 | pub mod add;
31 | pub mod constants;
32 | pub mod den;
33 | pub mod div;
34 | pub mod inner_product;
35 | pub mod instruction;
36 | pub mod mul;
37 | pub mod mul_const;
38 | pub mod ops;
39 | pub mod parameters;
40 | pub mod register;
41 | pub mod sub;
42 | mod util;
43 |
--------------------------------------------------------------------------------
/starkyx/src/chip/field/ops.rs:
--------------------------------------------------------------------------------
1 | use super::instruction::FromFieldInstruction;
2 | use super::parameters::FieldParameters;
3 | use super::register::FieldRegister;
4 | use crate::machine::builder::ops::{Add, Div, Mul, One, Sub, Zero};
5 | use crate::machine::builder::Builder;
6 |
7 | impl Add for FieldRegister
8 | where
9 | B::Instruction: FromFieldInstruction
,
10 | {
11 | type Output = Self;
12 |
13 | fn add(self, rhs: Self, builder: &mut B) -> Self::Output {
14 | builder.api().fp_add(&self, &rhs)
15 | }
16 | }
17 |
18 | impl Sub for FieldRegister
19 | where
20 | B::Instruction: FromFieldInstruction
,
21 | {
22 | type Output = Self;
23 |
24 | fn sub(self, rhs: Self, builder: &mut B) -> Self::Output {
25 | builder.api().fp_sub(&self, &rhs)
26 | }
27 | }
28 |
29 | impl Mul for FieldRegister
30 | where
31 | B::Instruction: FromFieldInstruction
,
32 | {
33 | type Output = Self;
34 |
35 | fn mul(self, rhs: Self, builder: &mut B) -> Self::Output {
36 | builder.api().fp_mul(&self, &rhs)
37 | }
38 | }
39 |
40 | impl Div for FieldRegister
41 | where
42 | B::Instruction: FromFieldInstruction
,
43 | {
44 | type Output = Self;
45 |
46 | fn div(self, rhs: Self, builder: &mut B) -> Self::Output {
47 | builder.api().fp_div(&self, &rhs)
48 | }
49 | }
50 |
51 | impl Zero for FieldRegister
52 | where
53 | B::Instruction: FromFieldInstruction
,
54 | {
55 | type Output = Self;
56 |
57 | fn zero(builder: &mut B) -> Self::Output {
58 | builder.api().fp_zero()
59 | }
60 | }
61 |
62 | impl One for FieldRegister
63 | where
64 | B::Instruction: FromFieldInstruction
,
65 | {
66 | type Output = Self;
67 |
68 | fn one(builder: &mut B) -> Self::Output {
69 | builder.api().fp_one()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/starkyx/src/chip/field/parameters.rs:
--------------------------------------------------------------------------------
1 | use core::fmt::Debug;
2 |
3 | use num::bigint::RandBigInt;
4 | use num::{BigUint, Zero};
5 | use rand::rngs::OsRng;
6 | use serde::de::DeserializeOwned;
7 | use serde::Serialize;
8 |
9 | pub const MAX_NB_LIMBS: usize = 32;
10 | pub const LIMB: u32 = 2u32.pow(16);
11 |
12 | pub trait FieldParameters:
13 | Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + Default
14 | {
15 | const NB_BITS_PER_LIMB: usize;
16 | const NB_LIMBS: usize;
17 | const NB_WITNESS_LIMBS: usize;
18 | const MODULUS: [u16; MAX_NB_LIMBS];
19 | const WITNESS_OFFSET: usize;
20 |
21 | fn modulus() -> BigUint {
22 | let mut modulus = BigUint::zero();
23 | for (i, limb) in Self::MODULUS.iter().enumerate() {
24 | modulus += BigUint::from(*limb) << (16 * i);
25 | }
26 | modulus
27 | }
28 |
29 | fn nb_bits() -> usize {
30 | Self::NB_BITS_PER_LIMB * Self::NB_LIMBS
31 | }
32 |
33 | fn rand() -> BigUint {
34 | OsRng.gen_biguint_below(&Self::modulus())
35 | }
36 | }
37 |
38 | #[cfg(test)]
39 | pub mod tests {
40 | use num::One;
41 | use serde::Deserialize;
42 |
43 | use super::*;
44 |
45 | #[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)]
46 | pub struct Fp25519;
47 |
48 | impl FieldParameters for Fp25519 {
49 | const NB_BITS_PER_LIMB: usize = 16;
50 | const NB_LIMBS: usize = 16;
51 | const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2;
52 | const MODULUS: [u16; MAX_NB_LIMBS] = [
53 | 65517, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
54 | 65535, 65535, 65535, 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 | ];
56 | const WITNESS_OFFSET: usize = 1usize << 21;
57 |
58 | fn modulus() -> BigUint {
59 | (BigUint::one() << 255) - BigUint::from(19u32)
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/starkyx/src/chip/field/util.rs:
--------------------------------------------------------------------------------
1 | use num::BigUint;
2 |
3 | use super::parameters::FieldParameters;
4 | use crate::math::prelude::*;
5 | use crate::polynomial::parser::PolynomialParser;
6 | use crate::polynomial::Polynomial;
7 |
8 | pub fn eval_field_operation(
9 | parser: &mut AP,
10 | p_vanishing: &Polynomial,
11 | p_witness_low: &Polynomial,
12 | p_witness_high: &Polynomial,
13 | ) {
14 | // Reconstruct and shift back the witness polynomial
15 | let limb_field = AP::Field::from_canonical_u32(2u32.pow(16));
16 | let limb = parser.constant(limb_field);
17 |
18 | let p_witness_high_mul_limb = parser.poly_scalar_mul(p_witness_high, &limb);
19 | let p_witness_shifted = parser.poly_add(p_witness_low, &p_witness_high_mul_limb);
20 |
21 | // Shift down the witness polynomial. Shifting is needed to range check that each
22 | // coefficient w_i of the witness polynomial satisfies |w_i| < 2^20.
23 | let offset = AP::Field::from_canonical_u32(P::WITNESS_OFFSET as u32);
24 | let offset = parser.constant(offset);
25 | let p_witness = parser.poly_scalar_sub(&p_witness_shifted, &offset);
26 |
27 | // Multiply by (x-2^16) and make the constraint
28 | let root_monomial = Polynomial::from_coefficients(vec![-limb_field, AP::Field::ONE]);
29 | let p_witness_mul_root = parser.poly_mul_poly_const(&p_witness, &root_monomial);
30 |
31 | let constraints = parser.poly_sub(p_vanishing, &p_witness_mul_root);
32 | for constr in constraints.coefficients {
33 | parser.constraint(constr);
34 | }
35 | }
36 |
37 | pub fn modulus_field_iter() -> impl Iterator- {
38 | P::MODULUS
39 | .into_iter()
40 | .map(|x| F::from_canonical_u16(x))
41 | .take(P::NB_LIMBS)
42 | }
43 |
44 | #[inline]
45 | pub fn compute_root_quotient_and_shift(
46 | p_vanishing: &Polynomial,
47 | offset: usize,
48 | ) -> Vec {
49 | // Evaluate the vanishing polynomial at x = 2^16.
50 | let p_vanishing_eval = p_vanishing
51 | .coefficients()
52 | .iter()
53 | .enumerate()
54 | .map(|(i, x)| F::from_noncanonical_biguint(BigUint::from(2u32).pow(16 * i as u32)) * *x)
55 | .sum::();
56 | debug_assert_eq!(p_vanishing_eval, F::ZERO);
57 |
58 | // Compute the witness polynomial by witness(x) = vanishing(x) / (x - 2^16).
59 | let root_monomial = F::from_canonical_u32(2u32.pow(16));
60 | let p_quotient = p_vanishing.root_quotient(root_monomial);
61 | debug_assert_eq!(p_quotient.degree(), p_vanishing.degree() - 1);
62 |
63 | // Sanity Check #1: For all i, |w_i| < 2^20 to prevent overflows.
64 | let offset_u64 = offset as u64;
65 |
66 | // Sanity Check #2: w(x) * (x - 2^16) = vanishing(x).
67 | let x_minus_root = Polynomial::::from_coefficients_slice(&[-root_monomial, F::ONE]);
68 | debug_assert_eq!(
69 | (&p_quotient * &x_minus_root).coefficients(),
70 | p_vanishing.coefficients()
71 | );
72 |
73 | // Shifting the witness polynomial to make it positive
74 | p_quotient
75 | .coefficients()
76 | .iter()
77 | .map(|x| *x + F::from_canonical_u64(offset_u64))
78 | .collect::>()
79 | }
80 |
--------------------------------------------------------------------------------
/starkyx/src/chip/instruction/bit.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 |
3 | use super::ConstraintInstruction;
4 | use crate::air::parser::AirParser;
5 | use crate::air::AirConstraint;
6 | use crate::chip::register::memory::MemorySlice;
7 | use crate::math::prelude::*;
8 |
9 | #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
10 | pub struct BitConstraint(pub MemorySlice);
11 |
12 | impl ConstraintInstruction for BitConstraint {}
13 |
14 | impl AirConstraint for BitConstraint {
15 | fn eval(&self, parser: &mut AP) {
16 | let bit_constraint = |bit: AP::Var, parser: &mut AP| {
17 | let bit_minus_one = parser.sub_const(bit, AP::Field::ONE);
18 | let constraint = parser.mul(bit, bit_minus_one);
19 | parser.constraint(constraint);
20 | };
21 |
22 | let bits = self.0.eval_slice(parser).to_vec();
23 | for bit in bits {
24 | bit_constraint(bit, parser);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/starkyx/src/chip/instruction/clock.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 |
3 | use super::Instruction;
4 | use crate::air::parser::AirParser;
5 | use crate::air::AirConstraint;
6 | use crate::chip::register::element::ElementRegister;
7 | use crate::chip::register::{Register, RegisterSerializable};
8 | use crate::chip::trace::writer::{AirWriter, TraceWriter};
9 | use crate::math::prelude::*;
10 |
11 | #[derive(Debug, Clone, Serialize, Deserialize)]
12 | pub struct ClockInstruction {
13 | pub(crate) clk: ElementRegister,
14 | }
15 |
16 | impl AirConstraint for ClockInstruction {
17 | fn eval(&self, parser: &mut AP) {
18 | let clk = self.clk.eval(parser);
19 | let clk_next = self.clk.next().eval(parser);
20 |
21 | parser.constraint_first_row(clk);
22 |
23 | let mut transition = parser.sub(clk_next, clk);
24 | transition = parser.sub_const(transition, AP::Field::ONE);
25 | parser.constraint_transition(transition);
26 | }
27 | }
28 |
29 | impl Instruction for ClockInstruction {
30 | fn write(&self, writer: &TraceWriter, row_index: usize) {
31 | let value = F::from_canonical_usize(row_index);
32 | writer.write(&self.clk, &value, row_index);
33 | }
34 |
35 | fn write_to_air(&self, writer: &mut impl AirWriter) {
36 | let value = F::from_canonical_usize(writer.row_index().unwrap());
37 | writer.write(&self.clk, &value);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/starkyx/src/chip/instruction/empty.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 |
3 | use super::Instruction;
4 | use crate::air::parser::AirParser;
5 | use crate::air::AirConstraint;
6 | use crate::chip::trace::writer::{AirWriter, TraceWriter};
7 | use crate::math::prelude::*;
8 |
9 | /// A defult instruction set that contains no custom instructions
10 | #[derive(Clone, Debug, Serialize, Deserialize)]
11 | pub struct EmptyInstruction {
12 | _marker: core::marker::PhantomData,
13 | }
14 |
15 | impl Instruction for EmptyInstruction {
16 | fn write(&self, _writer: &TraceWriter, _row_index: usize) {}
17 |
18 | fn write_to_air(&self, _writer: &mut impl AirWriter) {}
19 | }
20 |
21 | impl> AirConstraint for EmptyInstruction {
22 | fn eval(&self, _parser: &mut AP) {}
23 | }
24 |
--------------------------------------------------------------------------------
/starkyx/src/chip/instruction/mod.rs:
--------------------------------------------------------------------------------
1 | use core::fmt::Debug;
2 |
3 | use serde::{Deserialize, Serialize};
4 |
5 | use super::trace::writer::AirWriter;
6 | use crate::chip::trace::writer::TraceWriter;
7 | use crate::math::prelude::*;
8 |
9 | pub mod assign;
10 | pub mod bit;
11 | pub mod clock;
12 | pub mod cycle;
13 | pub mod empty;
14 | pub mod set;
15 |
16 | pub trait Instruction:
17 | 'static + Send + Sync + Clone + Debug + Serialize + for<'de> Deserialize<'de>
18 | {
19 | /// Writes the instruction to the trace.
20 | fn write(&self, writer: &TraceWriter, row_index: usize);
21 |
22 | #[allow(unused_variables)]
23 | // Writes the instruction to a general AirWriter.
24 | fn write_to_air(&self, writer: &mut impl AirWriter);
25 | }
26 |
27 | /// An instruction that only consists of constraints
28 | pub trait ConstraintInstruction:
29 | 'static + Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>
30 | {
31 | }
32 |
33 | impl Instruction for C {
34 | fn write(&self, _writer: &TraceWriter, _row_index: usize) {}
35 |
36 | fn write_to_air(&self, _writer: &mut impl AirWriter) {}
37 | }
38 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/instruction.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 |
3 | use super::get::GetInstruction;
4 | use super::set::SetInstruction;
5 | use super::time::Time;
6 | use super::watch::WatchInstruction;
7 | use crate::air::parser::AirParser;
8 | use crate::air::AirConstraint;
9 | use crate::chip::instruction::Instruction;
10 | use crate::chip::register::element::ElementRegister;
11 | use crate::chip::trace::writer::{AirWriter, TraceWriter};
12 | use crate::math::field::Field;
13 |
14 | #[derive(Debug, Clone, Serialize, Deserialize)]
15 | pub enum MemoryInstruction {
16 | Get(GetInstruction),
17 | Set(SetInstruction),
18 | Watch(WatchInstruction),
19 | }
20 |
21 | #[derive(Debug, Clone, Serialize, Deserialize)]
22 | pub struct MemoryOutput {
23 | pub label: String,
24 | pub index: Option,
25 | pub ts: Time,
26 | }
27 |
28 | #[derive(Debug, Clone, Serialize, Deserialize)]
29 | pub enum MemorySliceIndex {
30 | /// The index of the memory slice.
31 | Index(usize),
32 | /// The index of the memory slice and the index of the element within the slice.
33 | IndexElement(ElementRegister),
34 | }
35 |
36 | impl AirConstraint for MemoryInstruction {
37 | fn eval(&self, parser: &mut AP) {
38 | match self {
39 | Self::Get(instr) => instr.eval(parser),
40 | Self::Set(instr) => instr.eval(parser),
41 | Self::Watch(instr) => instr.eval(parser),
42 | }
43 | }
44 | }
45 |
46 | impl Instruction for MemoryInstruction {
47 | fn write(&self, writer: &TraceWriter, row_index: usize) {
48 | match self {
49 | Self::Get(instr) => instr.write(writer, row_index),
50 | Self::Set(instr) => instr.write(writer, row_index),
51 | Self::Watch(instr) => instr.write(writer, row_index),
52 | }
53 | }
54 |
55 | fn write_to_air(&self, writer: &mut impl AirWriter) {
56 | match self {
57 | Self::Get(instr) => instr.write_to_air(writer),
58 | Self::Set(instr) => instr.write_to_air(writer),
59 | Self::Watch(instr) => instr.write_to_air(writer),
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/map.rs:
--------------------------------------------------------------------------------
1 | use core::hash::Hash;
2 | use std::collections::HashMap;
3 |
4 | use serde::{Deserialize, Serialize};
5 |
6 | use super::pointer::key::RawPointerKey;
7 |
8 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9 | pub struct MemEntry {
10 | pub value: Vec,
11 | pub multiplicity: T,
12 | }
13 |
14 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15 | pub struct MemoryMap(pub(crate) HashMap, MemEntry>);
16 |
17 | impl MemoryMap {
18 | pub fn new() -> Self {
19 | Self(HashMap::new())
20 | }
21 |
22 | pub fn get(&self, ptr: &RawPointerKey) -> Option<&MemEntry> {
23 | self.0.get(ptr)
24 | }
25 |
26 | pub fn remove(&mut self, ptr: &RawPointerKey) -> Option> {
27 | self.0.remove(ptr)
28 | }
29 |
30 | pub fn insert(&mut self, ptr: RawPointerKey, value: MemEntry) {
31 | self.0.insert(ptr, value);
32 | }
33 |
34 | pub fn get_mut(&mut self, ptr: &RawPointerKey) -> Option<&mut MemEntry> {
35 | self.0.get_mut(ptr)
36 | }
37 | }
38 |
39 | impl Default for MemoryMap {
40 | fn default() -> Self {
41 | Self::new()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod builder;
2 | pub mod get;
3 | pub mod instruction;
4 | pub mod map;
5 | pub mod pointer;
6 | pub mod set;
7 | pub mod time;
8 | pub mod value;
9 | pub mod watch;
10 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/pointer/key.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 |
3 | use crate::chip::register::cubic::CubicRegister;
4 |
5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
6 | pub struct RawPointerKey {
7 | pub challenge: CubicRegister,
8 | pub shift: T,
9 | }
10 |
11 | impl RawPointerKey {
12 | pub(crate) fn new(challenge: CubicRegister, shift: T) -> Self {
13 | Self { challenge, shift }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/pointer/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod accumulate;
2 | pub mod key;
3 | pub mod raw;
4 | pub mod slice;
5 | mod typed;
6 |
7 | pub use typed::Pointer;
8 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/pointer/slice.rs:
--------------------------------------------------------------------------------
1 | use core::marker::PhantomData;
2 |
3 | use super::super::value::MemoryValue;
4 | use super::raw::RawPointer;
5 | use super::Pointer;
6 | use crate::chip::builder::AirBuilder;
7 | use crate::chip::register::array::ArrayRegister;
8 | use crate::chip::register::cubic::CubicRegister;
9 | use crate::chip::register::element::ElementRegister;
10 | use crate::chip::AirParameters;
11 |
12 | #[derive(Clone, Debug)]
13 | pub struct RawSlice {
14 | powers: ArrayRegister,
15 | }
16 |
17 | #[derive(Clone, Debug)]
18 | pub struct Slice {
19 | raw: RawSlice,
20 | challenges: ArrayRegister,
21 | _marker: PhantomData,
22 | }
23 |
24 | impl Slice {
25 | pub fn new(raw_slice: RawSlice, challenges: ArrayRegister) -> Self {
26 | Self {
27 | raw: raw_slice,
28 | challenges,
29 | _marker: PhantomData,
30 | }
31 | }
32 |
33 | pub fn get(&self, idx: usize) -> Pointer {
34 | let raw = self.raw.get(idx);
35 | Pointer::new(raw, self.challenges)
36 | }
37 |
38 | pub fn get_at(&self, idx: ElementRegister) -> Pointer {
39 | let raw = self.raw.get_at(idx);
40 | Pointer::new(raw, self.challenges)
41 | }
42 |
43 | pub fn get_at_shifted(&self, idx: ElementRegister, shift: i32) -> Pointer {
44 | let raw = self.raw.get_at_shifted(idx, shift);
45 | Pointer::new(raw, self.challenges)
46 | }
47 | }
48 |
49 | impl RawSlice {
50 | pub(crate) fn get(&self, idx: usize) -> RawPointer {
51 | assert!(idx <= i32::MAX as usize);
52 | RawPointer::new(self.powers, None, Some(idx as i32))
53 | }
54 |
55 | pub(crate) fn new(builder: &mut AirBuilder) -> Self {
56 | let powers = builder.challenge_powers(3);
57 |
58 | Self { powers }
59 | }
60 |
61 | pub(crate) fn get_at(&self, idx: ElementRegister) -> RawPointer {
62 | RawPointer::new(self.powers, Some(idx), None)
63 | }
64 |
65 | pub(crate) fn get_at_shifted(&self, idx: ElementRegister, shift: i32) -> RawPointer {
66 | RawPointer::new(self.powers, Some(idx), Some(shift))
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/pointer/typed.rs:
--------------------------------------------------------------------------------
1 | use core::marker::PhantomData;
2 |
3 | use super::raw::RawPointer;
4 | use crate::chip::register::array::ArrayRegister;
5 | use crate::chip::register::cubic::CubicRegister;
6 |
7 | /// A pointer emulating a mutable reference to a data of register type `T`.
8 | #[derive(Debug, Clone, Copy)]
9 | pub struct Pointer {
10 | pub raw: RawPointer,
11 | pub challenges: ArrayRegister,
12 | _marker: PhantomData,
13 | }
14 |
15 | impl Pointer {
16 | pub fn new(raw_ptr: RawPointer, challenges: ArrayRegister) -> Self {
17 | Self {
18 | raw: raw_ptr,
19 | challenges,
20 | _marker: PhantomData,
21 | }
22 | }
23 |
24 | pub(crate) fn from_challenges(
25 | raw_ptr_challenge_powers: ArrayRegister,
26 | compression_challenges: ArrayRegister,
27 | ) -> Self {
28 | Self::new(
29 | RawPointer::from_challenge(raw_ptr_challenge_powers),
30 | compression_challenges,
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/time.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 |
3 | use crate::chip::arithmetic::expression::ArithmeticExpression;
4 | use crate::chip::register::element::ElementRegister;
5 | use crate::chip::register::Register;
6 | use crate::math::prelude::*;
7 |
8 | /// A register that stores a timestamp.
9 | pub type Time = TimeStamp>;
10 |
11 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12 | pub struct TimeStamp(pub(crate) T);
13 |
14 | impl TimeStamp {
15 | pub(crate) fn new(value: T) -> Self {
16 | Self(value)
17 | }
18 | }
19 |
20 | impl Time {
21 | pub fn zero() -> Self {
22 | Self::new(ArithmeticExpression::zero())
23 | }
24 |
25 | pub fn constant(value: usize) -> Self {
26 | Self::new(ArithmeticExpression::from(F::from_canonical_usize(value)))
27 | }
28 |
29 | pub fn from_element(element: ElementRegister) -> Self {
30 | Self::new(element.expr())
31 | }
32 |
33 | pub fn expr(&self) -> ArithmeticExpression {
34 | self.0.clone()
35 | }
36 |
37 | pub fn advance_by(&self, interval: usize) -> Self {
38 | Self::new(self.0.clone() + ArithmeticExpression::from(F::from_canonical_usize(interval)))
39 | }
40 |
41 | pub fn advance(&self) -> Self {
42 | self.advance_by(1)
43 | }
44 |
45 | pub fn decrement_by(&self, interval: usize) -> Self {
46 | Self::new(self.0.clone() - ArithmeticExpression::from(F::from_canonical_usize(interval)))
47 | }
48 |
49 | pub fn decrement(&self) -> Self {
50 | self.decrement_by(1)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/value.rs:
--------------------------------------------------------------------------------
1 | use super::pointer::raw::RawPointer;
2 | use super::time::Time;
3 | use crate::chip::builder::AirBuilder;
4 | use crate::chip::register::array::ArrayRegister;
5 | use crate::chip::register::cubic::CubicRegister;
6 | use crate::chip::register::Register;
7 | use crate::chip::AirParameters;
8 |
9 | pub trait MemoryValue: Register {
10 | fn num_challenges() -> usize;
11 |
12 | fn compress(
13 | &self,
14 | builder: &mut AirBuilder,
15 | ptr: RawPointer,
16 | time: &Time,
17 | challenges: &ArrayRegister,
18 | ) -> CubicRegister;
19 | }
20 |
--------------------------------------------------------------------------------
/starkyx/src/chip/memory/watch.rs:
--------------------------------------------------------------------------------
1 | use log::debug;
2 | use serde::{Deserialize, Serialize};
3 |
4 | use super::pointer::raw::RawPointer;
5 | use crate::air::parser::AirParser;
6 | use crate::air::AirConstraint;
7 | use crate::chip::instruction::Instruction;
8 | use crate::chip::trace::writer::{AirWriter, TraceWriter};
9 | use crate::math::prelude::*;
10 |
11 | #[derive(Debug, Clone, Serialize, Deserialize)]
12 | pub struct WatchInstruction {
13 | ptr: RawPointer,
14 | name: String,
15 | }
16 |
17 | impl AirConstraint for WatchInstruction {
18 | // No constraints for this instruction.
19 | fn eval(&self, _parser: &mut AP) {}
20 | }
21 |
22 | impl Instruction for WatchInstruction {
23 | fn write(&self, writer: &TraceWriter, row_index: usize) {
24 | let mut memory = writer.memory_mut().unwrap();
25 | let key = self.ptr.read(writer, row_index);
26 | let entry_option = memory.get_mut(&key);
27 |
28 | if let Some(entry) = entry_option {
29 | debug!(
30 | "row {}: , {}: value: {:?}, multiplicities: {:?}",
31 | row_index, self.name, entry.value, entry.multiplicity
32 | );
33 | } else {
34 | debug!(
35 | "row {:?}: , {}: value: Uninitialized, multiplicities: Uninitialized",
36 | row_index, self.name,
37 | );
38 | }
39 | }
40 |
41 | fn write_to_air(&self, writer: &mut impl AirWriter) {
42 | let key = self.ptr.read_from_air(writer);
43 | let row_num = if let Some(row_index) = writer.row_index() {
44 | row_index.to_string()
45 | } else {
46 | "None".to_string()
47 | };
48 | let entry_option = writer.memory_mut().get_mut(&key);
49 |
50 | if let Some(entry) = entry_option {
51 | debug!(
52 | "row {}: , {}: value: {:?}, multiplicities: {:?}",
53 | row_num, self.name, entry.value, entry.multiplicity
54 | );
55 | } else {
56 | debug!(
57 | "row {}: , {}: value: Uninitialized, multiplicities: Uninitialized",
58 | row_num, self.name,
59 | )
60 | };
61 | }
62 | }
63 |
64 | impl WatchInstruction {
65 | pub fn new(ptr: RawPointer, name: String) -> Self {
66 | Self { ptr, name }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/starkyx/src/chip/mod.rs:
--------------------------------------------------------------------------------
1 | use serde::de::DeserializeOwned;
2 | use serde::{Deserialize, Serialize};
3 |
4 | use self::constraint::Constraint;
5 | use self::instruction::Instruction;
6 | use crate::math::prelude::*;
7 | use crate::plonky2::stark::Starky;
8 |
9 | pub mod air;
10 | pub mod arithmetic;
11 | pub mod bool;
12 | pub mod builder;
13 | pub mod constraint;
14 | pub mod ec;
15 | pub mod field;
16 | pub mod instruction;
17 | pub mod memory;
18 | pub mod register;
19 | pub mod table;
20 | pub mod trace;
21 | pub mod uint;
22 | pub mod utils;
23 |
24 | use core::fmt::Debug;
25 | pub trait AirParameters:
26 | 'static + Clone + Send + Sync + Sized + Debug + Serialize + DeserializeOwned
27 | {
28 | type Field: PrimeField64;
29 |
30 | type CubicParams: CubicParameters