Skip to content

Commit

Permalink
Add Ligero univariate and multilinear PCS (#132)
Browse files Browse the repository at this point in the history
* added hyrax PCS

* Add univariate and multilinear Ligero PCS

Co-authored-by: Hossein Moghaddas <[email protected]>
Co-authored-by: Antonio Mejías Gil <[email protected]>

* adapt the scheme to arkworks-rs/algebra#691

* move tests shared across univariate and ML ligero to utils

* remove unused no-std import

* adapt the scheme to arkworks-rs/algebra#691

* remove unused code in hyrax

* Improve the choice of dimensions for polynomial matrix

* Update comments

* parallelised row encoding and col-to-leaf hashing; significant performance gains

* expanded on Future Optimisations section

* fixed GH action failures: formatted and added feature flag

* remove Prepared data types from `PolynomialCommitment` trait

* Remove Prepared data types from `PolynomialCommitment` trait impl

* added necessary dependencies overwritten by previous merge commit

* fixed hashbrown version

* Add back the cfg dependency for no-std build

* fixed hashbrown version

* pulled

* created separate benchmark files

* fixed duplicate dependency to match other branches

* patched bn254 dep

* restructured benchmark macros to accept ML schemes; benches working

* moved hashing structures to bench-templates crate, started ligero bench coding

* completed ligero benchmarks

* added ligero benchmark file

* Hyrax fix bench (#42)

* fix bench call

* set num vars from 12-20

* Ligero fix benches (#40)

* fix bench call

* set num vars from 12-20

* Hyrax parallel `commit` (#39)

* Enable parallel commitment in hyrax

amend

* make `rand` optional

* remove dead code

* Make Hyrax hiding again (#43)

* removed evaluation randomness from proof and ignored claimed value in check to make scheme hiding

* fmt

* removed unnecessary usage of argument  in check, added _

* Fix tests: sponge config for univariate ligero

* Delete `IOPTranscript`, update with master (#50) (aka Hyrax++)

* Add the trait bounds

* Add `CommitmentState`

* Update benches for the new type

* Fix the name of local variable

* Merge `PCCommitmentState` with `PCRandomness`

* Update `README.md`

* Fix a bug

* Change `Randomness` to `CommitmentState`

* Maybe `empty` not return `Self`

* Make `empty` return `Self`

* Rename `rand` to `state`

* Partially integrate the new design into Hyrax

* Update Hyrax with the shared state

* Rename nonnative to emulated, as in `r1cs-std` (#137)

* Rename nonnative to emulated, as in `r1cs-std`

* Run `fmt`

* Temporarily change `Cargo.toml`

* Revert `Cargo.toml`

* Refactor `FoldedPolynomialStream` partially

* Substitute `ChallengeGenerator` by the generic sponge (#139)

* Rename nonnative to emulated, as in `r1cs-std`

* Run `fmt`

* Temporarily change `Cargo.toml`

* Substitute `ChallengeGenerator` with the generic sponge

* Run `fmt`

* Remove the extra file

* Update modules

* Delete the unnecessary loop

* Revert `Cargo.toml`

* Refactor `FoldedPolynomialStream` partially

* Update README

* Make the diff more readable

* Bring the whitespace back

* Make diff more readable, 2

* Fix according to breaking changes in `ark-ec` (#141)

* Fix for KZG10

* Fix the breaking changes in `ark-ec`

* Remove the extra loop

* Fix the loop range

* re-use the preprocessing table

* also re-use the preprocessing table for multilinear_pc

---------

Co-authored-by: mmagician <[email protected]>

* Auxiliary opening data (#134)

* Add the trait bounds

* Add `CommitmentState`

* Update benches for the new type

* Fix the name of local variable

* Merge `PCCommitmentState` with `PCRandomness`

* Update `README.md`

* Fix a bug

* Put `Randomness` in `CommitmentState`

* Add a comment

* Remove the extra loop

* Update the comment for `CommitmentState`

Co-authored-by: Marcin <[email protected]>

* cargo fmt

---------

Co-authored-by: Marcin <[email protected]>

* `batch_mul_with_preprocessing` no longer takes `self` as argument (#142)

* batch_mul_with_preprocessing no longer takes `self` as argument

* Apply suggestions from code review

Co-authored-by: Pratyush Mishra <[email protected]>

* fix variable name

---------

Co-authored-by: Pratyush Mishra <[email protected]>

* Remove ChallengeGenerator for Ligero (#56)

* Squash and merge `delete-chalgen` onto here

* Fix for `ChallengeGenerator`

* Delete `IOPTranscript` for Hyrax (#55)

* Use the sponge generic and rearrange `use`s

* Use sponge instead of `IOPTransript`

* Fix benches

* Remove the extra loop

---------

Co-authored-by: mmagician <[email protected]>
Co-authored-by: Pratyush Mishra <[email protected]>

* Delete `IOPTranscript`, update with master (#51) (aka Ligero++)

* Add the trait bounds

* Add `CommitmentState`

* Update benches for the new type

* Fix the name of local variable

* Merge `PCCommitmentState` with `PCRandomness`

* Update `README.md`

* Fix a bug

* Simplify `hash_column`

* Delete comments

* Add `CommitmentState`

* Make `fmt` happy

* Refactor, remove `hash_columns`

* Rename all params

* Maybe `empty` not return `Self`

* Make `empty` return `Self`

* Rename `rand` to `state`

* Add type `Randomness`

* Ligero+++ (#46)

* conversion to `into_iter` is a no-op

* remove explicit casts to vecs

* rename to use singular of `labeled_commitment`

* simplify the iterators even further by zipping two iters

* Apply suggestions from code review

* Fix tests: sponge config for univariate ligero

* Rename nonnative to emulated, as in `r1cs-std` (#137)

* Rename nonnative to emulated, as in `r1cs-std`

* Run `fmt`

* Temporarily change `Cargo.toml`

* Revert `Cargo.toml`

* Refactor `FoldedPolynomialStream` partially

* Substitute `ChallengeGenerator` by the generic sponge (#139)

* Rename nonnative to emulated, as in `r1cs-std`

* Run `fmt`

* Temporarily change `Cargo.toml`

* Substitute `ChallengeGenerator` with the generic sponge

* Run `fmt`

* Remove the extra file

* Update modules

* Delete the unnecessary loop

* Revert `Cargo.toml`

* Refactor `FoldedPolynomialStream` partially

* Update README

* Make the diff more readable

* Bring the whitespace back

* Make diff more readable, 2

* Fix according to breaking changes in `ark-ec` (#141)

* Fix for KZG10

* Fix the breaking changes in `ark-ec`

* Remove the extra loop

* Fix the loop range

* re-use the preprocessing table

* also re-use the preprocessing table for multilinear_pc

---------

Co-authored-by: mmagician <[email protected]>

* Auxiliary opening data (#134)

* Add the trait bounds

* Add `CommitmentState`

* Update benches for the new type

* Fix the name of local variable

* Merge `PCCommitmentState` with `PCRandomness`

* Update `README.md`

* Fix a bug

* Put `Randomness` in `CommitmentState`

* Add a comment

* Remove the extra loop

* Update the comment for `CommitmentState`

Co-authored-by: Marcin <[email protected]>

* cargo fmt

---------

Co-authored-by: Marcin <[email protected]>

* `batch_mul_with_preprocessing` no longer takes `self` as argument (#142)

* batch_mul_with_preprocessing no longer takes `self` as argument

* Apply suggestions from code review

Co-authored-by: Pratyush Mishra <[email protected]>

* fix variable name

---------

Co-authored-by: Pratyush Mishra <[email protected]>

* Remove `ChallengeGenerator` and `IOPTranscript` for Ligero (#57)

* Squash and merge `delete-chalgen` onto here

* Fix Ligero for `ChallengeGenerator` and `AsRef` for Merkle tree

* Fix tests: sponge config for univariate ligero

* Delete `IOPTranscript` for Ligero (#54)

* Replace the `IOPTranscript` with `CryptographicSponge`

* Delete extra comments

* Run fmt

* Fix tests: sponge config for univariate ligero

* Delete TODOs and do not absorb what you just squeezed

* Fix unused import

* Revert "Fix unused import"

This reverts commit e85af90.

* Try to fix

* Remove the extra loop

---------

Co-authored-by: mmagician <[email protected]>
Co-authored-by: Pratyush Mishra <[email protected]>

* Add a few comments and update `Cargo.toml`

* Remove extra `cfg_iter!`

Co-authored-by: Pratyush Mishra <[email protected]>

* Change `pedersen_commit` and add `cfg_into_iter!`

* Hash and absorb

* added Sync trait bound

Co-authored-by: Cesar Descalzo <[email protected]>

* removed TODO

* Fixed error whereby boolean value returned by path.verify was neglected

Co-authored-by: Cesar Descalzo <[email protected]>

Co-authored-by: mmagician <[email protected]>

* removed unnecessary qualification which linter didn't like

* changed potential panic to returning Err, stopping early

Co-authored-by: Cesar Descalzo <[email protected]>

* removed unnecessary function defined inside check()

Co-authored-by: Cesar Descalzo <[email protected]>

* various minor fixes

* Add `ark-std` to patch

* Reorder Hyrax checks

Co-authored-by: Antonio Mejías Gil <[email protected]>

* Add `ark-std` to patch

* Downgrade `hashbrown`

* Fix breaking change from algebra/poly (#72)

* Reorder deps

* Add dummy doc for nightly

* Fix `hashbrown` + Replace Blake2 by Blake3

* Revert to Blake2

* Fix merging issues

* Test if CI is happy

* Revert and cleanup

* Delete dummy doc

* Bring back `num_traits`

* Add `/` to Cargo.toml

---------

Co-authored-by: Antonio Mejías Gil <[email protected]>
Co-authored-by: Hossein Moghaddas <[email protected]>
Co-authored-by: Pratyush Mishra <[email protected]>
Co-authored-by: Cesar Descalzo <[email protected]>
Co-authored-by: Cesar199999 <[email protected]>
  • Loading branch information
6 people authored Oct 25, 2024
1 parent 77de8eb commit 78aa1d7
Show file tree
Hide file tree
Showing 15 changed files with 2,063 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ark-ec = { git = "https://github.com/arkworks-rs/algebra/" }
ark-serialize = { git = "https://github.com/arkworks-rs/algebra/" }
ark-poly = { git = "https://github.com/arkworks-rs/algebra/" }

ark-crypto-primitives = { git = "https://github.com/arkworks-rs/crypto-primitives" }
ark-crypto-primitives = { git = "https://github.com/arkworks-rs/crypto-primitives/" }
ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std/" }

ark-bls12-377 = { git = "https://github.com/arkworks-rs/algebra/" }
Expand Down
72 changes: 66 additions & 6 deletions bench-templates/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
use ark_crypto_primitives::sponge::{
poseidon::{PoseidonConfig, PoseidonSponge},
CryptographicSponge,
use ark_crypto_primitives::{
crh::{sha256::digest::Digest, CRHScheme},
sponge::{
poseidon::{PoseidonConfig, PoseidonSponge},
CryptographicSponge,
},
};
use ark_ff::PrimeField;
use ark_poly::Polynomial;
use ark_serialize::{CanonicalSerialize, Compress};
use ark_std::{test_rng, UniformRand};
use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha20Rng,
};

use core::time::Duration;
use std::time::Instant;
use std::{borrow::Borrow, marker::PhantomData, time::Instant};

use ark_poly_commit::{LabeledPolynomial, PolynomialCommitment};
use ark_poly_commit::{to_bytes, LabeledPolynomial, PolynomialCommitment};

pub use criterion::*;
pub use paste::paste;
Expand Down Expand Up @@ -276,3 +282,57 @@ macro_rules! bench {
}
};
}

/**** Auxiliary methods for linear-code-based PCSs ****/

/// Needed for benches and tests.
pub struct LeafIdentityHasher;

impl CRHScheme for LeafIdentityHasher {
type Input = Vec<u8>;
type Output = Vec<u8>;
type Parameters = ();

fn setup<R: RngCore>(_: &mut R) -> Result<Self::Parameters, ark_crypto_primitives::Error> {
Ok(())
}

fn evaluate<T: Borrow<Self::Input>>(
_: &Self::Parameters,
input: T,
) -> Result<Self::Output, ark_crypto_primitives::Error> {
Ok(input.borrow().to_vec().into())
}
}

/// Needed for benches and tests.
pub struct FieldToBytesColHasher<F, D>
where
F: PrimeField + CanonicalSerialize,
D: Digest,
{
_phantom: PhantomData<(F, D)>,
}

impl<F, D> CRHScheme for FieldToBytesColHasher<F, D>
where
F: PrimeField + CanonicalSerialize,
D: Digest,
{
type Input = Vec<F>;
type Output = Vec<u8>;
type Parameters = ();

fn setup<R: RngCore>(_rng: &mut R) -> Result<Self::Parameters, ark_crypto_primitives::Error> {
Ok(())
}

fn evaluate<T: Borrow<Self::Input>>(
_parameters: &Self::Parameters,
input: T,
) -> Result<Self::Output, ark_crypto_primitives::Error> {
let mut dig = D::new();
dig.update(to_bytes!(input.borrow()).unwrap());
Ok(dig.finalize().to_vec())
}
}
11 changes: 10 additions & 1 deletion poly-commit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,19 @@ ark-r1cs-std = { version = "^0.4.0", default-features = false, optional = true }
hashbrown = { version = "0.15", default-features = false, features = ["inline-more", "allocator-api2"], optional = true }
rand = { version = "0.8.0", optional = true }
rayon = { version = "1", optional = true }
merlin = { version = "3.0.0", default-features = false }

[[bench]]
name = "ipa_times"
path = "benches/ipa_times.rs"
harness = false

[[bench]]
name = "ligero_ml_times"
path = "benches/ligero_ml_times.rs"
harness = false


[[bench]]
name = "hyrax_times"
path = "benches/hyrax_times.rs"
Expand All @@ -53,10 +60,12 @@ ark-ed-on-bls12-381 = { version = "^0.4.0", default-features = false }
ark-bls12-381 = { version = "^0.4.0", default-features = false, features = [ "curve" ] }
ark-bls12-377 = { version = "^0.4.0", default-features = false, features = [ "curve" ] }
ark-bn254 = { version = "^0.4.0", default-features = false, features = [ "curve" ] }

rand_chacha = { version = "0.3.0", default-features = false }
ark-pcs-bench-templates = { path = "../bench-templates" }

[target.'cfg(target_arch = "aarch64")'.dependencies]
num-traits = { version = "0.2", default-features = false, features = ["libm"] }

[features]
default = [ "std", "parallel" ]
std = [ "ark-ff/std", "ark-ec/std", "ark-poly/std", "ark-std/std", "ark-relations/std", "ark-serialize/std", "ark-crypto-primitives/std"]
Expand Down
55 changes: 55 additions & 0 deletions poly-commit/benches/ligero_ml_times.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use ark_crypto_primitives::{
crh::{sha256::Sha256, CRHScheme, TwoToOneCRHScheme},
merkle_tree::{ByteDigestConverter, Config},
};
use ark_pcs_bench_templates::*;
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};

use ark_bn254::Fr;
use ark_ff::PrimeField;

use ark_poly_commit::linear_codes::{LinearCodePCS, MultilinearLigero};
use blake2::Blake2s256;
use rand_chacha::ChaCha20Rng;

// Ligero PCS over BN254
struct MerkleTreeParams;
type LeafH = LeafIdentityHasher;
type CompressH = Sha256;
impl Config for MerkleTreeParams {
type Leaf = Vec<u8>;

type LeafDigest = <LeafH as CRHScheme>::Output;
type LeafInnerDigestConverter = ByteDigestConverter<Self::LeafDigest>;
type InnerDigest = <CompressH as TwoToOneCRHScheme>::Output;

type LeafHash = LeafH;
type TwoToOneHash = CompressH;
}

pub type MLE<F> = DenseMultilinearExtension<F>;
type MTConfig = MerkleTreeParams;
type ColHasher<F> = FieldToBytesColHasher<F, Blake2s256>;
type Ligero<F> = LinearCodePCS<
MultilinearLigero<F, MTConfig, MLE<F>, ColHasher<F>>,
F,
MLE<F>,
MTConfig,
ColHasher<F>,
>;

fn rand_poly_ligero_ml<F: PrimeField>(
num_vars: usize,
rng: &mut ChaCha20Rng,
) -> DenseMultilinearExtension<F> {
DenseMultilinearExtension::rand(num_vars, rng)
}

fn rand_point_ligero_ml<F: PrimeField>(num_vars: usize, rng: &mut ChaCha20Rng) -> Vec<F> {
(0..num_vars).map(|_| F::rand(rng)).collect()
}

const MIN_NUM_VARS: usize = 12;
const MAX_NUM_VARS: usize = 22;

bench!(Ligero<Fr>, rand_poly_ligero_ml, rand_point_ligero_ml);
15 changes: 5 additions & 10 deletions poly-commit/src/ipa_pc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
BTreeMap, BTreeSet, BatchLCProof, DenseUVPolynomial, Error, Evaluations, LabeledCommitment,
LabeledPolynomial, LinearCombination, PCCommitmentState, PCCommitterKey, PCUniversalParams,
PolynomialCommitment, QuerySet, CHALLENGE_SIZE,
utils::inner_product, BTreeMap, BTreeSet, BatchLCProof, DenseUVPolynomial, Error, Evaluations,
LabeledCommitment, LabeledPolynomial, LinearCombination, PCCommitmentState, PCCommitterKey,
PCUniversalParams, PolynomialCommitment, QuerySet, CHALLENGE_SIZE,
};
use ark_crypto_primitives::sponge::CryptographicSponge;
use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM};
Expand Down Expand Up @@ -86,11 +86,6 @@ where
challenge.unwrap()
}

#[inline]
fn inner_product(l: &[G::ScalarField], r: &[G::ScalarField]) -> G::ScalarField {
ark_std::cfg_iter!(l).zip(r).map(|(li, ri)| *li * ri).sum()
}

/// The succinct portion of `PC::check`. This algorithm runs in time
/// O(log d), where d is the degree of the committed polynomials.
fn succinct_check<'a>(
Expand Down Expand Up @@ -674,10 +669,10 @@ where
let (key_proj_l, _) = key_proj.split_at_mut(n / 2);

let l = Self::cm_commit(key_l, coeffs_r, None, None)
+ &h_prime.mul(Self::inner_product(coeffs_r, z_l));
+ &h_prime.mul(inner_product(coeffs_r, z_l));

let r = Self::cm_commit(key_r, coeffs_l, None, None)
+ &h_prime.mul(Self::inner_product(coeffs_l, z_r));
+ &h_prime.mul(inner_product(coeffs_l, z_r));

let lr = G::Group::normalize_batch(&[l, r]);
l_vec.push(lr[0]);
Expand Down
5 changes: 5 additions & 0 deletions poly-commit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ pub use marlin::marlin_pst13_pc;
/// [bdfg]: https://eprint.iacr.org/2020/081.pdf
pub mod streaming_kzg;

/// Scheme based on the Ligero construction in [[Ligero]][ligero].
///
/// [ligero]: https://eprint.iacr.org/2022/1608
pub mod linear_codes;

/// A polynomial commitment scheme based on the hardness of the
/// discrete logarithm problem in prime-order groups. This is a
/// Fiat-Shamired version of the PCS described in the Hyrax paper
Expand Down
124 changes: 124 additions & 0 deletions poly-commit/src/linear_codes/data_structures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use crate::{utils::Matrix, PCCommitment, PCCommitmentState};
use ark_crypto_primitives::{
crh::CRHScheme,
merkle_tree::{Config, LeafParam, Path, TwoToOneParam},
};
use ark_ff::PrimeField;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
#[cfg(not(feature = "std"))]
use ark_std::vec::Vec;
use ark_std::{marker::PhantomData, rand::RngCore};

#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
/// The public parameters for Ligero PCS.
pub struct LigeroPCParams<F: PrimeField, C: Config, H: CRHScheme> {
pub(crate) _field: PhantomData<F>,
/// The security parameter
pub(crate) sec_param: usize,
/// The inverse of the code rate.
pub(crate) rho_inv: usize,
/// This is a flag which determines if the random linear combination is done.
pub(crate) check_well_formedness: bool,
/// Parameters for hash function of Merkle tree leaves
#[derivative(Debug = "ignore")]
pub(crate) leaf_hash_param: LeafParam<C>,
/// Parameters for hash function of Merke tree combining two nodes into one
#[derivative(Debug = "ignore")]
pub(crate) two_to_one_hash_param: TwoToOneParam<C>,
// Parameters for obtaining leaf digest from leaf value.
#[derivative(Debug = "ignore")]
pub(crate) col_hash_params: H::Parameters,
}

#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))]
pub(crate) struct Metadata {
pub(crate) n_rows: usize,
pub(crate) n_cols: usize,
pub(crate) n_ext_cols: usize,
}

/// The commitment to a polynomial is a root of the merkle tree,
/// where each node is a hash of the column of the encoded coefficient matrix U.
#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))]
pub struct LinCodePCCommitment<C: Config> {
// number of rows resp. columns of the square matrix containing the coefficients of the polynomial
pub(crate) metadata: Metadata,
pub(crate) root: C::InnerDigest,
}

impl<C: Config> PCCommitment for LinCodePCCommitment<C> {
fn empty() -> Self {
LinCodePCCommitment::default()
}

fn has_degree_bound(&self) -> bool {
false
}
}

#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))]
pub struct LinCodePCCommitmentState<F, H>
where
F: PrimeField,
H: CRHScheme,
{
pub(crate) mat: Matrix<F>,
pub(crate) ext_mat: Matrix<F>,
pub(crate) leaves: Vec<H::Output>,
}

impl<F, H> PCCommitmentState for LinCodePCCommitmentState<F, H>
where
F: PrimeField,
H: CRHScheme,
{
type Randomness = ();
fn empty() -> Self {
unimplemented!()
}

fn rand<R: RngCore>(
_num_queries: usize,
_has_degree_bound: bool,
_num_vars: Option<usize>,
_rng: &mut R,
) -> Self::Randomness {
unimplemented!()
}
}

/// Proof of an individual linear code well-formedness check or opening
#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))]
pub(crate) struct LinCodePCProofSingle<F, C>
where
F: PrimeField,
C: Config,
{
/// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf
pub(crate) paths: Vec<Path<C>>,

/// v, s.t. E(v) = w
pub(crate) v: Vec<F>,

pub(crate) columns: Vec<Vec<F>>,
}

/// The Proof type for linear code PCS, which amounts to an array of individual proofs
#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))]
pub struct LinCodePCProof<F, C>
where
F: PrimeField,
C: Config,
{
pub(crate) opening: LinCodePCProofSingle<F, C>,
pub(crate) well_formedness: Option<Vec<F>>,
}

// Multiple poly at one point
pub(crate) type LPCPArray<F, C> = Vec<LinCodePCProof<F, C>>;
Loading

0 comments on commit 78aa1d7

Please sign in to comment.