mirror of
https://github.com/logos-storage/dynamic-data-experiments.git
synced 2026-01-02 13:13:08 +00:00
impl column commitment.
This commit is contained in:
parent
07f8c0a5e7
commit
c314dacf08
1034
Cargo.lock
generated
1034
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
11
Cargo.toml
@ -7,3 +7,14 @@ version = "1.0.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "0.9.0", features = [ "std", "std_rng" ] }
|
||||
itertools = "0.14.0"
|
||||
clap = { version = "4.5.27", features = ["derive"] }
|
||||
ark-std = "0.5.0"
|
||||
ark-ff = "0.5.0"
|
||||
ark-ec = "0.5.0"
|
||||
ark-bls12-381 = "0.5.0"
|
||||
ark-bn254 = "0.5.0"
|
||||
ark-poly = "0.5.0"
|
||||
ark-poly-commit = "0.5.0"
|
||||
anyhow = "1.0.95"
|
||||
117
src/dynamic_data.rs
Normal file
117
src/dynamic_data.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use ark_bls12_381::Bls12_381;
|
||||
use ark_ec::pairing::Pairing;
|
||||
use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Evaluations, EvaluationDomain, GeneralEvaluationDomain};
|
||||
use ark_poly_commit::{Polynomial, marlin_pc::MarlinKZG10, LabeledPolynomial, PolynomialCommitment, QuerySet, LabeledCommitment};
|
||||
use ark_poly_commit::marlin_pc::{Commitment, Randomness,};
|
||||
use anyhow::{anyhow, Result};
|
||||
use ark_poly_commit::sonic_pc::UniversalParams;
|
||||
use ark_std::{end_timer, start_timer, test_rng};
|
||||
use crate::matrix::Matrix;
|
||||
|
||||
type E = Bls12_381;
|
||||
type F = <E as Pairing>::ScalarField;
|
||||
type UniPoly381 = DensePolynomial<F>;
|
||||
type PCS = MarlinKZG10<E, UniPoly381>;
|
||||
|
||||
// struct for the dynamic data scheme,
|
||||
// contains the params and functions needed for the dynamic data scheme
|
||||
pub struct DynamicData{
|
||||
n: usize, // the row size of the data matrix - un-coded
|
||||
k: usize, // the row size of the erasure coded data matrix
|
||||
m: usize, // the column size of the matrix
|
||||
|
||||
ploycommit_domain: GeneralEvaluationDomain<F>,
|
||||
encoding_domain: GeneralEvaluationDomain<F>,
|
||||
|
||||
pp: UniversalParams<Bls12_381>
|
||||
}
|
||||
|
||||
impl DynamicData {
|
||||
// setup the dynamic data scheme
|
||||
pub fn setup(n: usize, k:usize, m:usize) -> Result<Self>{
|
||||
let rng = &mut test_rng();
|
||||
let pp = PCS::setup(m,None, rng)?;
|
||||
let ploycommit_domain = EvaluationDomain::<F>::new(m).ok_or(anyhow!("polycommit domain error"))?;
|
||||
let encoding_domain = EvaluationDomain::<F>::new(n).ok_or(anyhow!("encoding domain error"))?;
|
||||
Ok(Self{
|
||||
n,
|
||||
k,
|
||||
m,
|
||||
ploycommit_domain,
|
||||
encoding_domain,
|
||||
pp,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn commit_columns(&self, matrix: Matrix<F>) -> Result<(
|
||||
Vec<LabeledPolynomial<F, UniPoly381>>,
|
||||
Vec<LabeledCommitment<Commitment<E>>>,
|
||||
Vec<Randomness<F, UniPoly381>>,
|
||||
)>{
|
||||
let rng = &mut test_rng();
|
||||
let degree = self.m;
|
||||
let (ck, vk) = PCS::trim(&self.pp, degree, 2, Some(&[degree])).unwrap();
|
||||
let mut col_polynomials = vec![];
|
||||
let timer = start_timer!(|| format!("Poly evaluations and interpolation for {} columns", degree));
|
||||
for i in 0..matrix.cols(){
|
||||
let poly_evals = Evaluations::from_vec_and_domain(matrix.column(i), self.ploycommit_domain.clone());
|
||||
let col_poly = poly_evals.interpolate();
|
||||
let label = String::from(format!("column_poly_{}", i));
|
||||
let labeled_poly = LabeledPolynomial::new(
|
||||
label,
|
||||
col_poly,
|
||||
Some(degree),
|
||||
Some(2),
|
||||
);
|
||||
col_polynomials.push(labeled_poly);
|
||||
}
|
||||
|
||||
let timer = start_timer!(|| format!("KZG commitment for {} columns", degree));
|
||||
let (labeled_comms, states) = PCS::commit(&ck, &col_polynomials, Some(rng)).unwrap();
|
||||
end_timer!(timer);
|
||||
Ok((col_polynomials,labeled_comms, states))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ark_std::test_rng;
|
||||
|
||||
#[test]
|
||||
fn test_commit_columns_roundtrip() {
|
||||
// dimensions: 3 rows, 2 columns
|
||||
let n = 8;
|
||||
let k = 4;
|
||||
let m = 8;
|
||||
|
||||
// setup
|
||||
let rng = &mut test_rng();
|
||||
let dd = DynamicData::setup(n, k, m).expect("setup should succeed");
|
||||
|
||||
// make a random n×m matrix
|
||||
let matrix = Matrix::new_random(n, m, rng);
|
||||
|
||||
// commit to its columns
|
||||
let (col_polys, commitments, randomness) =
|
||||
dd.commit_columns(matrix.clone()).expect("commit_columns should succeed");
|
||||
|
||||
// we produced exactly one polynomial, one comm, one rand per column
|
||||
assert_eq!(col_polys.len(), m);
|
||||
assert_eq!(commitments.len(), m);
|
||||
assert_eq!(randomness.len(), m);
|
||||
|
||||
// check that each polynomial really interpolates its original column
|
||||
for (i, poly) in col_polys.iter().enumerate() {
|
||||
let col = matrix.column(i);
|
||||
// evaluate poly at each domain point and collect
|
||||
let evals: Vec<_> = dd
|
||||
.ploycommit_domain
|
||||
.elements()
|
||||
.map(|x| poly.polynomial().evaluate(&x))
|
||||
.collect();
|
||||
assert_eq!(evals, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
pub mod matrix;
|
||||
pub mod dynamic_data;
|
||||
207
src/matrix.rs
Normal file
207
src/matrix.rs
Normal file
@ -0,0 +1,207 @@
|
||||
use ark_ff::Field;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use ark_std::rand::Rng;
|
||||
use ark_std::UniformRand;
|
||||
|
||||
|
||||
/// a generic dense matrix stored in row-major order.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Matrix<T: Field + Clone> {
|
||||
rows: usize,
|
||||
cols: usize,
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Field + Clone> Matrix<T> {
|
||||
/// Creates a new matrix from raw data.
|
||||
pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Self {
|
||||
assert!(data.len() == rows * cols, "Data length must equal rows*cols");
|
||||
Matrix { rows, cols, data }
|
||||
}
|
||||
|
||||
/// Generates a random matrix with given dimensions, uses given rng for randomness.
|
||||
pub fn new_random<R: Rng + ?Sized>(rows: usize, cols: usize, rng: &mut R) -> Self
|
||||
where
|
||||
T: UniformRand,
|
||||
{
|
||||
let mut data = Vec::with_capacity(rows * cols);
|
||||
for _ in 0..rows * cols {
|
||||
data.push(T::rand(rng));
|
||||
}
|
||||
Matrix { rows, cols, data }
|
||||
}
|
||||
|
||||
/// Creates a zero matrix (rows x cols).
|
||||
pub fn zeros(rows: usize, cols: usize) -> Self {
|
||||
Matrix { rows, cols, data: vec![T::zero(); rows * cols] }
|
||||
}
|
||||
|
||||
/// Creates an identity matrix of size n x n.
|
||||
pub fn identity(n: usize) -> Self {
|
||||
let mut m = Self::zeros(n, n);
|
||||
for i in 0..n {
|
||||
m[(i, i)] = T::one();
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
/// Constructs from a nested Vec
|
||||
pub fn from_nested_vec(nested: Vec<Vec<T>>) -> Self {
|
||||
let rows = nested.len();
|
||||
assert!(rows > 0, "must have at least one row");
|
||||
let cols = nested[0].len();
|
||||
let mut data = Vec::with_capacity(rows * cols);
|
||||
for row in nested.into_iter() {
|
||||
assert!(row.len() == cols, "all rows must have the same length");
|
||||
data.extend(row);
|
||||
}
|
||||
Matrix { rows, cols, data }
|
||||
}
|
||||
|
||||
/// Returns the number of rows.
|
||||
#[inline]
|
||||
pub fn rows(&self) -> usize { self.rows }
|
||||
|
||||
/// Returns the number of columns.
|
||||
#[inline]
|
||||
pub fn cols(&self) -> usize { self.cols }
|
||||
|
||||
/// Returns both dimensions (rows, cols).
|
||||
#[inline]
|
||||
pub fn dims(&self) -> (usize, usize) { (self.rows, self.cols) }
|
||||
|
||||
/// Returns a reference to the element at (row, col). Panics if out of bounds.
|
||||
#[inline]
|
||||
pub fn get(&self, row: usize, col: usize) -> &T {
|
||||
assert!(row < self.rows && col < self.cols, "Index out of bounds");
|
||||
&self.data[row * self.cols + col]
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the element at (row, col).
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self, row: usize, col: usize) -> &mut T {
|
||||
assert!(row < self.rows && col < self.cols, "Index out of bounds");
|
||||
&mut self.data[row * self.cols + col]
|
||||
}
|
||||
|
||||
/// Returns a slice for the given row.
|
||||
pub fn row(&self, row: usize) -> &[T] {
|
||||
assert!(row < self.rows, "Row index out of bounds");
|
||||
let start = row * self.cols;
|
||||
&self.data[start..start + self.cols]
|
||||
}
|
||||
|
||||
/// Returns a mutable slice for the given row.
|
||||
pub fn row_mut(&mut self, row: usize) -> &mut [T] {
|
||||
assert!(row < self.rows, "Row index out of bounds");
|
||||
let start = row * self.cols;
|
||||
&mut self.data[start..start + self.cols]
|
||||
}
|
||||
|
||||
/// Swaps two rows in-place.
|
||||
pub fn swap_rows(&mut self, i: usize, j: usize) {
|
||||
assert!(i < self.rows && j < self.rows, "Row index out of bounds");
|
||||
for col in 0..self.cols {
|
||||
let a = i * self.cols + col;
|
||||
let b = j * self.cols + col;
|
||||
self.data.swap(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/// Horizontal concatenation: [self | other].
|
||||
pub fn hcat(&self, other: &Self) -> Self {
|
||||
assert!(self.rows == other.rows, "Row counts must match");
|
||||
let mut result = Self::zeros(self.rows, self.cols + other.cols);
|
||||
for r in 0..self.rows {
|
||||
// copy self
|
||||
let src = r * self.cols;
|
||||
let dst = r * result.cols;
|
||||
result.data[dst..dst + self.cols]
|
||||
.copy_from_slice(&self.data[src..src + self.cols]);
|
||||
// copy other
|
||||
let src2 = r * other.cols;
|
||||
result.data[dst + self.cols..dst + self.cols + other.cols]
|
||||
.copy_from_slice(&other.data[src2..src2 + other.cols]);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Selects a subset of columns by index.
|
||||
pub fn select_columns(&self, cols_idx: &[usize]) -> Self {
|
||||
let mut result = Self::zeros(self.rows, cols_idx.len());
|
||||
for r in 0..self.rows {
|
||||
for (j, &c) in cols_idx.iter().enumerate() {
|
||||
result.data[r * result.cols + j] = self.get(r, c).clone();
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns a Vec of all elements in the given column.
|
||||
pub fn column(&self, col: usize) -> Vec<T> {
|
||||
assert!(col < self.cols, "Column index out of bounds");
|
||||
let mut v = Vec::with_capacity(self.rows);
|
||||
for r in 0..self.rows {
|
||||
v.push(self.get(r, col).clone());
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
/// Computes the inverse via in-place Gauss–Jordan; returns None if singular.
|
||||
pub fn invert(&self) -> Option<Self> {
|
||||
assert!(self.rows == self.cols, "Can only invert square matrices");
|
||||
let n = self.rows;
|
||||
let mut aug = self.hcat(&Self::identity(n));
|
||||
|
||||
for i in 0..n {
|
||||
// pivot check and swap if zero
|
||||
if aug[(i, i)].is_zero() {
|
||||
if let Some(k) = (i + 1..n).find(|&k| !aug[(k, i)].is_zero()) {
|
||||
aug.swap_rows(i, k);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// normalize pivot row
|
||||
let inv_pivot = aug[(i, i)].inverse().unwrap();
|
||||
for col in i..2 * n {
|
||||
let idx = i * aug.cols + col;
|
||||
aug.data[idx] = aug.data[idx].clone() * inv_pivot.clone();
|
||||
}
|
||||
// Clone pivot row slice
|
||||
let pivot_start = i * aug.cols + i;
|
||||
let pivot_len = 2 * n - i;
|
||||
let pivot_row: Vec<T> = aug.data[pivot_start..pivot_start + pivot_len].to_vec();
|
||||
|
||||
// remove other rows
|
||||
for r in 0..n {
|
||||
if r != i {
|
||||
let factor = aug[(r, i)].clone();
|
||||
if !factor.is_zero() {
|
||||
let row_offset = r * aug.cols;
|
||||
for k in 0..pivot_len {
|
||||
let idx = row_offset + i + k;
|
||||
aug.data[idx] = aug.data[idx].clone() - factor.clone() * pivot_row[k].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(aug.select_columns(&(n..2 * n).collect::<Vec<_>>()))
|
||||
}
|
||||
}
|
||||
|
||||
// indexing with (row, col)
|
||||
impl<T: Field + Clone> Index<(usize, usize)> for Matrix<T> {
|
||||
type Output = T;
|
||||
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
|
||||
self.get(row, col)
|
||||
}
|
||||
}
|
||||
|
||||
// mutable indexing with (row, col)
|
||||
impl<T: Field + Clone> IndexMut<(usize, usize)> for Matrix<T> {
|
||||
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
|
||||
self.get_mut(row, col)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user