Skip to content

Commit

Permalink
Merge branch 'main' into riscv-executor-tmp-base
Browse files Browse the repository at this point in the history
  • Loading branch information
lvella committed Oct 11, 2023
2 parents 04a5743 + dc3cc0c commit b53d14f
Show file tree
Hide file tree
Showing 48 changed files with 1,483 additions and 1,075 deletions.
105 changes: 105 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
version: 2.1

jobs:
pr-tests:
machine:
image: ubuntu-2004:current
resource_class: large
steps:
- run:
name: Install dependencies
command: sudo apt update -qqy && sudo apt install libclang-dev git nodejs -qqy

- run:
name: Install Rust
command: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

- checkout

- run:
name: Install pilcom
command: git clone https://github.com/0xPolygonHermez/pilcom.git

- restore_cache:
name: Restore pilcom modules cache
keys:
- v5-pilcom-node-modules-{{ checksum "pilcom/package-lock.json" }}

- run:
name: Install pilcom node modules if cache miss
command: |
if [ ! -d "pilcom/node_modules" ]; then
(cd pilcom && npm install)
fi
- save_cache:
name: Save pilcom modules cache
key: v5-pilcom-node-modules-{{ checksum "pilcom/package-lock.json" }}
paths:
- pilcom/node_modules

- restore_cache:
name: Restore Rust cache
keys:
- v5-cargo-pr-tests-{{ checksum "Cargo.toml" }}

- run:
name: Install Rust toolchain 1.72 (with clippy and rustfmt)
command: |
rustup toolchain install 1.72-x86_64-unknown-linux-gnu
rustup component add clippy --toolchain 1.72-x86_64-unknown-linux-gnu
rustup component add rustfmt --toolchain 1.72-x86_64-unknown-linux-gnu
- run:
name: Install nightly
command: rustup toolchain install nightly-2023-01-03-x86_64-unknown-linux-gnu

- run:
name: Install riscv target
command: rustup target add riscv32imac-unknown-none-elf --toolchain nightly-2023-01-03-x86_64-unknown-linux-gnu

- run:
name: Install stdlib
command: rustup component add rust-src --toolchain nightly-2023-01-03-x86_64-unknown-linux-gnu

- run:
name: Check without Halo2
command: cargo check --all --no-default-features --profile pr-tests

- run:
name: Build
command: cargo build --all --all-features --profile pr-tests

- save_cache:
name: Save Rust cache
key: v5-cargo-pr-tests-{{ checksum "Cargo.toml" }}
paths:
- ~/.cargo/registry
- ~/.cargo/git
- target

- run:
name: Run default tests
command: PILCOM=$(pwd)/pilcom/ cargo test --all --all-features --profile pr-tests --verbose

- run:
name: Run slow tests
command: PILCOM=$(pwd)/pilcom/ cargo test --all --all-features --profile pr-tests --verbose -- --ignored --nocapture --test-threads=1 --exact test_keccak test_vec_median instruction_tests::addi

- run:
name: Lint
command: cargo clippy --all --all-features -- -D warnings

- run:
name: Format
command: cargo fmt --all --check --verbose

- run:
name: Check benches compile without running them
command: cargo bench --all --all-features --profile pr-tests --no-run

workflows:
version: 2
build-and-test:
jobs:
- pr-tests
35 changes: 17 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
<p align="center">
<img src="book/src/powdr_wires.png" width="600">
</p>

# powdr

