Skip to content

Commit

Permalink
Merge branch 'novifinancial:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Al-Kindi-0 authored May 11, 2022
2 parents 87310b4 + 46dce1a commit ec8063f
Show file tree
Hide file tree
Showing 104 changed files with 6,125 additions and 1,839 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.4.0 (2022-04-29)
* Added support for Randomized AIR (with example).
* Added support for custom number of transition constraint exemptions.
* Enabled transition constraints of degree *n + 1* when blowup factor is *n*.
* Moved trace and constraint commitment construction into separate functions in the `Prover` trait.
* Introduced `Matrix` struct in the prover which is used as a backing type for trace and constraint evaluations.
* Added `ExtensionOf` trait and implemented it for all supported fields.
* Sped up inversion in `f64` field by using inversion method based on Fermat’s little theorem.
* Implemented `Randomizable` trait for `u32`, `u16`, and `u8` types.
* [BREAKING] `AirContext::new()` now requires `num_assertions` parameter.
* [BREAKING] Various interface changes in the `Air` trait to support multi-segment traces.
* Increased min version of `rustc` to 1.60.

## 0.3.2 (2022-01-20) - crypto
* Implemented into byte conversion for Rp64_256 digest.
* Moved capacity elements to the front of the state for Rp64_256.
Expand Down
28 changes: 18 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<a href="https://github.com/novifinancial/winterfell/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
<img src="https://github.com/novifinancial/winterfell/workflows/CI/badge.svg?branch=main">
<a href="https://deps.rs/repo/github/novifinancial/winterfell"><img src="https://deps.rs/repo/github/novifinancial/winterfell/status.svg"></a>
<img src="https://img.shields.io/badge/prover-rustc_1.57+-lightgray.svg">
<img src="https://img.shields.io/badge/verifier-rustc_1.57+-lightgray.svg">
<img src="https://img.shields.io/badge/prover-rustc_1.60+-lightgray.svg">
<img src="https://img.shields.io/badge/verifier-rustc_1.60+-lightgray.svg">
<a href="https://crates.io/crates/winterfell"><img src="https://img.shields.io/crates/v/winterfell"></a>

A STARK prover and verifier for arbitrary computations.
Expand All @@ -21,7 +21,9 @@ The aim of this project is to build a feature-rich, easy to use, and highly perf

Winterfell is a fully-functional, multi-threaded STARK prover and verifier with the following nice properties:

