A Noir's backend implementation using gnark

Overview

Using gnark as a backend for Noir

If you want to develop a backend for Noir, basically what you need to do is to translate an ACIR (Abstract Circuit Intermediate Representation) to something that your backend could understand. The prerequisites for this are to have certain knowledge about ACIR and its codebase, and the backend that you are going to support. In this case, the backend is gnark. Written in Go, gnark is a fast zk-SNARK library that offers a high-level API to design circuits. This library is open-source and developed under the Apache 2.0 license.

Overview

flowchart
    N[Noir] --ACIR--> BR[Backend in gnark wrapper in Rust]
    BR[Backend in gnark wrapper written in Rust] --Raw R1CS--> B[Concrete Backend]
    subgraph B[Concrete Backend]
        direction TB
        BW[WASM/FFI] --> BG[Backend in gnark written in Go]
    end

Backend wrapper written in Rust

This module is needed because Noir's backend has to be written in Rust and we want to develop one using gnark which is written in Go.

This Rust module is basically in charge of implementing the trait Backend for a given type which we've named Gnark which represents our backend and of mapping ACIR into an R1CS-friendly data structure. Even though gnark supports several proving systems (like Plonk and Groth16) this wrapper will translate ACIR into R1CS. In the future, more proving systems can be easily supported (we are already planning on supporting Plonk. By this I mean that, a C++ Plonk implementation is already supported as a backend for Noir, but gnark's Plonk implementation isn't).

The first part is not so difficult. We just followed the other Noir backends' structure (see Arkwork's Marlin's and Aztec's Plonk's).

The second part takes most of the work. It can be cut into two parts: the raw R1CS generation (ACIR translation) and the communication with the concrete backend (glue between Rust and Go). In the following paragraphs, we are going to explain these sub-parts a little bit better.

Generating a raw R1CS or translating ACIR to something R1CS-friendly could be seen as just mapping a struct to another struct. For this, we've made two structs: RawR1CS and RawGate.

The communication between the concrete backend (the one written in Go) could be done through a pre-compiled WASM API or through FFI. For this, what we are basically doing is serializing the RawR1CS struct into JSON and sending it as a parameter for the WASM functions (in the case that we end up using the WASM API) or to the Go functions (FFI). At the moment we are looking for the easiest way to communicate Rust with Go. We started using WASMER but it is a little bit limited in terms of the amount of information that can be sent to a WASM function so we have discarded it for the moment (a second look could help here). Another step can be to try another WASM library called WASM-PACK, but we decided to start researching FFI.

And that's it for this module, in the next section we are going to dive a little deeper into the WASM API.

ACIR to raw R1CS

The mapping from ACIR to R1CS. I prefer to use "raw" because it is not a concrete R1CS but its component parts.

These are the structures:

RawR1CS

pub struct RawR1CS {
    pub gates: Vec<RawGate>,
    pub public_inputs: acvm::PublicInputs,
    pub values: Vec<Fr>,
    pub num_variables: usize,
}

RawGate

pub struct RawGate {
    pub mul_terms: Vec<(Fr, acvm::Witness, acvm::Witness)>,
    pub add_terms: Vec<(Fr, acvm::Witness)>,
    pub constant_term: Fr,
}

Backends interface (glue)

This module wraps the Go functions in charge of the communication between Rust and Go.

The raw structures are JSON-deserialized and sent to the Go functions.

Backend written in Go (concrete backend)

This module is the real deal. It is in charge of generating the proof for a given circuit and also of verifying a given proof. Using the raw R1CS received from the backend wrapper, it rebuilds the circuit and generates the proof or verifies a proof (depending on what function you are using).

The API would compile to WASM which is going to be used by the Rust wrapper. Or it would just expose functions for the Rust FFI (again, we are researching which is the easiest way to interface).

You might also like...
Serialize & deserialize device tree binary using serde

serde_device_tree Use serde framework to deserialize Device Tree Blob binary files; no_std compatible. Use this library Run example: cargo run --examp

A turing-complete programming language using only zero-width unicode characters, inspired by brainfuck and whitespace.

