Skip to content
Open
Show file tree
Hide file tree
Changes from all 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,024 changes: 982 additions & 42 deletions crates/halo2_proofs/src/plonk/prover.rs

Large diffs are not rendered by default.

40 changes: 39 additions & 1 deletion crates/halo2_proofs/src/poly/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1970,6 +1970,24 @@ impl<C: CurveAffine> Params<C> {
}
}

/// Returns whether [`Self::commit_lagrange`] would use the prepared
/// no-orbits backend for a polynomial of `polynomial_len` coefficients.
#[cfg(all(feature = "multicore", not(feature = "orbits")))]
pub(crate) fn prepared_lagrange_commitments_active(&self, polynomial_len: usize) -> bool {
// Keep these checks aligned with the prepared no-orbits route above
// without factoring the commitment hot path through another helper.
if crate::multicore::current_num_threads() > prepared_commitment_max_threads(self.k) {
return false;
}

let (Some(prepared), Some(_fixed_bases)) = (self.lagrange_table(), self.fixed_base_table())
else {
return false;
};
let n = self.n as usize;
prepared.terms() == n && polynomial_len == n
}

/// Generates an empty multiscalar multiplication struct using the
/// appropriate params.
pub fn empty_msm(&self) -> MSM<'_, C> {
Expand Down Expand Up @@ -2241,6 +2259,14 @@ impl<C: CurveAffine> Params<C> {
/// params. Concurrent callers outside that pool safely wait for and share
/// the same attempt; fanning a cold call out across the worker pool can
/// occupy its other workers and serialize the initializer's parallel work.
///
/// # Security
///
/// Commitments evaluated from these prepared tables are variable-time in
/// their secret inputs. When proving several circuits together, their
/// relative sparsity and similarity can affect runtime. Callers must not
/// expose that timing across an untrusted boundary when those relationships
/// are sensitive.
pub fn prepare_commitments(&self) -> bool {
#[cfg(feature = "orbits")]
{
Expand Down Expand Up @@ -3544,7 +3570,19 @@ fn prepared_commitments_match_unprepared() {
.num_threads(num_threads)
.build()
.expect("test pool must build")
.install(|| exercise(&armed, &unarmed, 41 + num_threads as u64));
.install(|| {
#[cfg(not(feature = "orbits"))]
{
let full_len = armed.n as usize;
assert_eq!(
armed.prepared_lagrange_commitments_active(full_len),
num_threads <= prepared_commitment_max_threads(armed.k),
);
assert!(!armed.prepared_lagrange_commitments_active(full_len - 1));
assert!(!unarmed.prepared_lagrange_commitments_active(full_len));
}
exercise(&armed, &unarmed, 41 + num_threads as u64)
});
}
}

Expand Down
12 changes: 12 additions & 0 deletions crates/orchard/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,12 @@ impl<S: InProgressSignatures> InProgress<Unproven, S> {
///
/// Also returns an error if `pk` does not match the circuit version this
/// bundle's actions were built for, or if proof creation fails.
///
/// # Security
///
/// With a [`ProvingKey`] armed by [`ProvingKey::prepare_proving`], relative
/// sparsity and similarity between Actions can affect proving latency; see
/// [`Proof::create`].
pub fn create_proof(
&self,
pk: &ProvingKey,
Expand Down Expand Up @@ -1620,6 +1626,12 @@ impl<S: InProgressSignatures, V> Bundle<InProgress<Unproven, S>, V> {
///
/// Also returns an error if `pk` does not match this bundle's
/// [`circuit_version`](Self::circuit_version), or if proof creation fails.
///
/// # Security
///
/// With a [`ProvingKey`] armed by [`ProvingKey::prepare_proving`], relative
/// sparsity and similarity between Actions can affect proving latency; see
/// [`Proof::create`].
pub fn create_proof(
self,
pk: &ProvingKey,
Expand Down
16 changes: 16 additions & 0 deletions crates/orchard/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,14 @@ impl ProvingKey {
/// means arming was a no-op (Orchard was built with neither `multicore`
/// nor `orbits`, or its backend declined) and proving simply keeps its
/// unprepared path. Callers may ignore the result.
///
/// # Security
///
/// Proofs created after preparation remain variable-time in private
/// witnesses. When proving several Actions together, their sparsity and
/// similarity may affect timing; see [`halo2_proofs::plonk::create_proof`].
/// Do not expose proving latency across an untrusted boundary when those
/// relationships are sensitive.
pub fn prepare_proving(&self) -> bool {
self.params.prepare_commitments()
}
Expand Down Expand Up @@ -1597,6 +1605,14 @@ impl Proof {
///
/// All instances of a bundle carry the same `disableCrossAddress` value; that uniformity
/// is the bundle layer's invariant, and is not checked here.
///
/// # Security
///
/// Proof creation is variable-time in the private witnesses. With a
/// [`ProvingKey`] armed by [`ProvingKey::prepare_proving`], the relative
/// sparsity and similarity of several Actions can affect runtime. Do not
/// expose proving latency across an untrusted boundary when those
/// relationships are sensitive.
pub fn create(
pk: &ProvingKey,
circuits: &[Circuit],
Expand Down
6 changes: 6 additions & 0 deletions crates/orchard/src/pczt/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ impl super::Bundle {
/// Also returns an error if required Prover-role fields are missing or invalid,
/// or if proof creation fails.
///
/// # Security
///
/// With a [`ProvingKey`] armed by [`ProvingKey::prepare_proving`], relative
/// sparsity and similarity between Actions can affect proving latency; see
/// [`Proof::create`].
///
/// [`OrchardCircuitVersion::PostNu6_3`]: crate::circuit::OrchardCircuitVersion::PostNu6_3
pub fn create_proof<R: Rng + CryptoRng>(
&mut self,
Expand Down
27 changes: 25 additions & 2 deletions crates/pasta_curves/src/arithmetic/curves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,33 @@ pub trait CurveExt:
#[cfg(any(feature = "multicore", feature = "orbits"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "multicore", feature = "orbits"))))]
pub trait PreparedZeroCheck<C: CurveExt>: core::fmt::Debug + Send + Sync {
/// The number of fixed bases this preparation covers; `scalars` below
/// must have exactly this length.
/// The number of fixed bases this preparation covers; scalar slices
/// passed to the evaluation methods must have exactly this length.
fn terms(&self) -> usize;

/// Compares the variable-time scalar work of this prepared backend.
///
/// Returns `Some(true)` when the backend's conservative scalar-work model
/// accepts `candidate` over `baseline`, and `Some(false)` when it does not.
/// Returns `None` when the backend cannot compare the inputs at all. The
/// slices must have equal length and represent one evaluation each. Unlike
/// the evaluation methods, they may be samples of any length. The result
/// describes only the backend's modeled dimensions for these slices; it is
/// not an elapsed-time guarantee, a prediction for unsampled values, or a
/// statement of algebraic equivalence.
///
/// # Security
///
/// Variable-time in both scalar slices; callers must not use this with
/// secret scalars unless they already accept scalar-dependent timing.
fn scalar_work_is_at_most_vartime(
&self,
_candidate: &[C::ScalarExt],
_baseline: &[C::ScalarExt],
) -> Option<bool> {
None
}

/// Whether $\sum_i \[k_i\] P_i + \sum_j \[s_j\] Q_j$ is the identity.
///
/// # Security
Expand Down
Loading
Loading