Skip to content

Commit

Permalink
air (#2)
Browse files Browse the repository at this point in the history
* air notes and minor mods

* trace notes and conversion traits
  • Loading branch information
thor314 committed Sep 15, 2023
1 parent db23183 commit ad892ce
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 36 deletions.
39 changes: 33 additions & 6 deletions air/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
# Air implementation
Referencing the [starkware C++ implementation](https://github.com/starkware-libs/stone-prover/tree/main/src/starkware/air).

Progress:
- [x] some things
- [ ] components
- [ ] cpu
- [ ] compile_time_optional - maybe C++ fonkery, perhaps necessary in Rust
- [ ] everything else
Initial migration:
- 9/10 air.h
- 0/10 compile_time_optional* - maybe C++ fonkery, perhaps necessary in Rust
- 2/10 test_utils*
- 9/10 trace.h - ask a human
- 10/10 trace_context.h
- 0/10 trace_test.cc


## Air notes
- translating `Air` to a trait, this seems reasonable as `Air` is mostly an ABC
- can't represent the C++ constructor check in trait, which would require modifying struct state (trace_length)
- `CompositionPolynomial` in C++ implementation simply stores a unit struct pointer, I suspect this should be `composition_polynomial::CompositionPolynomial`


### Compile Time Optional notes
this looks like optimization territory

### test_utils
we'll get back to this when implementing tests for the module and stub it out for now

### Trace notes
`Trace` seems like a struct, no virtual methods. Custom copy constructor, default move constructor, default destructor, default {copy,move} assignment. Weird logic around copy, might be a bug on theirs. This file has a lot of odd boilerplate logic that I might want to talk to a human about.
- mapping `Allocate` to `new`
- Trace constructor - mapping to `From<Vec<Vec<F>>>`
- `CopyFrom` - ths looks to have a minor inefficiency, calling `values.size()` instead of `values.Length()`;

#### Trace context
this looks like a pretty useless trait, candidate for erasure

#### Trace test
come back later

5 changes: 4 additions & 1 deletion air/src/boundary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::collections::{HashMap, VecDeque};

use algebra::ConstFieldElementSpan;
use ark_ff::Field;
use composition_polynomial::CompositionPolynomial;

use crate::{assert_on_release, Air};

Expand Down Expand Up @@ -126,7 +127,7 @@ impl<F: Field> Air<F> for BoundaryAir<F> {
&self,
trace_generator: &F,
random_coefficients: &ConstFieldElementSpan<F>,
) -> Box<dyn crate::TmpCompositionPolynomial<F>> {
) -> Box<CompositionPolynomial<F>> {
// todo(tk): builder is a bad name for a builder of CompositionPolynomial, commenting until
// farther into refactor
//
Expand All @@ -143,6 +144,8 @@ impl<F: Field> Air<F> for BoundaryAir<F> {
fn get_interaction_params(&self) -> Option<crate::InteractionParams> { None }

fn num_columns(&self) -> usize { self.num_columns }

fn trace_length(&self) -> usize { todo!() }
}

/// List of tuples (column, x, y) indicating the constraint that column(x)=y.
Expand Down
49 changes: 30 additions & 19 deletions air/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,25 @@ use std::{collections::HashMap, option::Option, vec::Vec};

use algebra::{ConstFieldElementSpan, FieldElementVector};
use ark_ff::Field;
use composition_polynomial::CompositionPolynomial;

/// Temporary type while I figure out what to do with gsl::span
pub type TempGslSpan<T> = Vec<T>;

// todo(tk): import this from composition_polynomial
pub trait TmpCompositionPolynomial<F: Field> {}
// pub trait TmpCompositionPolynomial<F: Field> {}

// doc(tk)
///
pub trait Air<F: Field> {
/// Creates a CompositionPolynomial object based on the given (verifier-chosen) coefficients.
fn create_composition_polynomial(
&self,
trace_generator: &F,
random_coefficients: &ConstFieldElementSpan<F>,
// refactor(tk): dyn bad
) -> Box<dyn TmpCompositionPolynomial<F>>;
) -> Box<CompositionPolynomial<F>>;

fn trace_length(&self) -> usize;

/// Default to zero
fn get_composition_polynomial_degree_bound(&self) -> usize;
Expand All @@ -40,15 +43,29 @@ pub trait Air<F: Field> {
/// order to maintain soundness.
fn num_random_coefficients(&self) -> usize;

/// Returns the interaction parameters.
/// If there is no interaction, returns None.
fn get_interaction_params(&self) -> Option<InteractionParams>;
// refactor(tk): redundant?
fn get_num_constraints(&self) -> usize { self.num_random_coefficients() }

// get mask

/// helper for `get_n_columns_first`
fn num_columns(&self) -> usize;

// refactor(tk): redundant?
fn get_num_constraints(&self) -> usize { self.num_random_coefficients() }
/// When the AIR has interaction (i.e. for debugging and testing), clones the AIR and updates its
/// interaction elements. Returns the cloned AIR. Otherwise, this function shouldn't be used.
// todo: unsure how this is used, ignore for now
// refactor(tk): non-idiomatic rust
fn with_interaction_elements(
&self,
interaction_elms: &algebra::FieldElementVector<F>,
) -> Box<dyn Air<F>> {
assert_on_release(false, "Calling WithInteractionElements in an Air with no interaction.");
unreachable!()
}

/// Returns the interaction parameters.
/// If there is no interaction, returns None.
fn get_interaction_params(&self) -> Option<InteractionParams>;

/// If air has interaction, returns the number of columns in the first trace;
/// otherwise, returns the total number of columns.
Expand All @@ -59,14 +76,9 @@ pub trait Air<F: Field> {
}
}

/// When the AIR has interaction (i.e. for debugging and testing), clones the AIR and updates its
/// interaction elements. Returns the cloned AIR. Otherwise, this function shouldn't be used.
// todo: unsure how this is used, ignore for now
// refactor(tk): dyn bad
fn with_interaction_elements(&self, interaction_elms: &algebra::FieldElementVector) {
assert_on_release(false, "Calling WithInteractionElements in an air with no interaction.");
todo!()
}
// todo(tk): verify ok to drop ths
// protected:
// uint64_t trace_length_;
}

/// Helper NewType for the `get_mask` of the Air.
Expand All @@ -76,9 +88,8 @@ pub struct AirMask(pub Vec<(i64, u64)>);
/// Stores data relevant to the interaction.
pub struct InteractionParams {
// Number of columns in first and second trace.
pub n_columns_first: usize,
pub n_columns_second: usize,

pub n_columns_first: usize,
pub n_columns_second: usize,
// Number of interaction random elements.
pub n_interaction_elements: usize,
}
Expand Down
35 changes: 29 additions & 6 deletions air/src/trace.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
//! https://github.com/starkware-libs/stone-prover/blob/a78ff37c1402dc9c3e3050a1090cd98b7ff123b3/src/starkware/air/trace.h

use algebra::FieldElementVector;
use ark_ff::Field;
use composition_polynomial::TempGslSpan;

// todo: update with algebra::polymorphic::FieldElementVector
#[derive(Clone)]
// doc(tk)
#[derive(Clone, Default)]
pub struct Trace<F: Field> {
values: Vec<Vec<F>>,
values: Vec<FieldElementVector<F>>,
/// length of the Trace
pub length: usize,
/// width of the Trace
pub width: usize,
}

impl<F: Field> Trace<F> {
pub fn new(n_columns: usize, trace_length: usize) -> Self {
// todo(tk): check that this is equivalent: FieldElementT::UninitializedVector(trace_length))
let values = (0..n_columns).map(|_| Vec::with_capacity(trace_length)).collect();
let values = (0..n_columns).map(|_| Vec::with_capacity(trace_length).into()).collect();
Self { values, length: trace_length, width: n_columns }
}

Expand All @@ -30,10 +33,30 @@ impl<F: Field> Trace<F> {

impl<F: Field> From<Vec<Vec<F>>> for Trace<F> {
fn from(values: Vec<Vec<F>>) -> Self {
Self { length: values[0].len(), width: values.len(), values }
if values.is_empty() {
Trace::default()
} else {
let width = values.len();
let length = values[0].len();
let values: Vec<FieldElementVector<F>> = values.into_iter().map(|v| v.into()).collect();
Trace { width, length, values }
}
}
}

impl<F: Field> From<Vec<FieldElementVector<F>>> for Trace<F> {
fn from(values: Vec<FieldElementVector<F>>) -> Self {
if values.is_empty() {
Trace::default()
} else {
let width = values.len();
let length = values[0].0.len();
let values: Vec<FieldElementVector<F>> = values.into_iter().collect();
Trace { width, length, values }
}
}
}

impl<F: Field> From<Trace<F>> for Vec<TempGslSpan<F>> {
fn from(val: Trace<F>) -> Self { val.values.into_iter().collect() }
fn from(val: Trace<F>) -> Self { val.values.into_iter().map(|v| v.into()).collect() }
}
4 changes: 2 additions & 2 deletions air/src/trace_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ use crate::{assert_on_release, trace::Trace, Air};
pub trait TraceContext<F: Field> {
/// Updates AIR with given interaction elements if this AIR has an interaction. If not - throws an
/// error
fn set_interaction_elements(&mut self, _interaction_elms: &FieldElementVector) {
fn set_interaction_elements(&mut self, _interaction_elms: &FieldElementVector<F>) {
assert_on_release(false, "Calling set_interaction_elements in an AIR with no interaction.")
}

/// Create an interaction trace. In case the AIR does not have interaction, throw error or panic.
// todo(tk): update type sig: throw error or panic.
fn get_interaction_trace(&self) -> Trace<F>;

fn get_air(&self) -> &dyn Air<F> {
fn get_air(&self) -> Box<dyn Air<F>> {
assert_on_release(false, "GetAir is not implemented.");
unimplemented!();
}
Expand Down
31 changes: 29 additions & 2 deletions algebra/src/polymorphic/field_element_vector.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
use std::ops::{Deref, IndexMut, Index};

use ark_ff::Field;

/// A class representing a vector of FieldElement-s of a common field.
/// To create an instance call FieldElementVector::make().
pub struct FieldElementVector {
// todo
#[derive(Default, Clone)]
pub struct FieldElementVector<F: Field>(pub Vec<F>);

impl<F: Field> From<Vec<F>> for FieldElementVector<F> {
fn from(value: Vec<F>) -> Self { Self(value) }
}

impl<F: Field> Deref for FieldElementVector<F> {
type Target = Vec<F>;

fn deref(&self) -> &Self::Target { &self.0 }
}

impl<F: Field> Index<usize> for FieldElementVector<F> {
type Output = F;

fn index(&self, index: usize) -> &Self::Output { &self.0[index] }
}

impl<F: Field> IndexMut<usize> for FieldElementVector<F> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.0[index] }
}

impl<F: Field> From<FieldElementVector<F>> for Vec<F> {
fn from(value: FieldElementVector<F>) -> Self { value.0 }
}

0 comments on commit ad892ce

Please sign in to comment.