Introduce DeferredField trait with eager implementations

Add the `deferred` module with a `DeferredField` trait that enables
accumulating multiple unreduced products before performing a single
reduction.  The trait uses an accumulation-based API: callers feed
factor pairs into an `Accumulator` via `mul_accumulate` /
`square_accumulate`, then call `reduce` once at the end.

For now, both Fp and Fq implement the trait with `Accumulator = Self`,
performing eager reduction on each accumulation.  A later commit will
swap in a wide accumulator that defers reduction for real.

The module is feature-gated behind the `deferred` feature flag.
This commit is contained in:
Alex Xiong 2026-04-08 14:47:20 +08:00
parent 03d9e212b5
commit c1ec4b7830
No known key found for this signature in database
GPG key ID: 7A85B16A27849F46
5 changed files with 77 additions and 0 deletions

View file

@ -71,4 +71,5 @@ gpu = ["alloc", "ec-gpu"]
sqrt-table = ["alloc", "lazy_static"]
repr-c = []
uninline-portable = []
deferred = []
serde = ["hex", "serde_crate"]

29
src/deferred.rs Normal file
View file

@ -0,0 +1,29 @@
//! Deferred normalization for field arithmetic.
//!
//! This module provides the [`DeferredField`] trait, which enables accumulating
//! multiple unreduced products before performing a single expensive reduction.
//! This is useful for operations like inner products where many multiplications
//! feed into a sum.
use core::fmt::Debug;
/// A trait for fields that support deferred reduction of products.
///
/// Instead of reducing each multiplication result immediately, callers
/// accumulate products into an [`Accumulator`](Self::Accumulator) via
/// [`mul_accumulate`](Self::mul_accumulate) and
/// [`square_accumulate`](Self::square_accumulate), then perform a single
/// reduction at the end with [`reduce`](Self::reduce).
pub trait DeferredField: ff::Field {
/// A wide accumulator for unreduced products.
type Accumulator: Copy + Clone + Debug + Default;
/// Multiplies `a` by `b` and adds the result into `acc`.
fn mul_accumulate(acc: &mut Self::Accumulator, a: &Self, b: &Self);
/// Squares `a` and adds the result into `acc`.
fn square_accumulate(acc: &mut Self::Accumulator, a: &Self);
/// Reduces the accumulator to a canonical field element.
fn reduce(acc: Self::Accumulator) -> Self;
}

View file

@ -12,6 +12,8 @@ use lazy_static::lazy_static;
use ff::{FieldBits, PrimeFieldBits};
use crate::arithmetic::{adc, mac, sbb, SqrtTableHelpers};
#[cfg(feature = "deferred")]
use crate::deferred::DeferredField;
#[cfg(feature = "sqrt-table")]
use crate::arithmetic::SqrtTables;
@ -477,6 +479,26 @@ impl Fp {
}
}
#[cfg(feature = "deferred")]
impl DeferredField for Fp {
type Accumulator = Fp;
#[inline]
fn mul_accumulate(acc: &mut Fp, a: &Fp, b: &Fp) {
*acc += *a * *b;
}
#[inline]
fn square_accumulate(acc: &mut Fp, a: &Fp) {
*acc += a.square();
}
#[inline]
fn reduce(acc: Fp) -> Fp {
acc
}
}
impl From<Fp> for [u8; 32] {
fn from(value: Fp) -> [u8; 32] {
value.to_repr()

View file

@ -12,6 +12,8 @@ use lazy_static::lazy_static;
use ff::{FieldBits, PrimeFieldBits};
use crate::arithmetic::{adc, mac, sbb, SqrtTableHelpers};
#[cfg(feature = "deferred")]
use crate::deferred::DeferredField;
#[cfg(feature = "sqrt-table")]
use crate::arithmetic::SqrtTables;
@ -477,6 +479,26 @@ impl Fq {
}
}
#[cfg(feature = "deferred")]
impl DeferredField for Fq {
type Accumulator = Fq;
#[inline]
fn mul_accumulate(acc: &mut Fq, a: &Fq, b: &Fq) {
*acc += *a * *b;
}
#[inline]
fn square_accumulate(acc: &mut Fq, a: &Fq) {
*acc += a.square();
}
#[inline]
fn reduce(acc: Fq) -> Fq {
acc
}
}
impl From<Fq> for [u8; 32] {
fn from(value: Fq) -> [u8; 32] {
value.to_repr()

View file

@ -22,6 +22,9 @@ mod curves;
mod fields;
pub mod arithmetic;
#[cfg(feature = "deferred")]
#[cfg_attr(docsrs, doc(cfg(feature = "deferred")))]
pub mod deferred;
pub mod pallas;
pub mod vesta;