[![Matrix Chat](https://img.shields.io/badge/Matrix%20-chat-brightgreen?style=plastic&logo=matrix)](https://matrix.to/#/#powdr:matrix.org)
[![Twitter Follow](https://img.shields.io/twitter/follow/powdr_labs?style=plastic&logo=twitter)](https://twitter.com/powdr_labs)<!-- markdown-link-check-disable-line -->

*powdr* is an extended polynomial identity (PIL) and zk-focused assembly (zkASM)
language written in Rust, focused on modularity and excellent developer experience.

WARNING: This is a proof-of-concept implementation. It is missing many internal checks. DO NOT USE FOR PRODUCTION!
> WARNING: This codebase is experimental and has not been audited. DO NOT USE FOR PRODUCTION!
## Basic Concept
For detailed documentation please visit [the powdr book](https://docs.powdr.org/).

*powdr* is a toolkit that helps build zkVMs and similar proof frameworks.

It has two main components:

- A polynomial identity language that allows you to define polynomial constraints, lookups, etc.
- An extensible assembly language to perform dynamic executions.
- powdr-asm: an extensible assembly IR language to perform dynamic executions.
- powdr-PIL: a low level constraint language that allows you to define arithmetic constraints, lookups, etc.

Both frontend and backend are highly flexible.

As an example, *powdr* contains a frontend that enables you to write code in (no-std) Rust,
which is compiled to RISCV, then to powdr-asm and finally to PIL.
which is compiled to RISCV, then to powdr-asm and finally to powdr-PIL.

*powdr*-pil can be used to generate proofs using multiple backends, such as:

- Halo2
- eSTARKs: *powdr*-pil is fully compatible with the eSTARKS backend from Polygon Hermez,
although not yet fully integrated in an automatic way.
- Nova: ongoing work.
- other STARKs: maybe?
- Halo2: via [polyexen](https://github.com/Dhole/polyexen) and [snark-verifer](https://github.com/privacy-scaling-explorations/snark-verifier/)
- eSTARK: via [Eigen's starky](https://github.com/0xEigenLabs/eigen-zkvm/)
- SuperNova: ongoing work (https://github.com/powdr-labs/powdr/pull/453)

All stages are fully automatic, which means you do not need to write any
additional code for witness generation besides your Rust code. All witnesses
Expand All @@ -37,18 +36,18 @@ inferred, *powdr* can ensure that the system is not underconstrained, i.e.
there are no additional unwanted witnesses.

All artifacts from the compilation pipeline are human-readable. This means you
can inspect the RISCV assembly files, the powdr-asm, and the PIL file.
can inspect the RISCV assembly files, the powdr-asm IR, and the compiled PIL file.

The assembly language is designed to be extensible. This means that it does not have a single
native instruction. Instead, all instructions are user-defined and because of that,
it is easy to adapt *powdr* assembly to any VM.

### Notes on Efficiency

Currently, the code is quite wasteful. It generates many unnecessary columns.
The idea is to first see if automatic witness generation is possible in general.
If this is confirmed, various optimizer stages will be built to reduce the
column (and row) count automatically.
The current focus of the project is VM support and developer experience. The
compiler generates many unnecessary columns. We will soon start writing
optimizer steps that should bring performance closer to existing production
systems.

### Project structure

Expand Down
1 change: 0 additions & 1 deletion asm_to_pil/src/vm_to_constrained.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,6 @@ impl<T: FieldElement> ASMPILConverter<T> {
value: Expression<T>,
) -> Vec<(T, AffineExpressionComponent<T>)> {
match value {
Expression::Constant(_) => panic!(),
Expression::PublicReference(_) => panic!(),
Expression::FunctionCall(_) => panic!(),
Expression::Reference(reference) => {
Expand Down
41 changes: 22 additions & 19 deletions ast/src/analyzed/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,29 @@ use std::fmt::{Display, Formatter, Result};

use itertools::Itertools;

use crate::parsed::display::format_expressions;

use super::*;

impl<T: Display> Display for Analyzed<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
for (name, value) in &self.constants {
writeln!(f, "constant {name} = {value};")?;
}

let mut namespace = "Global".to_string();
let mut current_namespace = "Global".to_string();
let mut update_namespace = |name: &str, degree: DegreeType, f: &mut Formatter<'_>| {
if let Some(dot) = name.find('.') {
if name[..dot] != namespace {
namespace = name[..dot].to_string();
writeln!(f, "namespace {namespace}({degree});")?;
let new_name = if let Some(dot) = name.find('.') {
if name[..dot] != current_namespace {
current_namespace = name[..dot].to_string();
writeln!(f, "namespace {current_namespace}({degree});")?;
}
Ok(name[dot + 1..].to_string())
&name[dot + 1..]
} else {
Ok(name.to_string())
}
name
};
Ok((new_name.to_string(), &current_namespace != "Global"))
};

for statement in &self.source_order {
match statement {
StatementIdentifier::Definition(name) => {
let (symbol, definition) = &self.definitions[name];
let name = update_namespace(name, symbol.degree, f)?;
let (name, is_local) = update_namespace(name, symbol.degree, f)?;
match symbol.kind {
SymbolKind::Poly(poly_type) => {
let kind = match &poly_type {
Expand All @@ -49,6 +44,14 @@ impl<T: Display> Display for Analyzed<T> {
writeln!(f, ";")?
}
}
SymbolKind::Constant() => {
let indentation = if is_local { " " } else { "" };
writeln!(
f,
"{indentation}constant {name}{};",
definition.as_ref().unwrap()
)?;
}
SymbolKind::Other() => {
write!(f, " let {name}")?;
if let Some(value) = definition {
Expand All @@ -61,7 +64,7 @@ impl<T: Display> Display for Analyzed<T> {
StatementIdentifier::PublicDeclaration(name) => {
let decl = &self.public_declarations[name];
// TODO we do not know the degree of the namespace here.
let name = update_namespace(&decl.name, 0, f)?;
let (name, _) = update_namespace(&decl.name, 0, f)?;
writeln!(
f,
" public {name} = {}({});",
Expand Down Expand Up @@ -102,7 +105,7 @@ impl<T: Display> Display for RepeatedArray<T> {
}
}

impl<T: Display> Display for Identity<T> {
impl<T: Display> Display for Identity<Expression<T>> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self.kind {
IdentityKind::Polynomial => {
Expand All @@ -120,7 +123,7 @@ impl<T: Display> Display for Identity<T> {
}
}

impl<T: Display> Display for SelectedExpressions<T> {
impl<Expr: Display> Display for SelectedExpressions<Expr> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
Expand All @@ -129,7 +132,7 @@ impl<T: Display> Display for SelectedExpressions<T> {
.as_ref()
.map(|s| format!("{s} "))
.unwrap_or_default(),
format_expressions(&self.expressions)
self.expressions.iter().format(", ")
)
}
}
Expand Down
Loading

0 comments on commit b53d14f

Please sign in to comment.