Skip to content

Commit

Permalink
zkhack Bounty: Sumcheck (#149)
Browse files Browse the repository at this point in the history
* FiniteFiniteField corr

* add basic multi_var_poly

* make stuff vec

* test passes

* added testing and display

* add comments to mult_var_poly

* added comments to sum-check

* added example

* added readme

---------

Co-authored-by: goforashutosh <ashtheknight@gmail.com>
  • Loading branch information
0xJepsen and goforashutosh authored Aug 11, 2024
1 parent ed9de5d commit 5e61a8e
Show file tree
Hide file tree
Showing 9 changed files with 816 additions and 8 deletions.
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,26 @@
</div>

## Overview

Ronkathon is a rust implementation of a collection of cryptographic primitives. It is inspired by the common python plonkathon repository, and plonk-by-hand. We use the same curve and field as plonk-by-hand (not secure), and are working towards building everything from scratch to understand everything from first principles.

## Multivariate polynomials and sum-check

This project implements the sum-check protocol for multivariate polynomials over finite fields. The sum-check protocol is an interactive proof system where a prover convinces a verifier of the sum of a multivariate polynomial over a boolean hypercube. This implementation includes:

- A `MultiVarPolynomial` struct which represents a multivariate polynomial
- A `SumCheckProver` for generating proofs
- A `SumCheckVerifier` for verifying proofs
- A `SumCheck` struct that encapsulates the entire protocol.

Use

`cargo run --example sumcheck_ex`

to run example code.

## Primitives

- [Finite Group](src/field/group.rs)
- [Fields and Their Extensions](src/field/README.md)
- [Binary Fields](src/field/binary_towers/README.md)
Expand All @@ -28,46 +45,56 @@ Ronkathon is a rust implementation of a collection of cryptographic primitives.
- [DSL](src/compiler/README.md)

### Signatures

- [Tiny ECDSA](src/ecdsa.rs)

### Encryption

- [RSA](src/encryption/asymmetric/rsa/README.md)
- [DES](src/encryption/symmetric/des/README.md)
- [AES](src/encryption/symmetric/aes/README.md)
- [ChaCha](src/encryption/symmetric/chacha/README.md)

### Hash

- [Sha256 Hash](src/hashes/README.md)
- [Poseidon Hash](src/hashes/poseidon/README.md)

## In Progress

- [ ] Edwards curve Signatures (EdDSA)

## Resources

We have found the following resources helpful in understanding the foundational mathematics behind this implementation. After going through these, you should be able to understand the codebase

### Theoretic Resources

- [Plonk by Hand P1](https://research.metastate.dev/plonk-by-hand-part-1/)
- [Plonk by Hand P2](https://research.metastate.dev/plonk-by-hand-part-2-the-proof/)

### Code Refrences

- [Plonkathon](https://github.com/0xPARC/plonkathon/blob/main/README.md)
- [Plonky3](https://github.com/Plonky3/Plonky3)
- [py_pairing](https://github.com/ethereum/py_pairing/tree/master)
- [arkworks](https://github.com/arkworks-rs)


## Math

To see computations used in the background, go to the `math/` directory.
From there, you can run the `.sage` files in a SageMath environment.
In particular, the `math/field.sage` computes roots of unity in the `PlutoField` which is of size 101. To install sage on your machine, follow the instructions [here](https://doc.sagemath.org/html/en/installation/index.html). If you are on a Mac, you can install it via homebrew with `brew install --cask sage`.

## License

Licensed under your option of either:

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
55 changes: 55 additions & 0 deletions examples/sumcheck_ex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// File: examples/sum_check_demo.rs

use ronkathon::{
algebra::field::prime::PlutoBaseField, multi_var_poly::MultiVarPolynomial, sumcheck::SumCheck,
};

type F = PlutoBaseField;

fn create_demo_polynomial() -> MultiVarPolynomial<F> {
// Create the polynomial:
// 3 x^2 y^2 z^2 + 2x^2 y + 5x^2 z^2 + 4yz + 6x + 1
let coordinates = vec![
vec![0, 0, 0], // Constant term
vec![1, 0, 0], // x term
vec![0, 1, 1], // yz term
vec![2, 0, 2], // x^2 z^2 term
vec![2, 1, 0], // x^2 y term
vec![2, 2, 2], // x^2 y^2 z^2 term
];
let coefficients = vec![
F::from(1), // Constant term
F::from(6), // x term
F::from(4), // yz term
F::from(5), // x^2 z^2 term
F::from(2), // x^2 y term
F::from(3), // x^2 y^2 z^2 term
];
MultiVarPolynomial::from_coordinates(coordinates, coefficients).unwrap()
}

fn main() {
println!("Sum-Check Protocol Demonstration");
println!("================================");

let poly = create_demo_polynomial();
println!("Created multivariate polynomial:");
println!("3 x^2 y^2 z^2 + 2x^2 y + 5x^2 z^2 + 4yz + 6x + 1");

let expected_sum = F::from(57);
println!("\nExpected sum over boolean hypercube: {:?}", expected_sum);

let mut sumcheck = SumCheck::new(poly, true);
println!("\nRunning interactive sum-check protocol:");
sumcheck.run_interactive_protocol();

println!("\nVerification result:");
if sumcheck.verifier.result == expected_sum {
println!("Sum-check protocol succeeded! The sum is verified to be {:?}", expected_sum);
} else {
println!(
"Sum-check protocol failed. Expected {:?}, but got {:?}",
expected_sum, sumcheck.verifier.result
);
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ pub mod encryption;
pub mod hashes;
pub mod hmac;
pub mod kzg;
pub mod multi_var_poly;
pub mod polynomial;
pub mod sumcheck;
pub mod tree;

use core::{
Expand Down
107 changes: 107 additions & 0 deletions src/multi_var_poly/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//! Arithmetic operations for multivariate polynomials.
//! The operations are implemented for [`MultiVarPolynomial`] in the monomial basis.
//!
//! Note: Operations are restricted to polynomials with the same degree structure.
//!
//! ## Implementations
//! - [`Add`] for adding two multivariate polynomials.
//! - [`AddAssign`] for adding two multivariate polynomials in place.
//! - [`Sum`] for summing a collection of multivariate polynomials.
//! - [`Sub`] for subtracting two multivariate polynomials.
//! - [`SubAssign`] for subtracting two multivariate polynomials in place.
//! - [`Neg`] for negating a multivariate polynomial.
//! - [`Mul`] for scalar multiplication of a multivariate polynomial.
//! - [`MulAssign`] for scalar multiplication of a multivariate polynomial in place.

use std::{
iter::Sum,
ops::{Add, AddAssign, Neg, Sub, SubAssign},
};

use super::*;

impl<F: FiniteField> Add for MultiVarPolynomial<F> {
type Output = Self;

/// Implements addition of two multivariate polynomials by adding their coefficients.
fn add(self, rhs: Self) -> Self::Output {
assert_eq!(self.degree, rhs.degree, "Polynomials must have the same degree structure");

let coefficients =
self.coefficients.iter().zip(rhs.coefficients.iter()).map(|(&a, &b)| a + b).collect();

Self { degree: self.degree, coefficients }
}
}

impl<F: FiniteField> AddAssign for MultiVarPolynomial<F> {
/// Implements in-place addition of two multivariate polynomials by adding their coefficients.
fn add_assign(&mut self, rhs: Self) {
assert_eq!(self.degree, rhs.degree, "Polynomials must have the same degree structure");

for (a, b) in self.coefficients.iter_mut().zip(rhs.coefficients.iter()) {
*a += *b;
}
}
}

impl<F: FiniteField> Sum for MultiVarPolynomial<F> {
/// Implements summing a collection of multivariate polynomials.
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|x, y| x + y).expect("Cannot sum an empty iterator of MultiVarPolynomials")
}
}

impl<F: FiniteField> Sub for MultiVarPolynomial<F> {
type Output = Self;

/// Implements subtraction of two multivariate polynomials by subtracting their coefficients.
fn sub(self, rhs: Self) -> Self::Output {
assert_eq!(self.degree, rhs.degree, "Polynomials must have the same degree structure");

let coefficients =
self.coefficients.iter().zip(rhs.coefficients.iter()).map(|(&a, &b)| a - b).collect();

Self { degree: self.degree, coefficients }
}
}

impl<F: FiniteField> SubAssign for MultiVarPolynomial<F> {
/// Implements in-place subtraction of two multivariate polynomials by subtracting their
/// coefficients.
fn sub_assign(&mut self, rhs: Self) {
assert_eq!(self.degree, rhs.degree, "Polynomials must have the same degree structure");

for (a, b) in self.coefficients.iter_mut().zip(rhs.coefficients.iter()) {
*a -= *b;
}
}
}

impl<F: FiniteField> Neg for MultiVarPolynomial<F> {
type Output = Self;

/// Implements negation of a multivariate polynomial by negating its coefficients.
fn neg(self) -> Self::Output {
Self {
degree: self.degree,
coefficients: self.coefficients.into_iter().map(|c| -c).collect(),
}
}
}

impl<F: FiniteField> Mul<F> for MultiVarPolynomial<F> {
type Output = Self;

/// Implements scalar multiplication of a multivariate polynomial.
fn mul(self, rhs: F) -> Self::Output { self.scalar_mul(rhs) }
}

impl<F: FiniteField> MulAssign<F> for MultiVarPolynomial<F> {
/// Implements in-place scalar multiplication of a multivariate polynomial.
fn mul_assign(&mut self, rhs: F) {
for coeff in &mut self.coefficients {
*coeff *= rhs;
}
}
}
Loading

0 comments on commit 5e61a8e

Please sign in to comment.