Skip to content

Commit

Permalink
Implements for chapter 2 (#2)
Browse files Browse the repository at this point in the history
1. Freivalds Algorithm
2. Reed Solomon Fingerprint
3. univariate lagrange polynomial
     1.  encoding a using it as coeffients 
     2. using lagrange polynomail  with (domain, evaluation) 
          Left a error. Fix it later.
  • Loading branch information
SuccinctPaul authored Jul 19, 2023
1 parent 199adc1 commit 9da0757
Show file tree
Hide file tree
Showing 28 changed files with 835 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ Cargo.lock
*.pdb

.idea
.vscode
.vscode

# ignore tmp dump data
**/*.bin
File renamed without changes.
1 change: 1 addition & 0 deletions 1-ip/src/lib.rs → 1_IP/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// The interactive proofs case(1.2.1) in chapter 1
/// In this case, business store data in cloud_provider. Later, before business wants wanna do some computation on cloud_provider, the business check the `data` first.
mod prover;
mod utils;
mod verify;
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions 2_Freivalds_Algorithm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "Freivalds_Algorithm"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ff = "0.13.0"
bls12_381 = "0.8.0"
rand = "0.8.5"
rand_core = { version = "0.6.4", default-features = false, features = ["std"] }
37 changes: 37 additions & 0 deletions 2_Freivalds_Algorithm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::matrix::Matrix;
use crate::prover::Prover;
use crate::utils::gen_x;
use rand_core::OsRng;

mod matrix;
/// For matrix A and B, C = A · B.
///
/// How can one verify that two matrices were multiplied correctly.
/// First,choose a random `r∈Fp`,and let x=(1,r,r2,...,rn−1).
/// Then compute `y=Cx` and `z=A·Bx`,outputting YES if y = z and NO otherwise.
mod prover;
mod utils;
mod verifier;

#[test]
fn completeness() {
let n: usize = std::env::var("n")
.unwrap_or_else(|_| "4".to_string())
.parse()
.expect("Cannot parse DEGREE env var as u32");

// prover
let alice = Prover::random(n);
// C = A · B
let c = alice.matrix_multiplication();

let x = gen_x(OsRng, n);
// z=A·Bx
let z = alice.hash(&x);

// verify
// y=Cx
let y = c.matrix_mul_vec(&x);

assert_eq!(z, y);
}
157 changes: 157 additions & 0 deletions 2_Freivalds_Algorithm/src/matrix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use bls12_381::Scalar;
use ff::Field;
use rand_core::{OsRng, RngCore};
use std::ops::AddAssign;

/// This define `matrix` (rows * cols) (m × n)
#[derive(Debug, Clone)]
pub struct Matrix {
rows: usize,
cols: usize,
// columns
values: Vec<Vec<Scalar>>,
}

impl Matrix {
pub fn random(rows: usize, cols: usize) -> Self {
let values = (0..rows)
.map(|_| (0..cols).map(|_| Scalar::random(OsRng)).collect::<Vec<_>>())
.collect::<Vec<_>>();

Self { cols, rows, values }
}

fn get_columns(&self, column_index: usize) -> Vec<Scalar> {
assert!(0 <= column_index || self.cols > column_index);

self.values
.iter()
.map(|v| v.get(column_index).unwrap().clone())
.collect::<Vec<_>>()
}

fn vec_mul(a: &Vec<Scalar>, b: &Vec<Scalar>) -> Scalar {
assert_eq!(a.len(), b.len());

let mut res = Scalar::zero();
for (ai, bi) in a.into_iter().zip(b) {
let producti = ai.mul(bi);
res.add_assign(producti);
}
res
}

/// https://en.wikipedia.org/wiki/Dot_product
/// Suppose A(m * n), x(n) => A * x = y(n)
pub fn matrix_mul_vec(&self, vector: &Vec<Scalar>) -> Vec<Scalar> {
assert_eq!(self.cols, vector.len());
let n = self.cols;

let mut result: Vec<Scalar> = Vec::with_capacity(n);
for i in 0..self.rows {
let row_i = self.values.get(i).unwrap().clone();

let elem = Self::vec_mul(&row_i, vector);

result.push(elem);
}

result
}

/// https://en.wikipedia.org/wiki/Dot_product
/// Suppose A(m * n), B(n, p) => A * B = C(m * p)
pub fn mul(m_a: &Matrix, m_b: &Matrix) -> Self {
assert!(m_a.cols > 0 || m_b.rows > 0, "matrix a is empty");
assert!(m_b.cols > 0 || m_b.rows > 0, "matrix a is empty");
// ma.cols == mb.rows
assert_eq!(m_a.cols, m_b.rows);
let m = m_a.rows;
let n = m_a.cols;
// let n = m_b.rows;
let p = m_b.cols;

let mut matrix: Vec<Vec<Scalar>> = Vec::with_capacity(m);
for i in 0..m {
let mut new_row = Vec::with_capacity(p);

let row_i = m_a.values.get(i).unwrap().clone();
for j in 0..p {
// todo: this can be optimized by converting m_b columns as rows
let col_j = m_b.get_columns(j);
let elem_ij = Self::vec_mul(&row_i, &col_j);
new_row.push(elem_ij);
}

matrix.push(new_row);
}

Self {
rows: m,
cols: p,
values: matrix,
}
}
}

#[cfg(test)]
mod test {
use crate::matrix::Matrix;
use bls12_381::Scalar;

#[test]
fn test_random_matrix() {
let matrix = Matrix::random(3, 4);
println!("{:#?}", matrix);
}

#[test]
fn test_matrix_mul() {
let m: usize = 2;
let mut values: Vec<Vec<Scalar>> = Vec::with_capacity(m);
let mut row_1: Vec<Scalar> = Vec::with_capacity(m);
row_1.push(Scalar::one());
row_1.push(Scalar::zero());
let mut row_2: Vec<Scalar> = Vec::with_capacity(m);
row_2.push(Scalar::zero());
row_2.push(Scalar::one());
values.push(row_1);
values.push(row_2);

let a = Matrix {
rows: m,
cols: m,
values,
};
let b = a.clone();

let res = Matrix::mul(&a, &b);
assert_eq!(a.values, res.values);
println!("{:#?}", res);
}

#[test]
fn test_matrix_mul_vec() {
let m: usize = 2;
let mut values: Vec<Vec<Scalar>> = Vec::with_capacity(m);
let mut row_1: Vec<Scalar> = Vec::with_capacity(m);
row_1.push(Scalar::one());
row_1.push(Scalar::zero());
let mut row_2: Vec<Scalar> = Vec::with_capacity(m);
row_2.push(Scalar::zero());
row_2.push(Scalar::one());
values.push(row_1.clone());
values.push(row_2);

let a = Matrix {
rows: m,
cols: m,
values,
};
let b = a.clone();

let res = a.matrix_mul_vec(&row_1);
assert_eq!(row_1, res);
println!("{:#?}", res);
}
}
28 changes: 28 additions & 0 deletions 2_Freivalds_Algorithm/src/prover.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::matrix::Matrix;
use bls12_381::Scalar;
use ff::Field;

pub struct Prover {
a: Matrix,
b: Matrix,
}

impl Prover {
pub fn random(n: usize) -> Self {
Self {
a: Matrix::random(n, n),
b: Matrix::random(n, n),
}
}

pub fn matrix_multiplication(&self) -> Matrix {
Matrix::mul(&self.a, &self.b)
}

pub fn hash(&self, x: &Vec<Scalar>) -> Vec<Scalar> {
// tmp = Ax
let tmp = self.a.matrix_mul_vec(x);
// z = B temp
self.b.matrix_mul_vec(&tmp)
}
}
49 changes: 49 additions & 0 deletions 2_Freivalds_Algorithm/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::matrix::Matrix;
use bls12_381::Scalar;
use ff::Field;
use rand_core::RngCore;
use std::ops::MulAssign;

/// x=(1,r,r2,...,rn−1)
pub fn gen_x(rng: impl RngCore, n: usize) -> Vec<Scalar> {
let r: Scalar = Scalar::random(rng);

let mut cur_r = Scalar::one();
(0..n)
.map(|_| {
let res = cur_r;
cur_r.mul_assign(r);
res
})
.collect::<Vec<_>>()
}

#[cfg(test)]
mod test {
use bls12_381::Scalar;
use ff::Field;
use rand_core::OsRng;
use std::ops::MulAssign;

#[test]
fn test_gen_x() {
let n = 4;

let r: Scalar = Scalar::random(OsRng);

let target = vec![Scalar::one(), r, r.mul(&r), r.mul(&r).mul(&r)];

// Param::gen_x
let mut cur_r = Scalar::one();
let x = (0..n)
.map(|_| {
let res = cur_r;
cur_r.mul_assign(r);
res
})
.collect::<Vec<_>>();

assert_eq!(target, x);
println!("{:?}", x);
}
}
1 change: 1 addition & 0 deletions 2_Freivalds_Algorithm/src/verifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

12 changes: 12 additions & 0 deletions 2_Reed_Solomon_Fingerprinting/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "Reed_Solomon_Fingerprinting"
version = "0.1.0"
edition = "2021"
description = "The Reed-Solomon Fingerprinting case(2.1) in chapter 2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ff = "0.13.0"
bls12_381 = "0.8.0"
rand = "0.8.5"
rand_core = { version = "0.6.4", default-features = false, features = ["std"] }
69 changes: 69 additions & 0 deletions 2_Reed_Solomon_Fingerprinting/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::prover::Prover;
/// The Reed-Solomon Fingerprinting case(2.1) in chapter 2
/// In this case, we'll check whether Alice and Bob has the same file by checking RS-fingerprint.
use crate::utils::{dump_field_data, read_from_file};
use crate::verify::Verifier;
use bls12_381::Scalar;
use ff::Field;
use rand_core::{OsRng, RngCore};

mod prover;
mod utils;
mod verify;

#[derive(Default, Eq, PartialEq)]
pub(crate) struct Person {
data: Vec<Scalar>,
}

impl Person {
pub(crate) fn new(file_name: &str) -> Self {
let data = read_from_file(file_name);
Self { data }
}
}

const file_A: &str = "file_A.bin";
const file_B: &str = "file_B.bin";

fn prepare_data() {
let length = 10 + OsRng.next_u64() % 90;
dump_field_data(file_A, 10 + length);
dump_field_data(file_B, 10 + 2 * length);
}

#[test]
fn completeness() {
prepare_data();

let Alice = Person::new(file_A);
let Bob = Person::new(file_A);

// Alice RS fingerprint
let r = Person::challenge();
let fingerprint = Alice.fs_hash(r.clone());

// Bob check it
let result = Bob.verify(r, fingerprint);

assert!(result, "They are not same.");
}

#[test]
fn soundness() {
prepare_data();

let Alice = Person::new(file_A);
let Bob = Person::new(file_B);

// use the prover trait by alice

// Alice RS fingerprint
let r = Person::challenge();
let fingerprint = Alice.fs_hash(r.clone());

// Bob check it
let result = Bob.verify(r, fingerprint);

assert!(!result, "They are same.");
}
Loading

0 comments on commit 9da0757

Please sign in to comment.