Zero-Width A turing-complete programming language using only zero-width unicode characters, inspired by brainfuck and whitespace. Currently a (possibl

Quantogram - Approximate Quantile calculation using Histograms
Quantogram - Approximate Quantile calculation using Histograms

Quantogram - Approximate Quantile calculation using Histograms A library for Estimating Online Quantiles of Streams Quantogram accepts a stream of flo

Parse and encoding of data using the SCTE-35 standard.

SCTE-35 lib and parser for Rust Work in progress! This library provide access to parse and encoding of data using the SCTE-35 standard. This standard

Public aircraft & flightroute api Built in Rust for Docker, using PostgreSQL & Redis

api.adsbdb.com public aircraft & flightroute api Built in Rust for Docker, using PostgreSQL & Redis See typescript branch for original typescript vers

Key-value store for embedded systems, for raw NOR flash, using an LSM-Tree.

ekv Key-value store for embedded systems, for raw NOR flash, using an LSM-Tree. Features None yet TODO Everything Minimum supported Rust version (MSRV

Bitpack a boolean into a pointer using bit magic.

ptr-bool tl;dr: a pointer and boolean with the same size as a pointer. A convenience crate used to bitpack a boolean and pointer into the same eight b

The utility is designed to check the availability of peers and automatically update them in the Yggdrasil configuration file, as well as using the admin API - addPeer method.

Yggrasil network peers checker / updater The utility is designed to check the availability of peers and automatically update them in the Yggdrasil con

Using iced-rs library for YT monitoring app
Using iced-rs library for YT monitoring app

YouTube Monitoring App (using Rust) Description This app is built on the top of iced library. If you're curious what this is about, check out the YT m

Comments
  • Integration between Noir and gnark's Backend

    Integration between Noir and gnark's Backend

    Functionality (tested manually)

    • [x] nargo execute
    • [x] nargo check
    • [x] nargo contract
    • [x] nargo gates
    • [x] nargo new
    • [x] nargo test
    • [x] nargo compile
    • [x] nargo verify
    • [x] nargo prove

    Testing

    • [x] Integration tests
    opened by ilitteri 2
  • Deserialization for felts

    Deserialization for felts

    Changes

    • Implement deserialize method for felt.
    • Implement deseriliaze method for felts.
    • Remove MulTerm & AddTerm Serialize implementations and replace them with derives.
    • Also derive Deserialize for all the structs.
    opened by ilitteri 0
  • hello from gnark team

    hello from gnark team

    hi, given gnark's current architecture, I suspect you'll come up with a wish list at some point to make your life easier -- feel free to create issues in gnark repo / participate in discussions.

    Might be of interest to you: https://github.com/ConsenSys/gnark/pull/452 . In particular there is an example on how to build a R1CS without using the frontend; note that the APIs / interfaces are still quite experimental.

    func ExampleR1CS_GetConstraints() {
    	// build a constraint system; this is (usually) done by the frontend package
    	// for this Example we want to manipulate the constraints and output a string representation
    	// and build the linear expressions "manually".
    	r1cs := cs.NewR1CS(0)
    
    	ONE := r1cs.AddPublicVariable("1") // the "ONE" wire
    	Y := r1cs.AddPublicVariable("Y")
    	X := r1cs.AddSecretVariable("X")
    
    	v0 := r1cs.AddInternalVariable() // X²
    	v1 := r1cs.AddInternalVariable() // X³
    
    	// coefficients
    	cOne := r1cs.FromInterface(1)
    	cFive := r1cs.FromInterface(5)
    
    	// X² == X * X
    	r1cs.AddConstraint(constraint.R1C{
    		L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)},
    		R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)},
    		O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)},
    	})
    
    	// X³ == X² * X
    	r1cs.AddConstraint(constraint.R1C{
    		L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)},
    		R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)},
    		O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v1)},
    	})
    
    	// Y == X³ + X + 5
    	r1cs.AddConstraint(constraint.R1C{
    		R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, ONE)},
    		L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Y)},
    		O: constraint.LinearExpression{
    			r1cs.MakeTerm(&cFive, ONE),
    			r1cs.MakeTerm(&cOne, X),
    			r1cs.MakeTerm(&cOne, v1),
    		},
    	})
    
    	// get the constraints
    	constraints, r := r1cs.GetConstraints()
    
    	for _, r1c := range constraints {
    		fmt.Println(r1c.String(r))
    		// for more granularity use constraint.NewStringBuilder(r) that embeds a string.Builder
    		// and has WriteLinearExpression and WriteTerm methods.
    	}
    
    	// Output:
    	// X ⋅ X == v0
    	// v0 ⋅ X == v1
    	// Y ⋅ 1 == 5 + X + v1
    }
    
    opened by gbotrel 2
Owner
Lambdaclass
A venture studio and a engineering powerhouse at the same time
Lambdaclass
Zomby7e's Blog - Backend

7eblog_backend Zomby7e's Blog - Backend, is just a micro blog backend. This project is written in Rust, it depends on Actix, uses SQLite to store data

Zomby7e 2 Aug 26, 2022
A backend framework for building fast and flexible APIs rapidly.

Andromeda Andromeda is a backend framework for Rust, to simplify the development of the kinds of basic API services that we developers have to build s

Framesurge 7 Dec 28, 2022
A candidate backend for the Telegram channel @KonachanPopular

Konachan Popular (Rust) This repository contains the source code of the backend program running the Telegram channel @KonachanPopular. Run in a Contai

K4YT3X 10 Jan 3, 2023
A real-time data backend for browser-based applications.

DriftDB DriftDB is a real-time data backend for browser-based applications. For more information, see driftdb.com. Structure of this repo docs/: main

drifting in space 453 Feb 6, 2023
Neural Network implementation from scratch using Cairo 1.0

Neural Network for MNIST in Cairo 1.0 Implementation of a Neural Network from scratch using Cairo 1.0 for MNIST predictions. The NN has a simple two-l

Fran Algaba 6 Mar 14, 2023
Rust explained using easy English

Update 22 December 2020: mdBook can be found here. 28 November 2020: Now also available in simplified Chinese thanks to kumakichi! 1 February 2021: No

null 7.3k Jan 3, 2023
A fast uuid generator in Python using Rust

ruuid A fast UUID generator for Python built using Rust. Its a simple wrapper on top of Rust's UUID crate. How to use? Installation: pip3 install ruui

Rahul Nair 19 Jul 13, 2022
An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous and blocking clients respectively.

eithers_rust An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous a

null 2 Oct 24, 2021
(Ab)using technology for fun & profit.

(Ab)using technology for fun & profit. Code accompanying my blog

Sylvain Kerkour 357 Dec 30, 2022
A mixer for jack-audio using rust and druid UI

A simple mixer to allow me to use my midi controller (Novation LaunchControl XL) on linux and also to explore the new druid ui. Features volume faders

Richard Dodd (dodj) 25 Jul 6, 2022