diff --git a/w3f-plonk-common/Cargo.toml b/w3f-plonk-common/Cargo.toml index 116b450..70d1638 100644 --- a/w3f-plonk-common/Cargo.toml +++ b/w3f-plonk-common/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "w3f-plonk-common" -version = "0.0.1" +version = "0.0.2" edition = "2021" authors = ["Sergey Vasilyev "] license = "MIT/Apache-2.0" description = "Infrastructure for creating plonk-like proofs" keywords = ["cryptography", "plonk"] +repository = "https://github.com/w3f/ring-proof" [dependencies] ark-std.workspace = true @@ -44,3 +45,4 @@ parallel = [ ] print-trace = ["ark-std/print-trace"] asm = ["w3f-pcs/asm"] +test-vectors = [] diff --git a/w3f-plonk-common/src/domain.rs b/w3f-plonk-common/src/domain.rs index f373b41..a096cd9 100644 --- a/w3f-plonk-common/src/domain.rs +++ b/w3f-plonk-common/src/domain.rs @@ -109,7 +109,7 @@ impl Domain { pub(crate) fn column(&self, mut evals: Vec, hidden: bool) -> FieldColumn { let len = evals.len(); assert!(len <= self.capacity); - if self.hiding && hidden { + if self.hiding && hidden && !cfg!(feature = "test-vectors") { evals.resize(self.capacity, F::zero()); evals.resize_with(self.domains.x1.size(), || { F::rand(&mut getrandom_or_panic::getrandom_or_panic()) diff --git a/w3f-ring-proof/Cargo.toml b/w3f-ring-proof/Cargo.toml index c7e1c1f..cc1cd8b 100644 --- a/w3f-ring-proof/Cargo.toml +++ b/w3f-ring-proof/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "w3f-ring-proof" -version = "0.0.1" +version = "0.0.2" edition = "2021" authors = ["Sergey Vasilyev "] license = "MIT/Apache-2.0" description = "zk-proof of knowledge of the blinding factor for a Pedersen commitment" keywords = ["cryptography", "ring-vrf"] +repository = "https://github.com/w3f/ring-proof" [dependencies] ark-std.workspace = true @@ -16,7 +17,6 @@ ark-serialize.workspace = true w3f-pcs.workspace = true rayon = { workspace = true, optional = true } w3f-plonk-common = { path="../w3f-plonk-common", default-features = false } -blake2 = { version = "0.10", default-features = false } ark-transcript = { version = "0.0.3", default-features = false } [dev-dependencies] @@ -49,3 +49,4 @@ print-trace = [ "w3f-plonk-common/print-trace" ] asm = [ "w3f-pcs/asm" ] +test-vectors = [ "w3f-plonk-common/test-vectors" ] diff --git a/w3f-ring-proof/src/lib.rs b/w3f-ring-proof/src/lib.rs index 79ed917..ca45992 100644 --- a/w3f-ring-proof/src/lib.rs +++ b/w3f-ring-proof/src/lib.rs @@ -1,7 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; -use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_serialize::CanonicalSerialize; use ark_std::rand::RngCore; @@ -24,26 +22,6 @@ pub type RingProof = Proof>::C>, /// Polynomial Commitment Schemes. pub use w3f_pcs::pcs; -// Try and increment hash to curve. -pub(crate) fn hash_to_curve>( - message: &[u8], -) -> Affine { - use blake2::Digest; - let mut seed = message.to_vec(); - let cnt_offset = seed.len(); - seed.push(0); - loop { - let hash: [u8; 64] = blake2::Blake2b::digest(&seed[..]).into(); - let x = F::from_le_bytes_mod_order(&hash); - if let Some(point) = Affine::::get_point_from_y_unchecked(x, false) { - let point = point.clear_cofactor(); - assert!(point.is_in_correct_subgroup_assuming_on_curve()); - return point; - } - seed[cnt_offset] += 1; - } -} - #[derive(Clone)] pub struct ArkTranscript(ark_transcript::Transcript); @@ -121,7 +99,7 @@ mod tests { ArkTranscript::new(b"w3f-ring-proof-test"), ); let t_verify = start_timer!(|| "Verify"); - let res = ring_verifier.verify_ring_proof(proof, result.into_affine()); + let res = ring_verifier.verify(proof, result.into_affine()); end_timer!(t_verify); assert!(res); } @@ -160,7 +138,8 @@ mod tests { let domain = Domain::new(domain_size, true); let h = EdwardsAffine::rand(rng); let seed = EdwardsAffine::rand(rng); - let piop_params = PiopParams::setup(domain, h, seed); + let padding = EdwardsAffine::rand(rng); + let piop_params = PiopParams::setup(domain, h, seed, padding); (pcs_params, piop_params) } diff --git a/w3f-ring-proof/src/piop/params.rs b/w3f-ring-proof/src/piop/params.rs index b5a7111..22bd21e 100644 --- a/w3f-ring-proof/src/piop/params.rs +++ b/w3f-ring-proof/src/piop/params.rs @@ -8,31 +8,38 @@ use w3f_plonk_common::gadgets::ec::AffineColumn; use crate::piop::FixedColumns; +/// Plonk Interactive Oracle Proofs (PIOP) parameters. #[derive(Clone)] pub struct PiopParams> { - // Domain over which the piop is represented. + /// Domain over which the piop is represented. pub(crate) domain: Domain, - - // Number of bits used to represent a jubjub scalar. + /// Number of bits used to represent a jubjub scalar. pub(crate) scalar_bitlen: usize, - - // Length of the part of the column representing the public keys (including the padding). + /// Length of the part of the column representing the public keys (including the padding). pub keyset_part_size: usize, - - // The blinding base, a point from jubjub. + /// Blinding base point. pub(crate) h: Affine, - - // The point to start the summation from (as zero doesn't have a SW affine representation), - // should be from the jubjub prime-order subgroup complement. + /// Summation base point. pub(crate) seed: Affine, - - // The point used to pad the actual list of public keys. Should be of an unknown dlog. - pub(crate) padding_point: Affine, + /// The point used to pad the list of public keys. + pub(crate) padding: Affine, } impl> PiopParams { - pub fn setup(domain: Domain, h: Affine, seed: Affine) -> Self { - let padding_point = crate::hash_to_curve(b"/w3f/w3f-ring-proof/padding"); + /// Initialize PIOP parameters. + /// + /// - `domain`: polynomials evaluation domain. + /// - `h`: Blinding base point. + /// - `seed`: Accumulation base point + /// - `padding`: The point used to pad the list of public keys. + /// + /// All points should be of an unknown discrete log. + pub fn setup( + domain: Domain, + h: Affine, + seed: Affine, + padding: Affine, + ) -> Self { let scalar_bitlen = Curve::ScalarField::MODULUS_BIT_SIZE as usize; // 1 accounts for the last cells of the points and bits columns that remain unconstrained let keyset_part_size = domain.capacity - scalar_bitlen - 1; @@ -42,7 +49,7 @@ impl> PiopParams { keyset_part_size, h, seed, - padding_point, + padding, } } @@ -59,7 +66,7 @@ impl> PiopParams { pub fn points_column(&self, keys: &[Affine]) -> AffineColumn> { assert!(keys.len() <= self.keyset_part_size); let padding_len = self.keyset_part_size - keys.len(); - let padding = vec![self.padding_point; padding_len]; + let padding = vec![self.padding; padding_len]; let points = [keys, &padding, &self.power_of_2_multiples_of_h()].concat(); assert_eq!(points.len(), self.domain.capacity - 1); AffineColumn::public_column(points, &self.domain) @@ -107,8 +114,10 @@ mod tests { let rng = &mut test_rng(); let h = EdwardsAffine::rand(rng); let seed = EdwardsAffine::rand(rng); + let padding = EdwardsAffine::rand(rng); let domain = Domain::new(1024, false); - let params = PiopParams::::setup(domain, h, seed); + + let params = PiopParams::::setup(domain, h, seed, padding); let t = Fr::rand(rng); let t_bits = params.scalar_part(t); let th = cond_sum(&t_bits, ¶ms.power_of_2_multiples_of_h()); diff --git a/w3f-ring-proof/src/ring.rs b/w3f-ring-proof/src/ring.rs index a1d9350..600455d 100644 --- a/w3f-ring-proof/src/ring.rs +++ b/w3f-ring-proof/src/ring.rs @@ -18,41 +18,38 @@ use crate::PiopParams; const IDLE_ROWS: usize = ZK_ROWS + 1; /// Commitment to a list of VRF public keys as is used as a public input to the ring proof SNARK verifier. - -/// The VRF keys are (inner) curve points that we represent in the affine short Weierstrass coordinates. +/// +/// The VRF keys are (inner) curve points that we represent in the affine Twisted Edwards coordinates. /// We commit to the coordinate vectors independently using KZG on the outer curve. To make the commitment /// updatable we use SRS in the Lagrangian form: `L1, ..., Ln`, where `Li = L_i(t)G`. /// The commitment to a vector `a1, ..., an` is then `a1L1 + ... + anLn`. - +/// /// We pad the list of keys with a `padding` point with unknown dlog up to a certain size. /// Additionally, to make the commitment compatible with the snark, /// we append the power-of-2 powers of the VRF blinding Pedersen base /// `H, 2H, 4H, ..., 2^(s-1)H`, where `s` is the bitness of the VRF curve scalar field. /// The last `IDLE_ROWS = 4` elements are set to `(0, 0)`. - +/// /// Thus, the vector of points we commit to coordinatewise is /// `pk1, ..., pkn, padding, ..., padding, H, 2H, ..., 2^(s-1)H, 0, 0, 0, 0` - -// `KzgCurve` -- outer curve, subgroup of a pairing-friendly curve. We instantiate it with bls12-381 G1. -// `VrfCurveConfig` -- inner curve, the curve used by the VRF, in SW form. We instantiate it with Bandersnatch. -// `F` shared scalar field of the outer and the base field of the inner curves. #[derive(Clone, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] pub struct Ring< F: PrimeField, KzgCurve: Pairing, VrfCurveConfig: TECurveConfig, > { - // KZG commitments to the coordinates of the vector described above + /// KZG commitment to the x coordinates of the described vector. pub cx: KzgCurve::G1Affine, + /// KZG commitment to the y coordinates of the described vector. pub cy: KzgCurve::G1Affine, - // KZG commitment to a bitvector highlighting the part of the vector corresponding to the public keys. + /// KZG commitment to a bitvector highlighting the part of the vector corresponding to the public keys. pub selector: KzgCurve::G1Affine, - // maximal number of keys the commitment can "store". For domain of size `N` it is `N - (s + IDLE_ROWS)` + /// Maximal number of keys the commitment can "store". For domain of size `N` it is `N - (s + IDLE_ROWS)`. pub max_keys: usize, - // the number of keys "stored" in this commitment + /// Number of keys "stored" in this commitment. pub curr_keys: usize, - // a parameter - pub padding_point: Affine, + // Padding point. + pub padding: Affine, } impl< @@ -76,22 +73,23 @@ impl< VrfCurveConfig: TECurveConfig, > Ring { - // Builds the commitment to the vector - // `padding, ..., padding, H, 2H, ..., 2^(s-1)H, 0, 0, 0, 0`. - // We compute it as a sum of commitments of 2 vectors: - // `padding, ..., padding`, and - // `0, ..., 0, (H - padding), (2H - padding), ..., (2^(s-1)H - padding), -padding, -padding, -padding, -padding`. - // The first one is `padding * G`, the second requires an `(IDLE_ROWS + s)`-msm to compute. + /// Builds the commitment to the vector + /// `padding, ..., padding, H, 2H, ..., 2^(s-1)H, 0, 0, 0, 0`. + /// + /// We compute it as a sum of commitments of 2 vectors: + /// `padding, ..., padding`, and + /// `0, ..., 0, (H - padding), (2H - padding), ..., (2^(s-1)H - padding), -padding, -padding, -padding, -padding`. + /// The first one is `padding * G`, the second requires an `(IDLE_ROWS + s)`-msm to compute. + /// + /// - `piop_params`: SNARK parameters + /// - `srs`: Should return `srs[range]` for `range = (piop_params.keyset_part_size..domain_size)` + /// - `g`: Generator used in the SRS pub fn empty( - // SNARK parameters piop_params: &PiopParams, - // Should return `srs[range]` for `range = (piop_params.keyset_part_size..domain_size)` srs: impl Fn(Range) -> Result, ()>, - // generator used in the SRS g: KzgCurve::G1, ) -> Self { - let padding_point = piop_params.padding_point; - let (padding_x, padding_y) = padding_point.xy().unwrap(); // panics on inf, never happens + let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); // panics on inf, never happens let c1x = g * padding_x; let c1y = g * padding_y; @@ -122,19 +120,22 @@ impl< selector, max_keys: piop_params.keyset_part_size, curr_keys: 0, - padding_point, + padding: piop_params.padding, } } + /// Appends a set key sequence to the ring. + /// + /// - `keys`: Keys to append. + /// - `srs`: Should return `srs[range]` for `range = (self.curr_keys..self.curr_keys + keys.len())` pub fn append( &mut self, keys: &[Affine], - // Should return `srs[range]` for `range = (self.curr_keys..self.curr_keys + keys.len())` srs: impl Fn(Range) -> Result, ()>, ) { let new_size = self.curr_keys + keys.len(); assert!(new_size <= self.max_keys); - let (padding_x, padding_y) = self.padding_point.xy().unwrap(); + let (padding_x, padding_y) = self.padding.xy().unwrap(); let (xs, ys): (Vec, Vec) = keys .iter() .map(|p| p.xy().unwrap()) @@ -154,17 +155,18 @@ impl< self.curr_keys = new_size; } - // Builds the ring from the keys provided with 2 MSMs of size `keys.len() + scalar_bitlen + 5`. - // In some cases it may be beneficial to cash the empty ring, as updating it costs 2 MSMs of size `keys.len()`. + /// Builds the ring from the keys provided with 2 MSMs of size `keys.len() + scalar_bitlen + 5`. + /// + /// In some cases it may be beneficial to cash the empty ring, as updating it costs 2 MSMs of size `keys.len()`. + /// + /// - `piop_params`: SNARK parameters. + /// - `srs`: full-size Lagrangian SRS. pub fn with_keys( - // SNARK parameters piop_params: &PiopParams, keys: &[Affine], - // full-size Lagrangian srs srs: &RingBuilderKey, ) -> Self { - let padding_point = piop_params.padding_point; - let (padding_x, padding_y) = padding_point.xy().unwrap(); // panics on inf, never happens + let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); // panics on inf, never happens let powers_of_h = piop_params.power_of_2_multiples_of_h(); // Computes @@ -207,7 +209,7 @@ impl< selector, max_keys: piop_params.keyset_part_size, curr_keys: keys.len(), - padding_point, + padding: piop_params.padding, } } @@ -220,7 +222,7 @@ impl< cx: KzgCurve::G1Affine, cy: KzgCurve::G1Affine, selector: KzgCurve::G1Affine, - padding_point: Affine, + padding: Affine, ) -> Self { let max_keys = domain_size - (VrfCurveConfig::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS); @@ -230,7 +232,7 @@ impl< selector, max_keys, curr_keys: 0, - padding_point, + padding, } } } @@ -284,8 +286,9 @@ mod tests { // piop params let h = EdwardsAffine::rand(rng); let seed = EdwardsAffine::rand(rng); + let padding = EdwardsAffine::rand(rng); let domain = Domain::new(domain_size, true); - let piop_params = PiopParams::setup(domain, h, seed); + let piop_params = PiopParams::setup(domain, h, seed, padding); let mut ring = TestRing::empty(&piop_params, srs, ring_builder_key.g1); let (monimial_cx, monimial_cy) = get_monomial_commitment(&pcs_params, &piop_params, &[]); @@ -315,8 +318,9 @@ mod tests { // piop params let h = EdwardsAffine::rand(rng); let seed = EdwardsAffine::rand(rng); + let padding = EdwardsAffine::rand(rng); let domain = Domain::new(domain_size, true); - let piop_params = PiopParams::setup(domain, h, seed); + let piop_params = PiopParams::setup(domain, h, seed, padding); let ring = TestRing::empty(&piop_params, srs, ring_builder_key.g1); let same_ring = TestRing::with_keys(&piop_params, &[], &ring_builder_key); diff --git a/w3f-ring-proof/src/ring_prover.rs b/w3f-ring-proof/src/ring_prover.rs index 2fe35f8..ef9506c 100644 --- a/w3f-ring-proof/src/ring_prover.rs +++ b/w3f-ring-proof/src/ring_prover.rs @@ -7,9 +7,9 @@ use w3f_plonk_common::transcript::PlonkTranscript; use crate::piop::params::PiopParams; use crate::piop::{FixedColumns, PiopProver, ProverKey}; -use crate::RingProof; +use crate::{ArkTranscript, RingProof}; -pub struct RingProver +pub struct RingProver where F: PrimeField, CS: PCS, diff --git a/w3f-ring-proof/src/ring_verifier.rs b/w3f-ring-proof/src/ring_verifier.rs index 52bbc4b..322c18f 100644 --- a/w3f-ring-proof/src/ring_verifier.rs +++ b/w3f-ring-proof/src/ring_verifier.rs @@ -10,9 +10,9 @@ use w3f_plonk_common::verifier::PlonkVerifier; use crate::piop::params::PiopParams; use crate::piop::{FixedColumnsCommitted, PiopVerifier, VerifierKey}; -use crate::RingProof; +use crate::{ArkTranscript, RingProof}; -pub struct RingVerifier +pub struct RingVerifier where F: PrimeField, CS: PCS, @@ -45,7 +45,7 @@ where } } - pub fn verify_ring_proof(&self, proof: RingProof, result: Affine) -> bool { + pub fn verify(&self, proof: RingProof, result: Affine) -> bool { let (challenges, mut rng) = self.plonk_verifier.restore_challenges( &result, &proof,