Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ proptest = "1.2.0"
[features]
default = []
jem = ["tikv-jemallocator"]
ipa-hybrid = []

[profile.release]
debug = 1
Expand Down
25 changes: 24 additions & 1 deletion src/provider/pcs/hyrax_pc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
math::Math,
polys::eq::EqPolynomial,
provider::{
pcs::ipa::{InnerProductArgumentLinear, InnerProductInstance, InnerProductWitness},
pcs::ipa::{InnerProductInstance, InnerProductWitness},
traits::{DlogGroup, DlogGroupExt},
},
start_span,
Expand All @@ -31,6 +31,15 @@ use crate::big_num::delayed_reduction::DelayedReduction;
use crate::big_num::montgomery::MontgomeryLimbs;
use crate::provider::msm::{AffineGroupElement, FixedBaseMul, vartime_scalar_mul};

#[cfg(not(feature = "ipa-hybrid"))]
use crate::provider::pcs::ipa::InnerProductArgumentLinear;
#[cfg(feature = "ipa-hybrid")]
use crate::provider::pcs::ipa_hybrid::InnerProductArgumentHybrid;

/// Number of bullet reduction rounds for the hybrid IPA.
#[cfg(feature = "ipa-hybrid")]
const HYBRID_BULLET_ROUNDS: usize = 3;

/// Bind polynomial top variables using delayed reduction for Montgomery multiply.
/// Avoids per-product REDC, reducing multiply cost by ~50%.
/// The accumulator array (r_len * 72B) must fit in L2 cache.
Expand Down Expand Up @@ -135,7 +144,10 @@ pub struct HyraxEvaluationArgument<E: Engine>
where
E::GE: DlogGroupExt,
{
#[cfg(not(feature = "ipa-hybrid"))]
ipa: InnerProductArgumentLinear<E>,
#[cfg(feature = "ipa-hybrid")]
ipa: InnerProductArgumentHybrid<E, HYBRID_BULLET_ROUNDS>,
}

impl<E: Engine> PCSEngineTrait<E> for HyraxPCS<E>
Expand Down Expand Up @@ -463,6 +475,7 @@ where
let (_ipa_span, ipa_t) = start_span!("hyrax_prove_ipa");
let ipa_instance = InnerProductInstance::<E>::new(&comm_LZ, &R, &comm_eval.comm[0]);
let ipa_witness = InnerProductWitness::<E>::new(&LZ, &r_LZ, &blind_eval.blind[0]);
#[cfg(not(feature = "ipa-hybrid"))]
let ipa = InnerProductArgumentLinear::<E>::prove(
&ck.ck,
&ck.h,
Expand All @@ -472,6 +485,16 @@ where
&ipa_witness,
transcript,
)?;
#[cfg(feature = "ipa-hybrid")]
let ipa = InnerProductArgumentHybrid::<E, HYBRID_BULLET_ROUNDS>::prove(
&ck.ck,
&ck.h,
&ck_eval.ck[0],
&ck_eval.h,
&ipa_instance,
&ipa_witness,
transcript,
)?;
info!(elapsed_ms = %ipa_t.elapsed().as_millis(), "hyrax_prove_ipa");

Ok(HyraxEvaluationArgument { ipa })
Expand Down
41 changes: 34 additions & 7 deletions src/provider/pcs/ipa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ pub(crate) fn inner_product<T: Field + Send + Sync>(a: &[T], b: &[T]) -> T {
/// An inner product instance consists of a commitment to a vector `a` and another vector `b`
/// and the claim that c = <a, b>.
pub struct InnerProductInstance<E: Engine> {
comm_a_vec: E::GE,
b_vec: Vec<E::Scalar>,
comm_c: E::GE,
pub(crate) comm_a_vec: E::GE,
pub(crate) b_vec: Vec<E::Scalar>,
pub(crate) comm_c: E::GE,
}

/// Holds witness for the inner product instance.
pub struct InnerProductWitness<E: Engine> {
a_vec: Vec<E::Scalar>,
r_a: E::Scalar, // blind for the commitment to a_vec
r_c: E::Scalar, // blind for the commitment to c
pub(crate) a_vec: Vec<E::Scalar>,
pub(crate) r_a: E::Scalar, // blind for the commitment to a_vec
pub(crate) r_c: E::Scalar, // blind for the commitment to c
}

impl<E: Engine> InnerProductInstance<E>
Expand Down Expand Up @@ -133,6 +133,24 @@ where
) -> Result<Self, SpartanError> {
transcript.dom_sep(Self::protocol_name());

let n = U.b_vec.len();
if W.a_vec.len() != n {
return Err(SpartanError::InvalidInputLength {
reason: format!(
"linear IPA prove: a_vec has {} elements but b_vec has {n}",
W.a_vec.len()
),
});
}
if ck.len() < n {
return Err(SpartanError::InvalidInputLength {
reason: format!(
"linear IPA prove: ck has {} elements but need at least {n}",
ck.len()
),
});
}

// absorb the instance in the transcript
transcript.absorb(b"U", U);

Expand Down Expand Up @@ -193,13 +211,22 @@ where
if self.z_vec.len() != n || ck.len() < self.z_vec.len() {
return Err(SpartanError::InvalidInputLength {
reason: format!(
"Inner product argument verify: Expected {} elements in z_vec, got {}",
"linear IPA verify: expected {} elements in z_vec, got {}",
n,
self.z_vec.len()
),
});
}

if U.b_vec.len() != n {
return Err(SpartanError::InvalidInputLength {
reason: format!(
"linear IPA verify: b_vec has {} elements but expected {n}",
U.b_vec.len()
),
});
}

if U.comm_a_vec * r + self.delta
!= E::GE::vartime_multiscalar_mul(&self.z_vec, &ck[0..self.z_vec.len()], true)?
+ *h * self.z_delta
Expand Down
Loading
Loading