arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/sparse_mlpoly.rs
src/sparse_mlpoly.rsRaw
   1#![allow(clippy::type_complexity)]
   2#![allow(clippy::too_many_arguments)]
   3#![allow(clippy::needless_range_loop)]
   4use crate::poseidon_transcript::{AppendToPoseidon, PoseidonTranscript};
   5
   6use super::dense_mlpoly::DensePolynomial;
   7use super::dense_mlpoly::{
   8    EqPolynomial, IdentityPolynomial, PolyCommitment, PolyCommitmentGens, PolyEvalProof,
   9};
  10use super::errors::ProofVerifyError;
  11use super::math::Math;
  12use super::product_tree::{DotProductCircuit, ProductCircuit, ProductCircuitEvalProofBatched};
  13use super::random::RandomTape;
  14use super::scalar::Scalar;
  15use super::timer::Timer;
  16use super::transcript::AppendToTranscript;
  17use ark_ff::{Field, One, Zero};
  18use ark_serialize::*;
  19use core::cmp::Ordering;
  20use merlin::Transcript;
  21
  22#[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone)]
  23pub struct SparseMatEntry {
  24    row: usize,
  25    col: usize,
  26    val: Scalar,
  27}
  28
  29impl SparseMatEntry {
  30    pub fn new(row: usize, col: usize, val: Scalar) -> Self {
  31        SparseMatEntry { row, col, val }
  32    }
  33}
  34
  35#[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone)]
  36pub struct SparseMatPolynomial {
  37    num_vars_x: usize,
  38    num_vars_y: usize,
  39    M: Vec<SparseMatEntry>,
  40}
  41
  42pub struct Derefs {
  43    row_ops_val: Vec<DensePolynomial>,
  44    col_ops_val: Vec<DensePolynomial>,
  45    comb: DensePolynomial,
  46}
  47
  48#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
  49pub struct DerefsCommitment {
  50    comm_ops_val: PolyCommitment,
  51}
  52
  53impl Derefs {
  54    pub fn new(row_ops_val: Vec<DensePolynomial>, col_ops_val: Vec<DensePolynomial>) -> Self {
  55        assert_eq!(row_ops_val.len(), col_ops_val.len());
  56
  57        let derefs = {
  58            // combine all polynomials into a single polynomial (used below to produce a single commitment)
  59            let comb = DensePolynomial::merge(row_ops_val.iter().chain(col_ops_val.iter()));
  60
  61            Derefs {
  62                row_ops_val,
  63                col_ops_val,
  64                comb,
  65            }
  66        };
  67
  68        derefs
  69    }
  70
  71    pub fn commit(&self, gens: &PolyCommitmentGens) -> DerefsCommitment {
  72        let (comm_ops_val, _blinds) = self.comb.commit(gens, None);
  73        DerefsCommitment { comm_ops_val }
  74    }
  75}
  76
  77#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
  78pub struct DerefsEvalProof {
  79    proof_derefs: PolyEvalProof,
  80}
  81
  82impl DerefsEvalProof {
  83    fn protocol_name() -> &'static [u8] {
  84        b"Derefs evaluation proof"
  85    }
  86
  87    fn prove_single(
  88        joint_poly: &DensePolynomial,
  89        r: &[Scalar],
  90        evals: Vec<Scalar>,
  91        gens: &PolyCommitmentGens,
  92        transcript: &mut PoseidonTranscript,
  93        random_tape: &mut RandomTape,
  94    ) -> PolyEvalProof {
  95        assert_eq!(joint_poly.get_num_vars(), r.len() + evals.len().log_2());
  96
  97        // append the claimed evaluations to transcript
  98        // evals.append_to_transcript(b"evals_ops_val", transcript);
  99        transcript.append_scalar_vector(&evals);
 100
 101        // n-to-1 reduction
 102        let (r_joint, eval_joint) = {
 103            let challenges = transcript.challenge_vector(evals.len().log_2());
 104            let mut poly_evals = DensePolynomial::new(evals);
 105            for i in (0..challenges.len()).rev() {
 106                poly_evals.bound_poly_var_bot(&challenges[i]);
 107            }
 108            assert_eq!(poly_evals.len(), 1);
 109            let joint_claim_eval = poly_evals[0];
 110            let mut r_joint = challenges;
 111            r_joint.extend(r);
 112
 113            debug_assert_eq!(joint_poly.evaluate(&r_joint), joint_claim_eval);
 114            (r_joint, joint_claim_eval)
 115        };
 116        // decommit the joint polynomial at r_joint
 117        transcript.append_scalar(&eval_joint);
 118        let (proof_derefs, _comm_derefs_eval) = PolyEvalProof::prove(
 119            joint_poly,
 120            None,
 121            &r_joint,
 122            &eval_joint,
 123            None,
 124            gens,
 125            transcript,
 126            random_tape,
 127        );
 128
 129        proof_derefs
 130    }
 131
 132    // evalues both polynomials at r and produces a joint proof of opening
 133    pub fn prove(
 134        derefs: &Derefs,
 135        eval_row_ops_val_vec: &[Scalar],
 136        eval_col_ops_val_vec: &[Scalar],
 137        r: &[Scalar],
 138        gens: &PolyCommitmentGens,
 139        transcript: &mut PoseidonTranscript,
 140        random_tape: &mut RandomTape,
 141    ) -> Self {
 142        // transcript.append_protocol_name(DerefsEvalProof::protocol_name());
 143
 144        let evals = {
 145            let mut evals = eval_row_ops_val_vec.to_owned();
 146            evals.extend(eval_col_ops_val_vec);
 147            evals.resize(evals.len().next_power_of_two(), Scalar::zero());
 148            evals
 149        };
 150        let proof_derefs =
 151            DerefsEvalProof::prove_single(&derefs.comb, r, evals, gens, transcript, random_tape);
 152
 153        DerefsEvalProof { proof_derefs }
 154    }
 155
 156    fn verify_single(
 157        proof: &PolyEvalProof,
 158        comm: &PolyCommitment,
 159        r: &[Scalar],
 160        evals: Vec<Scalar>,
 161        gens: &PolyCommitmentGens,
 162        transcript: &mut PoseidonTranscript,
 163    ) -> Result<(), ProofVerifyError> {
 164        // append the claimed evaluations to transcript
 165        // evals.append_to_transcript(b"evals_ops_val", transcript);
 166        transcript.append_scalar_vector(&evals);
 167
 168        // n-to-1 reduction
 169        let challenges = transcript.challenge_vector(evals.len().log_2());
 170        let mut poly_evals = DensePolynomial::new(evals);
 171        for i in (0..challenges.len()).rev() {
 172            poly_evals.bound_poly_var_bot(&challenges[i]);
 173        }
 174        assert_eq!(poly_evals.len(), 1);
 175        let joint_claim_eval = poly_evals[0];
 176        let mut r_joint = challenges;
 177        r_joint.extend(r);
 178
 179        // decommit the joint polynomial at r_joint
 180        // joint_claim_eval.append_to_transcript(b"joint_claim_eval", transcript);
 181        transcript.append_scalar(&joint_claim_eval);
 182
 183        proof.verify_plain(gens, transcript, &r_joint, &joint_claim_eval, comm)
 184    }
 185
 186    // verify evaluations of both polynomials at r
 187    pub fn verify(
 188        &self,
 189        r: &[Scalar],
 190        eval_row_ops_val_vec: &[Scalar],
 191        eval_col_ops_val_vec: &[Scalar],
 192        gens: &PolyCommitmentGens,
 193        comm: &DerefsCommitment,
 194        transcript: &mut PoseidonTranscript,
 195    ) -> Result<(), ProofVerifyError> {
 196        // transcript.append_protocol_name(DerefsEvalProof::protocol_name());
 197        let mut evals = eval_row_ops_val_vec.to_owned();
 198        evals.extend(eval_col_ops_val_vec);
 199        evals.resize(evals.len().next_power_of_two(), Scalar::zero());
 200
 201        DerefsEvalProof::verify_single(
 202            &self.proof_derefs,
 203            &comm.comm_ops_val,
 204            r,
 205            evals,
 206            gens,
 207            transcript,
 208        )
 209    }
 210}
 211
 212impl AppendToTranscript for DerefsCommitment {
 213    fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
 214        transcript.append_message(b"derefs_commitment", b"begin_derefs_commitment");
 215        self.comm_ops_val.append_to_transcript(label, transcript);
 216        transcript.append_message(b"derefs_commitment", b"end_derefs_commitment");
 217    }
 218}
 219
 220impl AppendToPoseidon for DerefsCommitment {
 221    fn append_to_poseidon(&self, transcript: &mut PoseidonTranscript) {
 222        self.comm_ops_val.append_to_poseidon(transcript);
 223    }
 224}
 225struct AddrTimestamps {
 226    ops_addr_usize: Vec<Vec<usize>>,
 227    ops_addr: Vec<DensePolynomial>,
 228    read_ts: Vec<DensePolynomial>,
 229    audit_ts: DensePolynomial,
 230}
 231
 232impl AddrTimestamps {
 233    pub fn new(num_cells: usize, num_ops: usize, ops_addr: Vec<Vec<usize>>) -> Self {
 234        for item in ops_addr.iter() {
 235            assert_eq!(item.len(), num_ops);
 236        }
 237
 238        let mut audit_ts = vec![0usize; num_cells];
 239        let mut ops_addr_vec: Vec<DensePolynomial> = Vec::new();
 240        let mut read_ts_vec: Vec<DensePolynomial> = Vec::new();
 241        for ops_addr_inst in ops_addr.iter() {
 242            let mut read_ts = vec![0usize; num_ops];
 243
 244            // since read timestamps are trustworthy, we can simply increment the r-ts to obtain a w-ts
 245            // this is sufficient to ensure that the write-set, consisting of (addr, val, ts) tuples, is a set
 246            for i in 0..num_ops {
 247                let addr = ops_addr_inst[i];
 248                assert!(addr < num_cells);
 249                let r_ts = audit_ts[addr];
 250                read_ts[i] = r_ts;
 251
 252                let w_ts = r_ts + 1;
 253                audit_ts[addr] = w_ts;
 254            }
 255
 256            ops_addr_vec.push(DensePolynomial::from_usize(ops_addr_inst));
 257            read_ts_vec.push(DensePolynomial::from_usize(&read_ts));
 258        }
 259
 260        AddrTimestamps {
 261            ops_addr: ops_addr_vec,
 262            ops_addr_usize: ops_addr,
 263            read_ts: read_ts_vec,
 264            audit_ts: DensePolynomial::from_usize(&audit_ts),
 265        }
 266    }
 267
 268    fn deref_mem(addr: &[usize], mem_val: &[Scalar]) -> DensePolynomial {
 269        DensePolynomial::new(
 270            (0..addr.len())
 271                .map(|i| {
 272                    let a = addr[i];
 273                    mem_val[a]
 274                })
 275                .collect::<Vec<Scalar>>(),
 276        )
 277    }
 278
 279    pub fn deref(&self, mem_val: &[Scalar]) -> Vec<DensePolynomial> {
 280        (0..self.ops_addr.len())
 281            .map(|i| AddrTimestamps::deref_mem(&self.ops_addr_usize[i], mem_val))
 282            .collect::<Vec<DensePolynomial>>()
 283    }
 284}
 285
 286pub struct MultiSparseMatPolynomialAsDense {
 287    batch_size: usize,
 288    val: Vec<DensePolynomial>,
 289    row: AddrTimestamps,
 290    col: AddrTimestamps,
 291    comb_ops: DensePolynomial,
 292    comb_mem: DensePolynomial,
 293}
 294
 295pub struct SparseMatPolyCommitmentGens {
 296    gens_ops: PolyCommitmentGens,
 297    gens_mem: PolyCommitmentGens,
 298    gens_derefs: PolyCommitmentGens,
 299}
 300
 301impl SparseMatPolyCommitmentGens {
 302    pub fn new(
 303        label: &'static [u8],
 304        num_vars_x: usize,
 305        num_vars_y: usize,
 306        num_nz_entries: usize,
 307        batch_size: usize,
 308    ) -> SparseMatPolyCommitmentGens {
 309        let num_vars_ops = num_nz_entries.next_power_of_two().log_2()
 310            + (batch_size * 5).next_power_of_two().log_2();
 311        let num_vars_mem = if num_vars_x > num_vars_y {
 312            num_vars_x
 313        } else {
 314            num_vars_y
 315        } + 1;
 316        let num_vars_derefs = num_nz_entries.next_power_of_two().log_2()
 317            + (batch_size * 2).next_power_of_two().log_2();
 318
 319        let gens_ops = PolyCommitmentGens::new(num_vars_ops, label);
 320        let gens_mem = PolyCommitmentGens::new(num_vars_mem, label);
 321        let gens_derefs = PolyCommitmentGens::new(num_vars_derefs, label);
 322        SparseMatPolyCommitmentGens {
 323            gens_ops,
 324            gens_mem,
 325            gens_derefs,
 326        }
 327    }
 328}
 329
 330#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
 331pub struct SparseMatPolyCommitment {
 332    batch_size: usize,
 333    num_ops: usize,
 334    num_mem_cells: usize,
 335    comm_comb_ops: PolyCommitment,
 336    comm_comb_mem: PolyCommitment,
 337}
 338
 339impl AppendToTranscript for SparseMatPolyCommitment {
 340    fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
 341        transcript.append_u64(b"batch_size", self.batch_size as u64);
 342        transcript.append_u64(b"num_ops", self.num_ops as u64);
 343        transcript.append_u64(b"num_mem_cells", self.num_mem_cells as u64);
 344        self.comm_comb_ops
 345            .append_to_transcript(b"comm_comb_ops", transcript);
 346        self.comm_comb_mem
 347            .append_to_transcript(b"comm_comb_mem", transcript);
 348    }
 349}
 350
 351impl AppendToPoseidon for SparseMatPolyCommitment {
 352    fn append_to_poseidon(&self, transcript: &mut PoseidonTranscript) {
 353        transcript.append_u64(self.batch_size as u64);
 354        transcript.append_u64(self.num_ops as u64);
 355        transcript.append_u64(self.num_mem_cells as u64);
 356        self.comm_comb_ops.append_to_poseidon(transcript);
 357        self.comm_comb_mem.append_to_poseidon(transcript);
 358    }
 359}
 360
 361impl SparseMatPolynomial {
 362    pub fn new(num_vars_x: usize, num_vars_y: usize, M: Vec<SparseMatEntry>) -> Self {
 363        SparseMatPolynomial {
 364            num_vars_x,
 365            num_vars_y,
 366            M,
 367        }
 368    }
 369
 370    pub fn get_num_nz_entries(&self) -> usize {
 371        self.M.len().next_power_of_two()
 372    }
 373
 374    fn sparse_to_dense_vecs(&self, N: usize) -> (Vec<usize>, Vec<usize>, Vec<Scalar>) {
 375        assert!(N >= self.get_num_nz_entries());
 376        let mut ops_row: Vec<usize> = vec![0; N];
 377        let mut ops_col: Vec<usize> = vec![0; N];
 378        let mut val: Vec<Scalar> = vec![Scalar::zero(); N];
 379
 380        for i in 0..self.M.len() {
 381            ops_row[i] = self.M[i].row;
 382            ops_col[i] = self.M[i].col;
 383            val[i] = self.M[i].val;
 384        }
 385        (ops_row, ops_col, val)
 386    }
 387
 388    fn multi_sparse_to_dense_rep(
 389        sparse_polys: &[&SparseMatPolynomial],
 390    ) -> MultiSparseMatPolynomialAsDense {
 391        assert!(!sparse_polys.is_empty());
 392        for i in 1..sparse_polys.len() {
 393            assert_eq!(sparse_polys[i].num_vars_x, sparse_polys[0].num_vars_x);
 394            assert_eq!(sparse_polys[i].num_vars_y, sparse_polys[0].num_vars_y);
 395        }
 396
 397        let N = (0..sparse_polys.len())
 398            .map(|i| sparse_polys[i].get_num_nz_entries())
 399            .max()
 400            .unwrap()
 401            .next_power_of_two();
 402
 403        let mut ops_row_vec: Vec<Vec<usize>> = Vec::new();
 404        let mut ops_col_vec: Vec<Vec<usize>> = Vec::new();
 405        let mut val_vec: Vec<DensePolynomial> = Vec::new();
 406        for poly in sparse_polys {
 407            let (ops_row, ops_col, val) = poly.sparse_to_dense_vecs(N);
 408            ops_row_vec.push(ops_row);
 409            ops_col_vec.push(ops_col);
 410            val_vec.push(DensePolynomial::new(val));
 411        }
 412
 413        let any_poly = &sparse_polys[0];
 414
 415        let num_mem_cells = if any_poly.num_vars_x > any_poly.num_vars_y {
 416            any_poly.num_vars_x.pow2()
 417        } else {
 418            any_poly.num_vars_y.pow2()
 419        };
 420
 421        let row = AddrTimestamps::new(num_mem_cells, N, ops_row_vec);
 422        let col = AddrTimestamps::new(num_mem_cells, N, ops_col_vec);
 423
 424        // combine polynomials into a single polynomial for commitment purposes
 425        let comb_ops = DensePolynomial::merge(
 426            row.ops_addr
 427                .iter()
 428                .chain(row.read_ts.iter())
 429                .chain(col.ops_addr.iter())
 430                .chain(col.read_ts.iter())
 431                .chain(val_vec.iter()),
 432        );
 433        let mut comb_mem = row.audit_ts.clone();
 434        comb_mem.extend(&col.audit_ts);
 435
 436        MultiSparseMatPolynomialAsDense {
 437            batch_size: sparse_polys.len(),
 438            row,
 439            col,
 440            val: val_vec,
 441            comb_ops,
 442            comb_mem,
 443        }
 444    }
 445
 446    fn evaluate_with_tables(&self, eval_table_rx: &[Scalar], eval_table_ry: &[Scalar]) -> Scalar {
 447        assert_eq!(self.num_vars_x.pow2(), eval_table_rx.len());
 448        assert_eq!(self.num_vars_y.pow2(), eval_table_ry.len());
 449
 450        (0..self.M.len())
 451            .map(|i| {
 452                let row = self.M[i].row;
 453                let col = self.M[i].col;
 454                let val = &self.M[i].val;
 455                eval_table_rx[row] * eval_table_ry[col] * val
 456            })
 457            .sum()
 458    }
 459
 460    pub fn multi_evaluate(
 461        polys: &[&SparseMatPolynomial],
 462        rx: &[Scalar],
 463        ry: &[Scalar],
 464    ) -> Vec<Scalar> {
 465        let eval_table_rx = EqPolynomial::new(rx.to_vec()).evals();
 466        let eval_table_ry = EqPolynomial::new(ry.to_vec()).evals();
 467
 468        (0..polys.len())
 469            .map(|i| polys[i].evaluate_with_tables(&eval_table_rx, &eval_table_ry))
 470            .collect::<Vec<Scalar>>()
 471    }
 472
 473    pub fn multiply_vec(&self, num_rows: usize, num_cols: usize, z: &[Scalar]) -> Vec<Scalar> {
 474        assert_eq!(z.len(), num_cols);
 475
 476        (0..self.M.len())
 477            .map(|i| {
 478                let row = self.M[i].row;
 479                let col = self.M[i].col;
 480                let val = &self.M[i].val;
 481                (row, z[col] * val)
 482            })
 483            .fold(vec![Scalar::zero(); num_rows], |mut Mz, (r, v)| {
 484                Mz[r] += v;
 485                Mz
 486            })
 487    }
 488
 489    pub fn compute_eval_table_sparse(
 490        &self,
 491        rx: &[Scalar],
 492        num_rows: usize,
 493        num_cols: usize,
 494    ) -> Vec<Scalar> {
 495        assert_eq!(rx.len(), num_rows);
 496
 497        let mut M_evals: Vec<Scalar> = vec![Scalar::zero(); num_cols];
 498
 499        for i in 0..self.M.len() {
 500            let entry = &self.M[i];
 501            M_evals[entry.col] += rx[entry.row] * entry.val;
 502        }
 503        M_evals
 504    }
 505
 506    pub fn multi_commit(
 507        sparse_polys: &[&SparseMatPolynomial],
 508        gens: &SparseMatPolyCommitmentGens,
 509    ) -> (SparseMatPolyCommitment, MultiSparseMatPolynomialAsDense) {
 510        let batch_size = sparse_polys.len();
 511        let dense = SparseMatPolynomial::multi_sparse_to_dense_rep(sparse_polys);
 512
 513        let (comm_comb_ops, _blinds_comb_ops) = dense.comb_ops.commit(&gens.gens_ops, None);
 514        let (comm_comb_mem, _blinds_comb_mem) = dense.comb_mem.commit(&gens.gens_mem, None);
 515
 516        (
 517            SparseMatPolyCommitment {
 518                batch_size,
 519                num_mem_cells: dense.row.audit_ts.len(),
 520                num_ops: dense.row.read_ts[0].len(),
 521                comm_comb_ops,
 522                comm_comb_mem,
 523            },
 524            dense,
 525        )
 526    }
 527}
 528
 529impl MultiSparseMatPolynomialAsDense {
 530    pub fn deref(&self, row_mem_val: &[Scalar], col_mem_val: &[Scalar]) -> Derefs {
 531        let row_ops_val = self.row.deref(row_mem_val);
 532        let col_ops_val = self.col.deref(col_mem_val);
 533
 534        Derefs::new(row_ops_val, col_ops_val)
 535    }
 536}
 537
 538#[derive(Debug)]
 539struct ProductLayer {
 540    init: ProductCircuit,
 541    read_vec: Vec<ProductCircuit>,
 542    write_vec: Vec<ProductCircuit>,
 543    audit: ProductCircuit,
 544}
 545
 546#[derive(Debug)]
 547struct Layers {
 548    prod_layer: ProductLayer,
 549}
 550
 551impl Layers {
 552    fn build_hash_layer(
 553        eval_table: &[Scalar],
 554        addrs_vec: &[DensePolynomial],
 555        derefs_vec: &[DensePolynomial],
 556        read_ts_vec: &[DensePolynomial],
 557        audit_ts: &DensePolynomial,
 558        r_mem_check: &(Scalar, Scalar),
 559    ) -> (
 560        DensePolynomial,
 561        Vec<DensePolynomial>,
 562        Vec<DensePolynomial>,
 563        DensePolynomial,
 564    ) {
 565        let (r_hash, r_multiset_check) = r_mem_check;
 566
 567        //hash(addr, val, ts) = ts * r_hash_sqr + val * r_hash + addr
 568        let r_hash_sqr = r_hash.square();
 569        let hash_func = |addr: &Scalar, val: &Scalar, ts: &Scalar| -> Scalar {
 570            r_hash_sqr * ts + (*val) * r_hash + addr
 571        };
 572
 573        // hash init and audit that does not depend on #instances
 574        let num_mem_cells = eval_table.len();
 575        let poly_init_hashed = DensePolynomial::new(
 576            (0..num_mem_cells)
 577                .map(|i| {
 578                    // at init time, addr is given by i, init value is given by eval_table, and ts = 0
 579                    hash_func(&Scalar::from(i as u64), &eval_table[i], &Scalar::zero())
 580                        - r_multiset_check
 581                })
 582                .collect::<Vec<Scalar>>(),
 583        );
 584        let poly_audit_hashed = DensePolynomial::new(
 585            (0..num_mem_cells)
 586                .map(|i| {
 587                    // at audit time, addr is given by i, value is given by eval_table, and ts is given by audit_ts
 588                    hash_func(&Scalar::from(i as u64), &eval_table[i], &audit_ts[i])
 589                        - r_multiset_check
 590                })
 591                .collect::<Vec<Scalar>>(),
 592        );
 593
 594        // hash read and write that depends on #instances
 595        let mut poly_read_hashed_vec: Vec<DensePolynomial> = Vec::new();
 596        let mut poly_write_hashed_vec: Vec<DensePolynomial> = Vec::new();
 597        for i in 0..addrs_vec.len() {
 598            let (addrs, derefs, read_ts) = (&addrs_vec[i], &derefs_vec[i], &read_ts_vec[i]);
 599            assert_eq!(addrs.len(), derefs.len());
 600            assert_eq!(addrs.len(), read_ts.len());
 601            let num_ops = addrs.len();
 602            let poly_read_hashed = DensePolynomial::new(
 603                (0..num_ops)
 604                    .map(|i| {
 605                        // at read time, addr is given by addrs, value is given by derefs, and ts is given by read_ts
 606                        hash_func(&addrs[i], &derefs[i], &read_ts[i]) - r_multiset_check
 607                    })
 608                    .collect::<Vec<Scalar>>(),
 609            );
 610            poly_read_hashed_vec.push(poly_read_hashed);
 611
 612            let poly_write_hashed = DensePolynomial::new(
 613                (0..num_ops)
 614                    .map(|i| {
 615                        // at write time, addr is given by addrs, value is given by derefs, and ts is given by write_ts = read_ts + 1
 616                        hash_func(&addrs[i], &derefs[i], &(read_ts[i] + Scalar::one()))
 617                            - r_multiset_check
 618                    })
 619                    .collect::<Vec<Scalar>>(),
 620            );
 621            poly_write_hashed_vec.push(poly_write_hashed);
 622        }
 623
 624        (
 625            poly_init_hashed,
 626            poly_read_hashed_vec,
 627            poly_write_hashed_vec,
 628            poly_audit_hashed,
 629        )
 630    }
 631
 632    pub fn new(
 633        eval_table: &[Scalar],
 634        addr_timestamps: &AddrTimestamps,
 635        poly_ops_val: &[DensePolynomial],
 636        r_mem_check: &(Scalar, Scalar),
 637    ) -> Self {
 638        let (poly_init_hashed, poly_read_hashed_vec, poly_write_hashed_vec, poly_audit_hashed) =
 639            Layers::build_hash_layer(
 640                eval_table,
 641                &addr_timestamps.ops_addr,
 642                poly_ops_val,
 643                &addr_timestamps.read_ts,
 644                &addr_timestamps.audit_ts,
 645                r_mem_check,
 646            );
 647
 648        let prod_init = ProductCircuit::new(&poly_init_hashed);
 649        let prod_read_vec = (0..poly_read_hashed_vec.len())
 650            .map(|i| ProductCircuit::new(&poly_read_hashed_vec[i]))
 651            .collect::<Vec<ProductCircuit>>();
 652        let prod_write_vec = (0..poly_write_hashed_vec.len())
 653            .map(|i| ProductCircuit::new(&poly_write_hashed_vec[i]))
 654            .collect::<Vec<ProductCircuit>>();
 655        let prod_audit = ProductCircuit::new(&poly_audit_hashed);
 656
 657        // subset audit check
 658        let hashed_writes: Scalar = (0..prod_write_vec.len())
 659            .map(|i| prod_write_vec[i].evaluate())
 660            .product();
 661        let hashed_write_set: Scalar = prod_init.evaluate() * hashed_writes;
 662
 663        let hashed_reads: Scalar = (0..prod_read_vec.len())
 664            .map(|i| prod_read_vec[i].evaluate())
 665            .product();
 666        let hashed_read_set: Scalar = hashed_reads * prod_audit.evaluate();
 667
 668        //assert_eq!(hashed_read_set, hashed_write_set);
 669        debug_assert_eq!(hashed_read_set, hashed_write_set);
 670
 671        Layers {
 672            prod_layer: ProductLayer {
 673                init: prod_init,
 674                read_vec: prod_read_vec,
 675                write_vec: prod_write_vec,
 676                audit: prod_audit,
 677            },
 678        }
 679    }
 680}
 681
 682#[derive(Debug)]
 683struct PolyEvalNetwork {
 684    row_layers: Layers,
 685    col_layers: Layers,
 686}
 687
 688impl PolyEvalNetwork {
 689    pub fn new(
 690        dense: &MultiSparseMatPolynomialAsDense,
 691        derefs: &Derefs,
 692        mem_rx: &[Scalar],
 693        mem_ry: &[Scalar],
 694        r_mem_check: &(Scalar, Scalar),
 695    ) -> Self {
 696        let row_layers = Layers::new(mem_rx, &dense.row, &derefs.row_ops_val, r_mem_check);
 697        let col_layers = Layers::new(mem_ry, &dense.col, &derefs.col_ops_val, r_mem_check);
 698
 699        PolyEvalNetwork {
 700            row_layers,
 701            col_layers,
 702        }
 703    }
 704}
 705
 706#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
 707struct HashLayerProof {
 708    eval_row: (Vec<Scalar>, Vec<Scalar>, Scalar),
 709    eval_col: (Vec<Scalar>, Vec<Scalar>, Scalar),
 710    eval_val: Vec<Scalar>,
 711    eval_derefs: (Vec<Scalar>, Vec<Scalar>),
 712    proof_ops: PolyEvalProof,
 713    proof_mem: PolyEvalProof,
 714    proof_derefs: DerefsEvalProof,
 715}
 716
 717impl HashLayerProof {
 718    fn protocol_name() -> &'static [u8] {
 719        b"Sparse polynomial hash layer proof"
 720    }
 721
 722    fn prove_helper(
 723        rand: (&Vec<Scalar>, &Vec<Scalar>),
 724        addr_timestamps: &AddrTimestamps,
 725    ) -> (Vec<Scalar>, Vec<Scalar>, Scalar) {
 726        let (rand_mem, rand_ops) = rand;
 727
 728        // decommit ops-addr at rand_ops
 729        let mut eval_ops_addr_vec: Vec<Scalar> = Vec::new();
 730        for i in 0..addr_timestamps.ops_addr.len() {
 731            let eval_ops_addr = addr_timestamps.ops_addr[i].evaluate(rand_ops);
 732            eval_ops_addr_vec.push(eval_ops_addr);
 733        }
 734
 735        // decommit read_ts at rand_ops
 736        let mut eval_read_ts_vec: Vec<Scalar> = Vec::new();
 737        for i in 0..addr_timestamps.read_ts.len() {
 738            let eval_read_ts = addr_timestamps.read_ts[i].evaluate(rand_ops);
 739            eval_read_ts_vec.push(eval_read_ts);
 740        }
 741
 742        // decommit audit-ts at rand_mem
 743        let eval_audit_ts = addr_timestamps.audit_ts.evaluate(rand_mem);
 744
 745        (eval_ops_addr_vec, eval_read_ts_vec, eval_audit_ts)
 746    }
 747
 748    fn prove(
 749        rand: (&Vec<Scalar>, &Vec<Scalar>),
 750        dense: &MultiSparseMatPolynomialAsDense,
 751        derefs: &Derefs,
 752        gens: &SparseMatPolyCommitmentGens,
 753        transcript: &mut PoseidonTranscript,
 754        random_tape: &mut RandomTape,
 755    ) -> Self {
 756        // transcript.append_protocol_name(HashLayerProof::protocol_name());
 757
 758        let (rand_mem, rand_ops) = rand;
 759
 760        // decommit derefs at rand_ops
 761        let eval_row_ops_val = (0..derefs.row_ops_val.len())
 762            .map(|i| derefs.row_ops_val[i].evaluate(rand_ops))
 763            .collect::<Vec<Scalar>>();
 764        let eval_col_ops_val = (0..derefs.col_ops_val.len())
 765            .map(|i| derefs.col_ops_val[i].evaluate(rand_ops))
 766            .collect::<Vec<Scalar>>();
 767        let proof_derefs = DerefsEvalProof::prove(
 768            derefs,
 769            &eval_row_ops_val,
 770            &eval_col_ops_val,
 771            rand_ops,
 772            &gens.gens_derefs,
 773            transcript,
 774            random_tape,
 775        );
 776        let eval_derefs = (eval_row_ops_val, eval_col_ops_val);
 777
 778        // evaluate row_addr, row_read-ts, col_addr, col_read-ts, val at rand_ops
 779        // evaluate row_audit_ts and col_audit_ts at rand_mem
 780        let (eval_row_addr_vec, eval_row_read_ts_vec, eval_row_audit_ts) =
 781            HashLayerProof::prove_helper((rand_mem, rand_ops), &dense.row);
 782        let (eval_col_addr_vec, eval_col_read_ts_vec, eval_col_audit_ts) =
 783            HashLayerProof::prove_helper((rand_mem, rand_ops), &dense.col);
 784        let eval_val_vec = (0..dense.val.len())
 785            .map(|i| dense.val[i].evaluate(rand_ops))
 786            .collect::<Vec<Scalar>>();
 787
 788        // form a single decommitment using comm_comb_ops
 789        let mut evals_ops: Vec<Scalar> = Vec::new();
 790        evals_ops.extend(&eval_row_addr_vec);
 791        evals_ops.extend(&eval_row_read_ts_vec);
 792        evals_ops.extend(&eval_col_addr_vec);
 793        evals_ops.extend(&eval_col_read_ts_vec);
 794        evals_ops.extend(&eval_val_vec);
 795        evals_ops.resize(evals_ops.len().next_power_of_two(), Scalar::zero());
 796        transcript.append_scalar_vector(&evals_ops);
 797        let challenges_ops = transcript.challenge_vector(evals_ops.len().log_2());
 798
 799        let mut poly_evals_ops = DensePolynomial::new(evals_ops);
 800        for i in (0..challenges_ops.len()).rev() {
 801            poly_evals_ops.bound_poly_var_bot(&challenges_ops[i]);
 802        }
 803        assert_eq!(poly_evals_ops.len(), 1);
 804        let joint_claim_eval_ops = poly_evals_ops[0];
 805        let mut r_joint_ops = challenges_ops;
 806        r_joint_ops.extend(rand_ops);
 807        debug_assert_eq!(dense.comb_ops.evaluate(&r_joint_ops), joint_claim_eval_ops);
 808        transcript.append_scalar(&joint_claim_eval_ops);
 809        let (proof_ops, _comm_ops_eval) = PolyEvalProof::prove(
 810            &dense.comb_ops,
 811            None,
 812            &r_joint_ops,
 813            &joint_claim_eval_ops,
 814            None,
 815            &gens.gens_ops,
 816            transcript,
 817            random_tape,
 818        );
 819
 820        // form a single decommitment using comb_comb_mem at rand_mem
 821        let evals_mem: Vec<Scalar> = vec![eval_row_audit_ts, eval_col_audit_ts];
 822        // evals_mem.append_to_transcript(b"claim_evals_mem", transcript);
 823        transcript.append_scalar_vector(&evals_mem);
 824        let challenges_mem = transcript.challenge_vector(evals_mem.len().log_2());
 825
 826        let mut poly_evals_mem = DensePolynomial::new(evals_mem);
 827        for i in (0..challenges_mem.len()).rev() {
 828            poly_evals_mem.bound_poly_var_bot(&challenges_mem[i]);
 829        }
 830        assert_eq!(poly_evals_mem.len(), 1);
 831        let joint_claim_eval_mem = poly_evals_mem[0];
 832        let mut r_joint_mem = challenges_mem;
 833        r_joint_mem.extend(rand_mem);
 834        debug_assert_eq!(dense.comb_mem.evaluate(&r_joint_mem), joint_claim_eval_mem);
 835        transcript.append_scalar(&joint_claim_eval_mem);
 836        let (proof_mem, _comm_mem_eval) = PolyEvalProof::prove(
 837            &dense.comb_mem,
 838            None,
 839            &r_joint_mem,
 840            &joint_claim_eval_mem,
 841            None,
 842            &gens.gens_mem,
 843            transcript,
 844            random_tape,
 845        );
 846
 847        HashLayerProof {
 848            eval_row: (eval_row_addr_vec, eval_row_read_ts_vec, eval_row_audit_ts),
 849            eval_col: (eval_col_addr_vec, eval_col_read_ts_vec, eval_col_audit_ts),
 850            eval_val: eval_val_vec,
 851            eval_derefs,
 852            proof_ops,
 853            proof_mem,
 854            proof_derefs,
 855        }
 856    }
 857
 858    fn verify_helper(
 859        rand: &(&Vec<Scalar>, &Vec<Scalar>),
 860        claims: &(Scalar, Vec<Scalar>, Vec<Scalar>, Scalar),
 861        eval_ops_val: &[Scalar],
 862        eval_ops_addr: &[Scalar],
 863        eval_read_ts: &[Scalar],
 864        eval_audit_ts: &Scalar,
 865        r: &[Scalar],
 866        r_hash: &Scalar,
 867        r_multiset_check: &Scalar,
 868    ) -> Result<(), ProofVerifyError> {
 869        let r_hash_sqr = r_hash.square();
 870        let hash_func = |addr: &Scalar, val: &Scalar, ts: &Scalar| -> Scalar {
 871            r_hash_sqr * ts + (*val) * r_hash + addr
 872        };
 873
 874        let (rand_mem, _rand_ops) = rand;
 875        let (claim_init, claim_read, claim_write, claim_audit) = claims;
 876
 877        // init
 878        let eval_init_addr = IdentityPolynomial::new(rand_mem.len()).evaluate(rand_mem);
 879        let eval_init_val = EqPolynomial::new(r.to_vec()).evaluate(rand_mem);
 880        let hash_init_at_rand_mem =
 881            hash_func(&eval_init_addr, &eval_init_val, &Scalar::zero()) - r_multiset_check; // verify the claim_last of init chunk
 882        assert_eq!(&hash_init_at_rand_mem, claim_init);
 883
 884        // read
 885        for i in 0..eval_ops_addr.len() {
 886            let hash_read_at_rand_ops =
 887                hash_func(&eval_ops_addr[i], &eval_ops_val[i], &eval_read_ts[i]) - r_multiset_check; // verify the claim_last of init chunk
 888            assert_eq!(&hash_read_at_rand_ops, &claim_read[i]);
 889        }
 890
 891        // write: shares addr, val component; only decommit write_ts
 892        for i in 0..eval_ops_addr.len() {
 893            let eval_write_ts = eval_read_ts[i] + Scalar::one();
 894            let hash_write_at_rand_ops =
 895                hash_func(&eval_ops_addr[i], &eval_ops_val[i], &eval_write_ts) - r_multiset_check; // verify the claim_last of init chunk
 896            assert_eq!(&hash_write_at_rand_ops, &claim_write[i]);
 897        }
 898
 899        // audit: shares addr and val with init
 900        let eval_audit_addr = eval_init_addr;
 901        let eval_audit_val = eval_init_val;
 902        let hash_audit_at_rand_mem =
 903            hash_func(&eval_audit_addr, &eval_audit_val, eval_audit_ts) - r_multiset_check;
 904        assert_eq!(&hash_audit_at_rand_mem, claim_audit); // verify the last step of the sum-check for audit
 905
 906        Ok(())
 907    }
 908
 909    fn verify(
 910        &self,
 911        rand: (&Vec<Scalar>, &Vec<Scalar>),
 912        claims_row: &(Scalar, Vec<Scalar>, Vec<Scalar>, Scalar),
 913        claims_col: &(Scalar, Vec<Scalar>, Vec<Scalar>, Scalar),
 914        claims_dotp: &[Scalar],
 915        comm: &SparseMatPolyCommitment,
 916        gens: &SparseMatPolyCommitmentGens,
 917        comm_derefs: &DerefsCommitment,
 918        rx: &[Scalar],
 919        ry: &[Scalar],
 920        r_hash: &Scalar,
 921        r_multiset_check: &Scalar,
 922        transcript: &mut PoseidonTranscript,
 923    ) -> Result<(), ProofVerifyError> {
 924        let timer = Timer::new("verify_hash_proof");
 925        // transcript.append_protocol_name(HashLayerProof::protocol_name());
 926
 927        let (rand_mem, rand_ops) = rand;
 928
 929        // verify derefs at rand_ops
 930        let (eval_row_ops_val, eval_col_ops_val) = &self.eval_derefs;
 931        assert_eq!(eval_row_ops_val.len(), eval_col_ops_val.len());
 932        self.proof_derefs.verify(
 933            rand_ops,
 934            eval_row_ops_val,
 935            eval_col_ops_val,
 936            &gens.gens_derefs,
 937            comm_derefs,
 938            transcript,
 939        )?;
 940
 941        // verify the decommitments used in evaluation sum-check
 942        let eval_val_vec = &self.eval_val;
 943        assert_eq!(claims_dotp.len(), 3 * eval_row_ops_val.len());
 944        for i in 0..claims_dotp.len() / 3 {
 945            let claim_row_ops_val = claims_dotp[3 * i];
 946            let claim_col_ops_val = claims_dotp[3 * i + 1];
 947            let claim_val = claims_dotp[3 * i + 2];
 948
 949            assert_eq!(claim_row_ops_val, eval_row_ops_val[i]);
 950            assert_eq!(claim_col_ops_val, eval_col_ops_val[i]);
 951            assert_eq!(claim_val, eval_val_vec[i]);
 952        }
 953
 954        // verify addr-timestamps using comm_comb_ops at rand_ops
 955        let (eval_row_addr_vec, eval_row_read_ts_vec, eval_row_audit_ts) = &self.eval_row;
 956        let (eval_col_addr_vec, eval_col_read_ts_vec, eval_col_audit_ts) = &self.eval_col;
 957
 958        let mut evals_ops: Vec<Scalar> = Vec::new();
 959        evals_ops.extend(eval_row_addr_vec);
 960        evals_ops.extend(eval_row_read_ts_vec);
 961        evals_ops.extend(eval_col_addr_vec);
 962        evals_ops.extend(eval_col_read_ts_vec);
 963        evals_ops.extend(eval_val_vec);
 964        evals_ops.resize(evals_ops.len().next_power_of_two(), Scalar::zero());
 965        transcript.append_scalar_vector(&evals_ops);
 966        // evals_ops.append_to_transcript(b"claim_evals_ops", transcript);
 967        let challenges_ops = transcript.challenge_vector(evals_ops.len().log_2());
 968
 969        let mut poly_evals_ops = DensePolynomial::new(evals_ops);
 970        for i in (0..challenges_ops.len()).rev() {
 971            poly_evals_ops.bound_poly_var_bot(&challenges_ops[i]);
 972        }
 973        assert_eq!(poly_evals_ops.len(), 1);
 974        let joint_claim_eval_ops = poly_evals_ops[0];
 975        let mut r_joint_ops = challenges_ops;
 976        r_joint_ops.extend(rand_ops);
 977        transcript.append_scalar(&joint_claim_eval_ops);
 978        assert!(self
 979            .proof_ops
 980            .verify_plain(
 981                &gens.gens_ops,
 982                transcript,
 983                &r_joint_ops,
 984                &joint_claim_eval_ops,
 985                &comm.comm_comb_ops
 986            )
 987            .is_ok());
 988
 989        // verify proof-mem using comm_comb_mem at rand_mem
 990        // form a single decommitment using comb_comb_mem at rand_mem
 991        let evals_mem: Vec<Scalar> = vec![*eval_row_audit_ts, *eval_col_audit_ts];
 992        // evals_mem.append_to_transcript(b"claim_evals_mem", transcript);
 993        transcript.append_scalar_vector(&evals_mem);
 994        let challenges_mem = transcript.challenge_vector(evals_mem.len().log_2());
 995
 996        let mut poly_evals_mem = DensePolynomial::new(evals_mem);
 997        for i in (0..challenges_mem.len()).rev() {
 998            poly_evals_mem.bound_poly_var_bot(&challenges_mem[i]);
 999        }
1000        assert_eq!(poly_evals_mem.len(), 1);
1001        let joint_claim_eval_mem = poly_evals_mem[0];
1002        let mut r_joint_mem = challenges_mem;
1003        r_joint_mem.extend(rand_mem);
1004        // joint_claim_eval_mem.append_to_transcript(b"joint_claim_eval_mem", transcript);
1005        transcript.append_scalar(&joint_claim_eval_mem);
1006        self.proof_mem.verify_plain(
1007            &gens.gens_mem,
1008            transcript,
1009            &r_joint_mem,
1010            &joint_claim_eval_mem,
1011            &comm.comm_comb_mem,
1012        )?;
1013
1014        // verify the claims from the product layer
1015        let (eval_ops_addr, eval_read_ts, eval_audit_ts) = &self.eval_row;
1016        HashLayerProof::verify_helper(
1017            &(rand_mem, rand_ops),
1018            claims_row,
1019            eval_row_ops_val,
1020            eval_ops_addr,
1021            eval_read_ts,
1022            eval_audit_ts,
1023            rx,
1024            r_hash,
1025            r_multiset_check,
1026        )?;
1027
1028        let (eval_ops_addr, eval_read_ts, eval_audit_ts) = &self.eval_col;
1029        HashLayerProof::verify_helper(
1030            &(rand_mem, rand_ops),
1031            claims_col,
1032            eval_col_ops_val,
1033            eval_ops_addr,
1034            eval_read_ts,
1035            eval_audit_ts,
1036            ry,
1037            r_hash,
1038            r_multiset_check,
1039        )?;
1040
1041        timer.stop();
1042        Ok(())
1043    }
1044}
1045
1046#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
1047struct ProductLayerProof {
1048    eval_row: (Scalar, Vec<Scalar>, Vec<Scalar>, Scalar),
1049    eval_col: (Scalar, Vec<Scalar>, Vec<Scalar>, Scalar),
1050    eval_val: (Vec<Scalar>, Vec<Scalar>),
1051    proof_mem: ProductCircuitEvalProofBatched,
1052    proof_ops: ProductCircuitEvalProofBatched,
1053}
1054
1055impl ProductLayerProof {
1056    fn protocol_name() -> &'static [u8] {
1057        b"Sparse polynomial product layer proof"
1058    }
1059
1060    pub fn prove(
1061        row_prod_layer: &mut ProductLayer,
1062        col_prod_layer: &mut ProductLayer,
1063        dense: &MultiSparseMatPolynomialAsDense,
1064        derefs: &Derefs,
1065        eval: &[Scalar],
1066        transcript: &mut PoseidonTranscript,
1067    ) -> (Self, Vec<Scalar>, Vec<Scalar>) {
1068        // transcript.append_protocol_name(ProductLayerProof::protocol_name());
1069
1070        let row_eval_init = row_prod_layer.init.evaluate();
1071        let row_eval_audit = row_prod_layer.audit.evaluate();
1072        let row_eval_read = (0..row_prod_layer.read_vec.len())
1073            .map(|i| row_prod_layer.read_vec[i].evaluate())
1074            .collect::<Vec<Scalar>>();
1075        let row_eval_write = (0..row_prod_layer.write_vec.len())
1076            .map(|i| row_prod_layer.write_vec[i].evaluate())
1077            .collect::<Vec<Scalar>>();
1078
1079        // subset check
1080        let ws: Scalar = (0..row_eval_write.len())
1081            .map(|i| row_eval_write[i])
1082            .product();
1083        let rs: Scalar = (0..row_eval_read.len()).map(|i| row_eval_read[i]).product();
1084        assert_eq!(row_eval_init * ws, rs * row_eval_audit);
1085
1086        transcript.append_scalar(&row_eval_init);
1087        transcript.append_scalar_vector(&row_eval_read);
1088        transcript.append_scalar_vector(&row_eval_write);
1089        transcript.append_scalar(&row_eval_audit);
1090
1091        let col_eval_init = col_prod_layer.init.evaluate();
1092        let col_eval_audit = col_prod_layer.audit.evaluate();
1093        let col_eval_read: Vec<Scalar> = (0..col_prod_layer.read_vec.len())
1094            .map(|i| col_prod_layer.read_vec[i].evaluate())
1095            .collect();
1096        let col_eval_write: Vec<Scalar> = (0..col_prod_layer.write_vec.len())
1097            .map(|i| col_prod_layer.write_vec[i].evaluate())
1098            .collect();
1099
1100        // subset check
1101        let ws: Scalar = (0..col_eval_write.len())
1102            .map(|i| col_eval_write[i])
1103            .product();
1104        let rs: Scalar = (0..col_eval_read.len()).map(|i| col_eval_read[i]).product();
1105        assert_eq!(col_eval_init * ws, rs * col_eval_audit);
1106
1107        transcript.append_scalar(&col_eval_init);
1108        transcript.append_scalar_vector(&col_eval_read);
1109        transcript.append_scalar_vector(&col_eval_write);
1110        transcript.append_scalar(&col_eval_audit);
1111
1112        // prepare dotproduct circuit for batching then with ops-related product circuits
1113        assert_eq!(eval.len(), derefs.row_ops_val.len());
1114        assert_eq!(eval.len(), derefs.col_ops_val.len());
1115        assert_eq!(eval.len(), dense.val.len());
1116        let mut dotp_circuit_left_vec: Vec<DotProductCircuit> = Vec::new();
1117        let mut dotp_circuit_right_vec: Vec<DotProductCircuit> = Vec::new();
1118        let mut eval_dotp_left_vec: Vec<Scalar> = Vec::new();
1119        let mut eval_dotp_right_vec: Vec<Scalar> = Vec::new();
1120        for i in 0..derefs.row_ops_val.len() {
1121            // evaluate sparse polynomial evaluation using two dotp checks
1122            let left = derefs.row_ops_val[i].clone();
1123            let right = derefs.col_ops_val[i].clone();
1124            let weights = dense.val[i].clone();
1125
1126            // build two dot product circuits to prove evaluation of sparse polynomial
1127            let mut dotp_circuit = DotProductCircuit::new(left, right, weights);
1128            let (dotp_circuit_left, dotp_circuit_right) = dotp_circuit.split();
1129
1130            let (eval_dotp_left, eval_dotp_right) =
1131                (dotp_circuit_left.evaluate(), dotp_circuit_right.evaluate());
1132
1133            // eval_dotp_left.append_to_transcript(b"claim_eval_dotp_left", transcript);
1134            // eval_dotp_right.append_to_transcript(b"claim_eval_dotp_right", transcript);
1135            transcript.append_scalar(&eval_dotp_left);
1136            transcript.append_scalar(&eval_dotp_right);
1137            assert_eq!(eval_dotp_left + eval_dotp_right, eval[i]);
1138            eval_dotp_left_vec.push(eval_dotp_left);
1139            eval_dotp_right_vec.push(eval_dotp_right);
1140
1141            dotp_circuit_left_vec.push(dotp_circuit_left);
1142            dotp_circuit_right_vec.push(dotp_circuit_right);
1143        }
1144
1145        // The number of operations into the memory encoded by rx and ry are always the same (by design)
1146        // So we can produce a batched product proof for all of them at the same time.
1147        // prove the correctness of claim_row_eval_read, claim_row_eval_write, claim_col_eval_read, and claim_col_eval_write
1148        // TODO: we currently only produce proofs for 3 batched sparse polynomial evaluations
1149        assert_eq!(row_prod_layer.read_vec.len(), 3);
1150        let (row_read_A, row_read_B, row_read_C) = {
1151            let (vec_A, vec_BC) = row_prod_layer.read_vec.split_at_mut(1);
1152            let (vec_B, vec_C) = vec_BC.split_at_mut(1);
1153            (vec_A, vec_B, vec_C)
1154        };
1155
1156        let (row_write_A, row_write_B, row_write_C) = {
1157            let (vec_A, vec_BC) = row_prod_layer.write_vec.split_at_mut(1);
1158            let (vec_B, vec_C) = vec_BC.split_at_mut(1);
1159            (vec_A, vec_B, vec_C)
1160        };
1161
1162        let (col_read_A, col_read_B, col_read_C) = {
1163            let (vec_A, vec_BC) = col_prod_layer.read_vec.split_at_mut(1);
1164            let (vec_B, vec_C) = vec_BC.split_at_mut(1);
1165            (vec_A, vec_B, vec_C)
1166        };
1167
1168        let (col_write_A, col_write_B, col_write_C) = {
1169            let (vec_A, vec_BC) = col_prod_layer.write_vec.split_at_mut(1);
1170            let (vec_B, vec_C) = vec_BC.split_at_mut(1);
1171            (vec_A, vec_B, vec_C)
1172        };
1173
1174        let (dotp_left_A, dotp_left_B, dotp_left_C) = {
1175            let (vec_A, vec_BC) = dotp_circuit_left_vec.split_at_mut(1);
1176            let (vec_B, vec_C) = vec_BC.split_at_mut(1);
1177            (vec_A, vec_B, vec_C)
1178        };
1179
1180        let (dotp_right_A, dotp_right_B, dotp_right_C) = {
1181            let (vec_A, vec_BC) = dotp_circuit_right_vec.split_at_mut(1);
1182            let (vec_B, vec_C) = vec_BC.split_at_mut(1);
1183            (vec_A, vec_B, vec_C)
1184        };
1185
1186        let (proof_ops, rand_ops) = ProductCircuitEvalProofBatched::prove(
1187            &mut vec![
1188                &mut row_read_A[0],
1189                &mut row_read_B[0],
1190                &mut row_read_C[0],
1191                &mut row_write_A[0],
1192                &mut row_write_B[0],
1193                &mut row_write_C[0],
1194                &mut col_read_A[0],
1195                &mut col_read_B[0],
1196                &mut col_read_C[0],
1197                &mut col_write_A[0],
1198                &mut col_write_B[0],
1199                &mut col_write_C[0],
1200            ],
1201            &mut vec![
1202                &mut dotp_left_A[0],
1203                &mut dotp_right_A[0],
1204                &mut dotp_left_B[0],
1205                &mut dotp_right_B[0],
1206                &mut dotp_left_C[0],
1207                &mut dotp_right_C[0],
1208            ],
1209            transcript,
1210        );
1211
1212        // produce a batched proof of memory-related product circuits
1213        let (proof_mem, rand_mem) = ProductCircuitEvalProofBatched::prove(
1214            &mut vec![
1215                &mut row_prod_layer.init,
1216                &mut row_prod_layer.audit,
1217                &mut col_prod_layer.init,
1218                &mut col_prod_layer.audit,
1219            ],
1220            &mut Vec::new(),
1221            transcript,
1222        );
1223
1224        let product_layer_proof = ProductLayerProof {
1225            eval_row: (row_eval_init, row_eval_read, row_eval_write, row_eval_audit),
1226            eval_col: (col_eval_init, col_eval_read, col_eval_write, col_eval_audit),
1227            eval_val: (eval_dotp_left_vec, eval_dotp_right_vec),
1228            proof_mem,
1229            proof_ops,
1230        };
1231
1232        let mut product_layer_proof_encoded: Vec<u8> = Vec::new();
1233        product_layer_proof
1234            .serialize(&mut product_layer_proof_encoded)
1235            .unwrap();
1236        let msg = format!(
1237            "len_product_layer_proof {:?}",
1238            product_layer_proof_encoded.len()
1239        );
1240        Timer::print(&msg);
1241
1242        (product_layer_proof, rand_mem, rand_ops)
1243    }
1244
1245    pub fn verify(
1246        &self,
1247        num_ops: usize,
1248        num_cells: usize,
1249        eval: &[Scalar],
1250        transcript: &mut PoseidonTranscript,
1251    ) -> Result<
1252        (
1253            Vec<Scalar>,
1254            Vec<Scalar>,
1255            Vec<Scalar>,
1256            Vec<Scalar>,
1257            Vec<Scalar>,
1258        ),
1259        ProofVerifyError,
1260    > {
1261        // transcript.append_protocol_name(ProductLayerProof::protocol_name());
1262
1263        let timer = Timer::new("verify_prod_proof");
1264        let num_instances = eval.len();
1265
1266        // subset check
1267        let (row_eval_init, row_eval_read, row_eval_write, row_eval_audit) = &self.eval_row;
1268        assert_eq!(row_eval_write.len(), num_instances);
1269        assert_eq!(row_eval_read.len(), num_instances);
1270        let ws: Scalar = (0..row_eval_write.len())
1271            .map(|i| row_eval_write[i])
1272            .product();
1273        let rs: Scalar = (0..row_eval_read.len()).map(|i| row_eval_read[i]).product();
1274        assert_eq!(ws * row_eval_init, rs * row_eval_audit);
1275
1276        // row_eval_init.append_to_transcript(b"claim_row_eval_init", transcript);
1277        // row_eval_read.append_to_transcript(b"claim_row_eval_read", transcript);
1278        // row_eval_write.append_to_transcript(b"claim_row_eval_write", transcript);
1279        // row_eval_audit.append_to_transcript(b"claim_row_eval_audit", transcript);
1280
1281        transcript.append_scalar(row_eval_init);
1282        transcript.append_scalar_vector(row_eval_read);
1283        transcript.append_scalar_vector(row_eval_write);
1284        transcript.append_scalar(row_eval_audit);
1285
1286        // subset check
1287        let (col_eval_init, col_eval_read, col_eval_write, col_eval_audit) = &self.eval_col;
1288        assert_eq!(col_eval_write.len(), num_instances);
1289        assert_eq!(col_eval_read.len(), num_instances);
1290        let ws: Scalar = (0..col_eval_write.len())
1291            .map(|i| col_eval_write[i])
1292            .product();
1293        let rs: Scalar = (0..col_eval_read.len()).map(|i| col_eval_read[i]).product();
1294        assert_eq!(ws * col_eval_init, rs * col_eval_audit);
1295
1296        // col_eval_init.append_to_transcript(b"claim_col_eval_init", transcript);
1297        // col_eval_read.append_to_transcript(b"claim_col_eval_read", transcript);
1298        // col_eval_write.append_to_transcript(b"claim_col_eval_write", transcript);
1299        // col_eval_audit.append_to_transcript(b"claim_col_eval_audit", transcript);
1300
1301        transcript.append_scalar(col_eval_init);
1302        transcript.append_scalar_vector(col_eval_read);
1303        transcript.append_scalar_vector(col_eval_write);
1304        transcript.append_scalar(col_eval_audit);
1305
1306        // verify the evaluation of the sparse polynomial
1307        let (eval_dotp_left, eval_dotp_right) = &self.eval_val;
1308        assert_eq!(eval_dotp_left.len(), eval_dotp_left.len());
1309        assert_eq!(eval_dotp_left.len(), num_instances);
1310        let mut claims_dotp_circuit: Vec<Scalar> = Vec::new();
1311        for i in 0..num_instances {
1312            assert_eq!(eval_dotp_left[i] + eval_dotp_right[i], eval[i]);
1313            // eval_dotp_left[i].append_to_transcript(b"claim_eval_dotp_left", transcript);
1314            // eval_dotp_right[i].append_to_transcript(b"claim_eval_dotp_right", transcript)
1315            transcript.append_scalar(&eval_dotp_left[i]);
1316            transcript.append_scalar(&eval_dotp_right[i]);
1317
1318            claims_dotp_circuit.push(eval_dotp_left[i]);
1319            claims_dotp_circuit.push(eval_dotp_right[i]);
1320        }
1321
1322        // verify the correctness of claim_row_eval_read, claim_row_eval_write, claim_col_eval_read, and claim_col_eval_write
1323        let mut claims_prod_circuit: Vec<Scalar> = Vec::new();
1324        claims_prod_circuit.extend(row_eval_read);
1325        claims_prod_circuit.extend(row_eval_write);
1326        claims_prod_circuit.extend(col_eval_read);
1327        claims_prod_circuit.extend(col_eval_write);
1328
1329        let (claims_ops, claims_dotp, rand_ops) = self.proof_ops.verify(
1330            &claims_prod_circuit,
1331            &claims_dotp_circuit,
1332            num_ops,
1333            transcript,
1334        );
1335        // verify the correctness of claim_row_eval_init and claim_row_eval_audit
1336        let (claims_mem, _claims_mem_dotp, rand_mem) = self.proof_mem.verify(
1337            &[
1338                *row_eval_init,
1339                *row_eval_audit,
1340                *col_eval_init,
1341                *col_eval_audit,
1342            ],
1343            &Vec::new(),
1344            num_cells,
1345            transcript,
1346        );
1347        timer.stop();
1348
1349        Ok((claims_mem, rand_mem, claims_ops, claims_dotp, rand_ops))
1350    }
1351}
1352
1353#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
1354struct PolyEvalNetworkProof {
1355    proof_prod_layer: ProductLayerProof,
1356    proof_hash_layer: HashLayerProof,
1357}
1358
1359impl PolyEvalNetworkProof {
1360    fn protocol_name() -> &'static [u8] {
1361        b"Sparse polynomial evaluation proof"
1362    }
1363
1364    pub fn prove(
1365        network: &mut PolyEvalNetwork,
1366        dense: &MultiSparseMatPolynomialAsDense,
1367        derefs: &Derefs,
1368        evals: &[Scalar],
1369        gens: &SparseMatPolyCommitmentGens,
1370        transcript: &mut PoseidonTranscript,
1371        random_tape: &mut RandomTape,
1372    ) -> Self {
1373        // transcript.append_protocol_name(PolyEvalNetworkProof::protocol_name());
1374
1375        let (proof_prod_layer, rand_mem, rand_ops) = ProductLayerProof::prove(
1376            &mut network.row_layers.prod_layer,
1377            &mut network.col_layers.prod_layer,
1378            dense,
1379            derefs,
1380            evals,
1381            transcript,
1382        );
1383
1384        // proof of hash layer for row and col
1385        let proof_hash_layer = HashLayerProof::prove(
1386            (&rand_mem, &rand_ops),
1387            dense,
1388            derefs,
1389            gens,
1390            transcript,
1391            random_tape,
1392        );
1393
1394        PolyEvalNetworkProof {
1395            proof_prod_layer,
1396            proof_hash_layer,
1397        }
1398    }
1399
1400    pub fn verify(
1401        &self,
1402        comm: &SparseMatPolyCommitment,
1403        comm_derefs: &DerefsCommitment,
1404        evals: &[Scalar],
1405        gens: &SparseMatPolyCommitmentGens,
1406        rx: &[Scalar],
1407        ry: &[Scalar],
1408        r_mem_check: &(Scalar, Scalar),
1409        nz: usize,
1410        transcript: &mut PoseidonTranscript,
1411    ) -> Result<(), ProofVerifyError> {
1412        let timer = Timer::new("verify_polyeval_proof");
1413        // transcript.append_protocol_name(PolyEvalNetworkProof::protocol_name());
1414
1415        let num_instances = evals.len();
1416        let (r_hash, r_multiset_check) = r_mem_check;
1417
1418        let num_ops = nz.next_power_of_two();
1419        let num_cells = rx.len().pow2();
1420        assert_eq!(rx.len(), ry.len());
1421
1422        let (claims_mem, rand_mem, mut claims_ops, claims_dotp, rand_ops) =
1423            self.proof_prod_layer
1424                .verify(num_ops, num_cells, evals, transcript)?;
1425        assert_eq!(claims_mem.len(), 4);
1426        assert_eq!(claims_ops.len(), 4 * num_instances);
1427        assert_eq!(claims_dotp.len(), 3 * num_instances);
1428
1429        let (claims_ops_row, claims_ops_col) = claims_ops.split_at_mut(2 * num_instances);
1430        let (claims_ops_row_read, claims_ops_row_write) =
1431            claims_ops_row.split_at_mut(num_instances);
1432        let (claims_ops_col_read, claims_ops_col_write) =
1433            claims_ops_col.split_at_mut(num_instances);
1434
1435        // verify the proof of hash layer
1436        self.proof_hash_layer.verify(
1437            (&rand_mem, &rand_ops),
1438            &(
1439                claims_mem[0],
1440                claims_ops_row_read.to_vec(),
1441                claims_ops_row_write.to_vec(),
1442                claims_mem[1],
1443            ),
1444            &(
1445                claims_mem[2],
1446                claims_ops_col_read.to_vec(),
1447                claims_ops_col_write.to_vec(),
1448                claims_mem[3],
1449            ),
1450            &claims_dotp,
1451            comm,
1452            gens,
1453            comm_derefs,
1454            rx,
1455            ry,
1456            r_hash,
1457            r_multiset_check,
1458            transcript,
1459        )?;
1460        timer.stop();
1461
1462        Ok(())
1463    }
1464}
1465
1466#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
1467pub struct SparseMatPolyEvalProof {
1468    comm_derefs: DerefsCommitment,
1469    poly_eval_network_proof: PolyEvalNetworkProof,
1470}
1471
1472impl SparseMatPolyEvalProof {
1473    fn protocol_name() -> &'static [u8] {
1474        b"Sparse polynomial evaluation proof"
1475    }
1476
1477    fn equalize(rx: &[Scalar], ry: &[Scalar]) -> (Vec<Scalar>, Vec<Scalar>) {
1478        match rx.len().cmp(&ry.len()) {
1479            Ordering::Less => {
1480                let diff = ry.len() - rx.len();
1481                let mut rx_ext = vec![Scalar::zero(); diff];
1482                rx_ext.extend(rx);
1483                (rx_ext, ry.to_vec())
1484            }
1485            Ordering::Greater => {
1486                let diff = rx.len() - ry.len();
1487                let mut ry_ext = vec![Scalar::zero(); diff];
1488                ry_ext.extend(ry);
1489                (rx.to_vec(), ry_ext)
1490            }
1491            Ordering::Equal => (rx.to_vec(), ry.to_vec()),
1492        }
1493    }
1494
1495    pub fn prove(
1496        dense: &MultiSparseMatPolynomialAsDense,
1497        rx: &[Scalar], // point at which the polynomial is evaluated
1498        ry: &[Scalar],
1499        evals: &[Scalar], // a vector evaluation of \widetilde{M}(r = (rx,ry)) for each M
1500        gens: &SparseMatPolyCommitmentGens,
1501        transcript: &mut PoseidonTranscript,
1502        random_tape: &mut RandomTape,
1503    ) -> SparseMatPolyEvalProof {
1504        // transcript.append_protocol_name(SparseMatPolyEvalProof::protocol_name());
1505
1506        // ensure there is one eval for each polynomial in dense
1507        assert_eq!(evals.len(), dense.batch_size);
1508
1509        let (mem_rx, mem_ry) = {
1510            // equalize the lengths of rx and ry
1511            let (rx_ext, ry_ext) = SparseMatPolyEvalProof::equalize(rx, ry);
1512            let poly_rx = EqPolynomial::new(rx_ext).evals();
1513            let poly_ry = EqPolynomial::new(ry_ext).evals();
1514            (poly_rx, poly_ry)
1515        };
1516
1517        let derefs = dense.deref(&mem_rx, &mem_ry);
1518
1519        // commit to non-deterministic choices of the prover
1520        let timer_commit = Timer::new("commit_nondet_witness");
1521        let comm_derefs = {
1522            let comm = derefs.commit(&gens.gens_derefs);
1523            comm.append_to_poseidon(transcript);
1524            comm
1525        };
1526        timer_commit.stop();
1527
1528        let poly_eval_network_proof = {
1529            // produce a random element from the transcript for hash function
1530            let r_mem_check = transcript.challenge_vector(2);
1531
1532            // build a network to evaluate the sparse polynomial
1533            let timer_build_network = Timer::new("build_layered_network");
1534            let mut net = PolyEvalNetwork::new(
1535                dense,
1536                &derefs,
1537                &mem_rx,
1538                &mem_ry,
1539                &(r_mem_check[0], r_mem_check[1]),
1540            );
1541            timer_build_network.stop();
1542
1543            let timer_eval_network = Timer::new("evalproof_layered_network");
1544            let poly_eval_network_proof = PolyEvalNetworkProof::prove(
1545                &mut net,
1546                dense,
1547                &derefs,
1548                evals,
1549                gens,
1550                transcript,
1551                random_tape,
1552            );
1553            timer_eval_network.stop();
1554
1555            poly_eval_network_proof
1556        };
1557
1558        SparseMatPolyEvalProof {
1559            comm_derefs,
1560            poly_eval_network_proof,
1561        }
1562    }
1563
1564    pub fn verify(
1565        &self,
1566        comm: &SparseMatPolyCommitment,
1567        rx: &[Scalar], // point at which the polynomial is evaluated
1568        ry: &[Scalar],
1569        evals: &[Scalar], // evaluation of \widetilde{M}(r = (rx,ry))
1570        gens: &SparseMatPolyCommitmentGens,
1571        transcript: &mut PoseidonTranscript,
1572    ) -> Result<(), ProofVerifyError> {
1573        // transcript.append_protocol_name(SparseMatPolyEvalProof::protocol_name());
1574
1575        // equalize the lengths of rx and ry
1576        let (rx_ext, ry_ext) = SparseMatPolyEvalProof::equalize(rx, ry);
1577
1578        let (nz, num_mem_cells) = (comm.num_ops, comm.num_mem_cells);
1579        assert_eq!(rx_ext.len().pow2(), num_mem_cells);
1580
1581        // add claims to transcript and obtain challenges for randomized mem-check circuit
1582        self.comm_derefs.append_to_poseidon(transcript);
1583
1584        // produce a random element from the transcript for hash function
1585        let r_mem_check = transcript.challenge_vector(2);
1586
1587        self.poly_eval_network_proof.verify(
1588            comm,
1589            &self.comm_derefs,
1590            evals,
1591            gens,
1592            &rx_ext,
1593            &ry_ext,
1594            &(r_mem_check[0], r_mem_check[1]),
1595            nz,
1596            transcript,
1597        )
1598    }
1599}
1600
1601#[derive(Clone)]
1602pub struct SparsePolyEntry {
1603    pub idx: usize,
1604    pub val: Scalar,
1605}
1606
1607impl SparsePolyEntry {
1608    pub fn new(idx: usize, val: Scalar) -> Self {
1609        SparsePolyEntry { idx, val }
1610    }
1611}
1612#[derive(Clone)]
1613pub struct SparsePolynomial {
1614    pub num_vars: usize,
1615    pub Z: Vec<SparsePolyEntry>,
1616}
1617
1618impl SparsePolynomial {
1619    pub fn new(num_vars: usize, Z: Vec<SparsePolyEntry>) -> Self {
1620        SparsePolynomial { num_vars, Z }
1621    }
1622
1623    // TF IS THIS??
1624
1625    fn compute_chi(a: &[bool], r: &[Scalar]) -> Scalar {
1626        assert_eq!(a.len(), r.len());
1627        let mut chi_i = Scalar::one();
1628        for j in 0..r.len() {
1629            if a[j] {
1630                chi_i *= r[j];
1631            } else {
1632                chi_i *= Scalar::one() - r[j];
1633            }
1634        }
1635        chi_i
1636    }
1637
1638    // Takes O(n log n). TODO: do this in O(n) where n is the number of entries in Z
1639    pub fn evaluate(&self, r: &[Scalar]) -> Scalar {
1640        assert_eq!(self.num_vars, r.len());
1641
1642        (0..self.Z.len())
1643            .map(|i| {
1644                let bits = self.Z[i].idx.get_bits(r.len());
1645                println!("{:?}", bits);
1646                SparsePolynomial::compute_chi(&bits, r) * self.Z[i].val
1647            })
1648            .sum()
1649    }
1650}
1651
1652#[cfg(test)]
1653mod tests {
1654    use crate::parameters::poseidon_params;
1655
1656    use super::*;
1657    use ark_std::UniformRand;
1658    use rand::RngCore;
1659
1660    #[test]
1661    fn check_sparse_polyeval_proof() {
1662        let mut rng = ark_std::rand::thread_rng();
1663
1664        let num_nz_entries: usize = 256;
1665        let num_rows: usize = 256;
1666        let num_cols: usize = 256;
1667        let num_vars_x: usize = num_rows.log_2();
1668        let num_vars_y: usize = num_cols.log_2();
1669
1670        let mut M: Vec<SparseMatEntry> = Vec::new();
1671
1672        for _i in 0..num_nz_entries {
1673            M.push(SparseMatEntry::new(
1674                (rng.next_u64() % (num_rows as u64)) as usize,
1675                (rng.next_u64() % (num_cols as u64)) as usize,
1676                Scalar::rand(&mut rng),
1677            ));
1678        }
1679
1680        let poly_M = SparseMatPolynomial::new(num_vars_x, num_vars_y, M);
1681        let gens = SparseMatPolyCommitmentGens::new(
1682            b"gens_sparse_poly",
1683            num_vars_x,
1684            num_vars_y,
1685            num_nz_entries,
1686            3,
1687        );
1688
1689        // commitment
1690        let (poly_comm, dense) =
1691            SparseMatPolynomial::multi_commit(&[&poly_M, &poly_M, &poly_M], &gens);
1692
1693        // evaluation
1694        let rx: Vec<Scalar> = (0..num_vars_x)
1695            .map(|_i| Scalar::rand(&mut rng))
1696            .collect::<Vec<Scalar>>();
1697        let ry: Vec<Scalar> = (0..num_vars_y)
1698            .map(|_i| Scalar::rand(&mut rng))
1699            .collect::<Vec<Scalar>>();
1700        let eval = SparseMatPolynomial::multi_evaluate(&[&poly_M], &rx, &ry);
1701        let evals = vec![eval[0], eval[0], eval[0]];
1702
1703        let params = poseidon_params();
1704        let mut random_tape = RandomTape::new(b"proof");
1705        let mut prover_transcript = PoseidonTranscript::new(&params);
1706        let proof = SparseMatPolyEvalProof::prove(
1707            &dense,
1708            &rx,
1709            &ry,
1710            &evals,
1711            &gens,
1712            &mut prover_transcript,
1713            &mut random_tape,
1714        );
1715
1716        let mut verifier_transcript = PoseidonTranscript::new(&params);
1717        assert!(proof
1718            .verify(
1719                &poly_comm,
1720                &rx,
1721                &ry,
1722                &evals,
1723                &gens,
1724                &mut verifier_transcript,
1725            )
1726            .is_ok());
1727    }
1728}