**A simple interface.** This library provides a relatively simple interface for describing general computations. See [usage](#Usage) for a quick tutorial, [air crate](air) for the description of the interface, and [examples crate](examples) for a few real-world examples.
**A simple interface.** The library provides a relatively simple interface for describing general computations. See [usage](#Usage) for a quick tutorial, [air crate](air) for the description of the interface, and [examples crate](examples) for a few real-world examples.

**Randomized AIR support.** The library supports multi-stage trace commitments, which enables support for [randomized AIR](air/#randomized-air). This greatly increases the expressivity of AIR constraints, and enables, among other things, multiset and permutation checks similar to the ones available in PLONKish systems.

**Multi-threaded proof generation.** When compiled with `concurrent` feature enabled, the proof generation process will run in multiple threads. The library also supports concurrent construction of execution trace tables. The [performance](#Performance) section showcases the benefits of multi-threading.

Expand Down Expand Up @@ -89,19 +91,19 @@ First, we need to define an *execution trace* for our computation. This trace sh
| ... |
| 1,048,575 | 247770943907079986105389697876176586605 |

To record the trace, we'll use the `ExecutionTrace` struct provided by the library. The function below, is just a modified version of the `do_work()` function which records every intermediate state of the computation in the `ExecutionTrace` struct:
To record the trace, we'll use the `TraceTable` struct provided by the library. The function below, is just a modified version of the `do_work()` function which records every intermediate state of the computation in the `TraceTable` struct:

```Rust
use winterfell::{
math::{fields::f128::BaseElement, FieldElement},
ExecutionTrace,
TraceTable,
};

pub fn build_do_work_trace(start: BaseElement, n: usize) -> ExecutionTrace<BaseElement> {
pub fn build_do_work_trace(start: BaseElement, n: usize) -> TraceTable<BaseElement> {
// Instantiate the trace with a given width and length; this will allocate all
// required memory for the trace
let trace_width = 1;
let mut trace = ExecutionTrace::new(trace_width, n);
let mut trace = TraceTable::new(trace_width, n);

// Fill the trace with data; the first closure initializes the first state of the
// computation; the second closure computes the next state of the computation based
Expand Down Expand Up @@ -164,8 +166,8 @@ impl Air for WorkAir {
type PublicInputs = PublicInputs;

// Here, we'll construct a new instance of our computation which is defined by 3 parameters:
// starting value, number of steps, and the end result. Another way to think about it is that
// an instance of our computation is a specific invocation of the do_work() function.
// starting value, number of steps, and the end result. Another way to think about it is
// that an instance of our computation is a specific invocation of the do_work() function.
fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: ProofOptions) -> Self {
// our execution trace should have only one column.
assert_eq!(1, trace_info.width());
Expand All @@ -176,8 +178,14 @@ impl Air for WorkAir {
// constraints don't match, an error will be thrown in the debug mode, but in release
// mode, an invalid proof will be generated which will not be accepted by any verifier.
let degrees = vec![TransitionConstraintDegree::new(3)];

// We also need to specify the exact number of assertions we will place against the
// execution trace. This number must be the same as the number of items in a vector
// returned from the get_assertions() method below.
let num_assertions = 2;

WorkAir {
context: AirContext::new(trace_info, degrees, options),
context: AirContext::new(trace_info, degrees, num_assertions, options),
start: pub_inputs.start,
result: pub_inputs.result,
}
Expand Down
16 changes: 8 additions & 8 deletions air/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[package]
name = "winter-air"
version = "0.3.0"
version = "0.4.0"
description = "AIR components for the Winterfell STARK prover/verifier"
authors = ["winterfell contributors"]
readme = "README.md"
license = "MIT"
repository = "https://github.com/novifinancial/winterfell"
documentation = "https://docs.rs/winter-air/0.3.0"
documentation = "https://docs.rs/winter-air/0.4.0"
categories = ["cryptography", "no-std"]
keywords = ["crypto", "arithmetization", "air"]
edition = "2021"
rust-version = "1.57"
rust-version = "1.60"

[lib]
bench = false
Expand All @@ -20,13 +20,13 @@ default = ["std"]
std = ["crypto/std", "fri/std", "math/std", "utils/std"]

[dependencies]
crypto = { version = "0.3", path = "../crypto", package = "winter-crypto", default-features = false }
fri = { version = "0.3", path = "../fri", package = "winter-fri", default-features = false }
math = { version = "0.3", path = "../math", package = "winter-math", default-features = false }
utils = { version = "0.3", path = "../utils/core", package = "winter-utils", default-features = false }
crypto = { version = "0.4", path = "../crypto", package = "winter-crypto", default-features = false }
fri = { version = "0.4", path = "../fri", package = "winter-fri", default-features = false }
math = { version = "0.4", path = "../math", package = "winter-math", default-features = false }
utils = { version = "0.4", path = "../utils/core", package = "winter-utils", default-features = false }

[dev-dependencies]
rand-utils = { version = "0.3", path = "../utils/rand", package = "winter-rand-utils" }
rand-utils = { version = "0.4", path = "../utils/rand", package = "winter-rand-utils" }

# Allow math in docs
[package.metadata.docs.rs]
Expand Down
24 changes: 17 additions & 7 deletions air/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ Keep in mind is that since transition constraints define algebraic relations, th
#### Constraint degrees
One of the main factors impacting proof generation time and proof size is the maximum degree of transition constraints. The higher is this degree, the larger our blowup factor needs to be. Usually, we want to keep this degree as low as possible - e.g. under 4 or 8. To accurately describe degrees of your transition constraints, keep the following in mind:

* All trace registers have degree `1`.
* When multiplying trace registers together, the degree increases by `1`. For example, if our constraint involves multiplication of two registers, the degree of this constraint will be `2`. We can describe this constraint using `TransitionConstraintDegree` struct as follows: `TransitionConstraintDegree::new(2)`.
* All trace columns have degree `1`.
* When multiplying trace columns together, the degree increases by `1`. For example, if our constraint involves multiplication of two columns, the degree of this constraint will be `2`. We can describe this constraint using `TransitionConstraintDegree` struct as follows: `TransitionConstraintDegree::new(2)`.
* Degrees of periodic columns depend on the length of their cycles, but in most cases, these degrees are very close to `1`.
* To describe a degree of a constraint involving multiplication of trace registers and periodic columns, use the `with_cycles()` constructor of `TransitionConstraintDegree` struct. For example, if our constraint involves multiplication of one trace register and one periodic column with a cycle of 32 steps, the degree can be described as: `TransitionConstraintDegree::with_cycles(1, vec![32])`.
* To describe a degree of a constraint involving multiplication of trace columns and periodic columns, use the `with_cycles()` constructor of `TransitionConstraintDegree` struct. For example, if our constraint involves multiplication of one trace column and one periodic column with a cycle of 32 steps, the degree can be described as: `TransitionConstraintDegree::with_cycles(1, vec![32])`.

In general, multiplications should be used judiciously - though, there are ways to ease this restriction a bit (check out [mulfib8](../examples/src/fibonacci/mulfib8/air.rs) example).

Expand All @@ -51,17 +51,27 @@ Assertions are used to specify that a valid execution trace of a computation mus

To define assertions for your computation, you'll need to implement `get_assertions()` function of the `Air` trait. Every computation must have at least one assertion. Assertions can be of the following types:

* A single assertion - such assertion specifies that a single cell of an execution trace must be equal to a specific value. For example: *value in register 0, step 0, must be equal to 1*.
* A periodic assertion - such assertion specifies that values in a given register at specified intervals should be equal to some values. For example: *values in register 0, steps 0, 8, 16, 24 etc. must be equal to 2*.
* A sequence assertion - such assertion specifies that values in a given register at specific intervals must be equal to a sequence of provided values. For example: *values in register 0, step 0 must be equal to 1, step 8 must be equal to 2, step 16 must be equal to 3 etc.*
* A single assertion - such assertion specifies that a single cell of an execution trace must be equal to a specific value. For example: *value in column 0, step 0, must be equal to 1*.
* A periodic assertion - such assertion specifies that values in a given column at specified intervals should be equal to some values. For example: *values in column 0, steps 0, 8, 16, 24 etc. must be equal to 2*.
* A sequence assertion - such assertion specifies that values in a given column at specific intervals must be equal to a sequence of provided values. For example: *values in column 0, step 0 must be equal to 1, step 8 must be equal to 2, step 16 must be equal to 3 etc.*

For more information on how to define assertions see the [assertions](src/air/assertions/mod.rs) module and check out the examples in the [examples crate](../examples).

### Periodic values
Sometimes, it may be useful to define a column in an execution trace which contains a set of repeating values. For example, let's say we have a register which contains value 1 on every 4th step, and 0 otherwise. Such a column can be described with a simple periodic sequence of `[1, 0, 0, 0]`.
Sometimes, it may be useful to define a column in an execution trace which contains a set of repeating values. For example, let's say we have a column which contains value 1 on every 4th step, and 0 otherwise. Such a column can be described with a simple periodic sequence of `[1, 0, 0, 0]`.

To define such columns for your computation, you can override `get_periodic_column_values()` method of the `Air` trait. The values of the periodic columns at a given step of the computation will be supplied to the `evaluate_transition()` method via the `periodic_values` parameter.

### Randomized AIR
Randomized AIR is a powerful extension of AIR which enables, among other things, multiset and permutation checks similar to the ones available in PLONKish systems. These, in turn, allow efficient descriptions of "non-local" constraints which can be used to build such components as efficient range checks, random access memory, and many others.

With Randomized AIR, construction of the execution trace is split into multiple stages. During the first stage, the *main trace segment* is built in a manner similar to how the trace is built for regular AIR. In the subsequent stages, *auxiliary trace segments* are built. When building auxiliary trace segments, the prover has access to extra randomness sent by the verifier (in the non-interactive version of the protocol, this randomness is derived from the previous trace segment commitments). Currently, the number of auxiliary trace segments is limited to one.

To describe Randomized AIR, you will need to do the following when implementing the `Air` trait:
* The `AirContext` struct returned from `Air::context()` method must be instantiated using `AirContext::new_multi_segment()` constructor. When building AIR context in this way, you will need to provide a `TraceLayout` which describes the shape of a multi-segment execution trace.
* Override `Air::evaluate_aux_transition()` method. This method is similar to the `Air::evaluate_transition()` method but it also accepts two extra parameters: `aux_evaluation_frame` and `aux_rand_elements`. These parameters are needed for evaluating transition constraints over the auxiliary trace segments.
* Override `Air::get_aux_assertions()` method. This method is similar to the `Air::get_assertions()` method, but it should return assertions against columns of the auxiliary trace segments.

## Protocol parameters
`ProofOptions` struct defines a set of options which are used during STARK proof generation and verification. These options have a direct impact on the security of the generated proofs as well as the proof generation time. Specifically, security of STARK proofs depends on:

Expand Down
Loading

0 comments on commit ec8063f

Please sign in to comment.