ZK/SEC Research notes from zkSecurity
All posts
educative

Optimizing Barrett Reduction: Tighter Bounds Eliminate Redundant Subtractions

Barrett reduction

Barrett reduction is a widely used algorithm for reducing a value modulo $m$. Our analysis, conducted during the Rust p256 crate audit, shows that the error bound for Barrett reduction can be tighter than traditionally assumed. For most moduli used in cryptography (e.g., NIST curves), the quotient approximation error is at most 1 (not 2). This improvement eliminates the need for a second subtraction in practice. By adopting this optimization, RustCrypto p256 achieves a 14% performance improvement in scalar multiplication.

What Is Barrett Reduction?

Barrett reduction is a method for efficiently computing the remainder of a division operation (i.e., modulus operation), $x \mod m$, without performing an actual division.

We want to compute $r = x \mod m$, which can be expressed as $x = q \cdot m + r$, where $q$ is the quotient and $r$ is the remainder. In practice (e.g., cryptographic field arithmetic), the modulus $m$ can be a large integer represented using $k$ limbs. Each limb is a 32-bit or 64-bit value (depending on the machine word), making the radix $b = 2^{32}$ or $2^{64}$. In practice, the value $x$ is a $2k$-limb integer because it results from the multiplication of two $k$-limb integers.

One way to compute $r$ is to first calculate $q$ as:

$$ q = \lfloor x / m \rfloor $$

Once $q$ is determined, $r$ can be computed as $r = x - q \cdot m$. Barrett reduction provides a more efficient way to approximate $q$, avoiding the need for direct division, which is computationally expensive.

First, let's rewrite the formula above as:

$$ q = \lfloor x / m \rfloor = \left\lfloor\frac{x}{m} \cdot \frac{b^{2k}}{b^{2k}}\right\rfloor = \left\lfloor\frac{x}{m} \cdot \frac{b^{2k}}{b^{k+1}\cdot b^{k-1}}\right\rfloor = \left\lfloor\frac{b^{2k}}{m} \cdot \frac{x}{b^{k-1}} \cdot \frac{1}{b^{k+1}}\right\rfloor $$

So far, our computation is exact. However, instead of computing $q$ exactly, we'll approximate it by computing:

$$ \tilde{q} = \left\lfloor \frac{{\color{red}{\lfloor}} \frac{x}{b^{k-1}} {\color{red}{\rfloor}} \cdot {\color{red}{\lfloor}} \frac{b^{2k}}{m} {\color{red}{\rfloor}}}{b^{k+1}}\right\rfloor $$

This allows us to precompute $\mu = \lfloor \frac{b^{2k}}{m} \rfloor$ and rewrite the above as:

$$ q= \left\lfloor \frac{\lfloor \frac{x}{b^{k-1}} \rfloor \cdot \mu}{b^{k+1}}\right\rfloor $$

Note: Both $\lfloor \frac{\cdot}{b^{k-1}} \rfloor$ and $\lfloor \frac{\cdot}{b^{k+1}} \rfloor$ are fast to compute using right shifts.

Since the two approximations can be smaller than their exact computations, we have $\tilde{q} \leq q$. Traditional analysis has shown that $\tilde{q} \in [q - 2, q]$ (we will elaborate on this in the analysis section). This means the approximate quotient $\tilde{q}$ is at most 2 less than the true quotient $q$.

Computing $r$ in $x \approx \tilde{q} \cdot m + r$

If we had computed $q$ exactly, we would simply compute:

$$r = x - q \cdot m$$

Since $r \in [0, m)$, only the bit length of $m$ is involved in that subtraction. Thus, we can compute it faster by involving only the least significant $b^k$ bits:

$$r = x - q \cdot m \mod{b^k} = (x \mod{b^k}) - (q \cdot m \mod{b^k})$$

(where modulo $b^k$ can be computed efficiently)

r-mod

However, remember that we have computed an approximation $\tilde{q}$ of $q$, where $\tilde{q} \in [q-2, q]$.

We know that either:

  1. $r = x - \tilde{q} \cdot m$
  2. $r = x - (\tilde{q} + 1) \cdot m$
  3. $r = x - (\tilde{q} + 2) \cdot m$

To compute $r$, we first calculate case 1. If the result is not smaller than $m$, we subtract $m$ once or twice to bring it into the correct range.

This means that we might not have $\tilde{r} = x - \tilde{q} \cdot m < b^k$ immediately. Instead, the value could be $m$ or $2m$ times larger.

Since $m < b^k$, we know $2 \cdot m < 2 \cdot b^k$. This allows us to upper bound our approximation:

$$r \leq\tilde{r} \leq r + 2m < b^k + 2 \cdot b^k < b^{k+1}$$

Then, we can calculate $\tilde{r}$ more efficiently:

$$\tilde{r} = ((x \bmod{b^{k+1}}) - (\tilde{q}\cdot m \bmod{b^{k+1}})) \bmod{b^{k+1}}$$

tilde-r-mod

Again, the $\bmod{b^{k+1}}$ operation is very efficient on binary machines.

We finally arrive at the algorithm as described in Handbook of Applied Cryptography, Chapter 14. The steps outlined above closely follow the process detailed in the book.

Barrett Algorithm

Source: Handbook of Applied Cryptography, Chapter 14

A Tighter Bound Analysis

The bound of $\tilde{q}$ directly determines how many times $r$ needs to be subtracted by $m$ to fall within the correct range. Traditionally, the bound is known to be $\tilde{q} \in [q-2, q]$. In this section, we will show that for almost all moduli in practice, the tighter bound holds: $\tilde{q} \in [q-1, q]$.

Remember that

$$q = \lfloor \frac{x}{m} \rfloor$$ $$\tilde{q} = \lfloor \frac{\lfloor \frac{x}{b^{k-1}} \rfloor \cdot \lfloor \frac{b^{2k}}{m} \rfloor}{b^{k+1}} \rfloor$$

Since $\tilde{q}$ is derived from a truncated approximation of $\frac{x}{m}$, it naturally satisfies $\tilde{q} \le q$.

Let's denote $\alpha = x \mod {b^{k-1}}$, where $\alpha \lt b^{k-1}$. Denote $\beta = b^{2k} \mod m$, where $\beta \lt m$. Then we can remove the floor operation:

$$\lfloor \frac{x}{b^{k-1}} \rfloor = \frac{x - \alpha}{b^{k-1}}$$ $$\lfloor \frac{b^{2k}}{m} \rfloor = \frac{b^{2k} - \beta}{m}$$

Then we can simplify $\tilde{q}$:

$$ \begin{align*} \tilde{q} &= \lfloor \frac{\lfloor \frac{x}{b^{k-1}} \rfloor \cdot \lfloor \frac{b^{2k}}{m} \rfloor}{b^{k+1}} \rfloor\\ &= \lfloor \frac{ \frac{x - \alpha}{b^{k-1}} \cdot \frac{b^{2k} - \beta}{m}}{b^{k+1}} \rfloor \\ &= \lfloor \frac{(x - \alpha) \cdot (b^{2k} - \beta)}{m \cdot b^{2k}} \rfloor \\ &= \lfloor \frac{x}{m} - {\color{red}{\frac{\alpha \cdot b^{2k} + \beta \cdot (x - \alpha)}{m \cdot b^{2k}}}} \rfloor \end{align*} $$

We use ${\color{red}{z}}$ to denote the red part (note that $z \ge 0$). Then we have $\tilde{q} = \lfloor \frac{x}{m} - {\color{red}{z}} \rfloor$. By the floor function inequality $\lfloor x \rfloor + \lfloor y \rfloor + 1 \ge \lfloor x + y \rfloor$, we have:

$$\lfloor \frac{x}{m} - z \rfloor + \lfloor z \rfloor + 1 \ge \lfloor \left(\frac{x}{m} - z\right) + z \rfloor = \lfloor \frac{x}{m} \rfloor = q$$

That is saying $\tilde{q} + \lfloor z \rfloor + 1 \ge q$.

The bound of $z$ is the key to analyzing the bound of $\tilde{q}$. If we can prove that $0 \le z \lt 2$, then we will have $\lfloor z \rfloor \le 1$ and finally $\tilde{q} + 2 \ge \tilde{q} + \lfloor z \rfloor + 1 \ge q$. Let's analyze the bound of $z$.

Prove that $\tilde{q} \in [q-2, q]$

We have:

$$ \begin{align*} z &= \frac{\alpha \cdot b^{2k} + \beta \cdot (x-\alpha)}{m \cdot b^{2k}} \\ &\lt \frac{{\color{red}{b^{k-1}}} \cdot b^{2k} + \beta \cdot {\color{red}{b^{2k}}}}{m\cdot b^{2k}} \\ &= \frac{b^{k-1} + \beta}{m} \end{align*} $$

We know that $b^{k-1} \lt m$ (because $m$ is $k$-limb) and $\beta \lt m$. Then we have:

$$z \lt \frac{b^{k-1} + \beta}{m} \lt \frac{m + m}{m} = 2$$

And thus:

$$\lfloor z \rfloor \le 1$$

That's exactly what we want. Therefore, we conclude that $\tilde{q} + 2 \ge \tilde{q} + \lfloor z \rfloor + 1 \ge q$.

Tighter Bound in Practice: $\tilde{q} \in [q-1, q]$

We have proved that $\tilde{q} \in [q-2, q]$ under all circumstances. However, this is a loose bound. Here, we claim that for almost all moduli $m$ in practice, we have a tighter bound: $z \lt 1$, and thus $\tilde{q} + 1 \ge \tilde{q} + \lfloor z \rfloor + 1 \ge q$.

Let's examine which moduli $m$ satisfy this tighter bound. Recall that $z \lt \frac{b^{k-1} + \beta}{m}$, so $z \lt 1$ holds if the following is true:

$$\frac{b^{k-1} + \beta}{m} \le 1$$

Which means:

$$b^{k-1} + \beta \le m$$

Further:

$$\beta \le m - b ^{k-1}$$

That's saying if $\beta$ is no greater than $m-b^{k-1}$, then $z \lt 1$ and thus $\tilde{q} \in [q-1, q]$. We can formalize this as the Tighter Bound Criterion:

$$ \boxed{\text{Given a modulus } m \text{, if } \beta \le m - b^{k-1} \text{ (where } \beta = b^{2k} \bmod{m}\text{), then } \tilde{q} \in [q-1, q] \text{.}} $$

It's worth noting that $\beta = b^{2k} \mod{m}$ falls within $[0, m)$. In practice, where $b$ is either $2^{32}$ or $2^{64}$, and $m$ approaches $b^k$, the value $m - b^{k-1}$ is very close to $m$.

The behavior of $\beta = b^{2k} \bmod{m}$ resembles a uniform random distribution over $[0, m)$ for any random modulus $m$. This makes it highly probable that $\beta \le m - b^{k-1}$. Consequently, most moduli $m$ will satisfy $z \lt 1$, leading to $\tilde{q} + 1 \ge q$.

To quantify this probability, let's assume the common case where $\frac{b^k}{2} \lt m \lt b^k$ and $\beta$ follows a uniform distribution. Under these conditions:

$$ \Pr[\beta \le m - b^{k-1}] = \frac{m-b^{k-1}}{m} > 1 - \frac{2}{b} $$

To put this in perspective:

  • When $b = 2^{32}$, the probability of achieving the tighter bound exceeds $1 - \frac{1}{2^{31}}$.
  • When $b = 2^{64}$, the probability of achieving the tighter bound exceeds $1 - \frac{1}{2^{63}}$.

That is, for nearly all moduli in practice, the tighter bound $\tilde{q} \in [{q-1}, q]$ holds.

Here is an intuitive explanation: $\mu$ (i.e., $\lfloor \frac{b^{2k}}{m} \rfloor$) is the quotient of $m$ divide $b^{2k}$, and $\beta$ is the remainder. If $\beta$ is very small, then $\mu$ will be very close to the actual quotient and thus the calculation of $\tilde{q}$ will have less approximation errors. Our analysis shows that as long as $\beta$ is no greater than $m - b^{k-1}$, the calculated $\tilde{q}$ is at most $1$ less than $q$. As that is a very loose requirement for $\beta$ (or $m$), most of the moduli have a tighter bound.

Practical Optimization For Barrett Reduction Implementation

The tighter bound enables faster Barrett reduction implementation. According to traditional analysis, we may need to subtract $r$ by $m$ twice to get the final result. For a given modulus $m$, if the tighter bound holds, then we can subtract $r$ by $m$ at most once. This means we can save one subtraction.

This is very useful for constant time implementation where it always substract the max times. For example, in RustCrypto P-256 scalar field implementation, it always subtracts twice.

pub(super) const fn barrett_reduce(lo: U256, hi: U256) -> U256 {
    [...]

    let r1 = [a0, a1, a2, a3, a4];
    let r2 = q3_times_n_keep_five(&q3);
    let r = sub_inner_five(r1, r2);

    // Result is in range (0, 3*n - 1),
    // and 90% of the time, no subtraction will be needed.
    let r = subtract_n_if_necessary(r);
    let r = subtract_n_if_necessary(r);
    U256::new([r[0], r[1], r[2], r[3]])
}

As P-256 scalar field satisfies $\beta \le m - b^{k-1}$, the tighter bound $\tilde{q} \in [{q-1}, q]$ holds. This implies the calculated $\tilde{q}$ is at most $1$ less than the actual quotient $q$. This means r can be subtracted at most once to get the final result. The second subtract_n_if_necessary call in the code above is unnecessary and can be safely removed.

Benchmarks show that simply removing the second subtraction improves multiplication and inversion performance by 14%.

scalar operations/mul
    time:   [38.900 ns 38.957 ns 39.026 ns]
    change: [-14.379% -14.052% -13.734%] (p = 0.00 < 0.05)
    Performance has improved.
scalar operations/invert
    time:   [20.716 µs 20.758 µs 20.823 µs]
    change: [-14.817% -14.331% -13.969%] (p = 0.00 < 0.05)
    Performance has improved.

As analyzed in the previous section, the tighter bound holds for almost all moduli. Thus, this optimization applies to most of the Barrett reductions with fixed moduli (e.g., ECC, ZKP).

Here is the Python script to test if a modulus $m$ has the tighter bound:

# Tighter Bound Criterion for the Barret reduction
def tighter_bound_criterion(m):
    def inner_test(m, b):
        # k chosen such that b^{k-1} < m < b^k
        k = 1
        while b**k < m:
            k += 1
        print("k = ", k)
        beta = b**(2*k) % m

        # calculate criterion
        return beta <= m - b**(k-1)

    # test both b=2^32 and b=2^64
    return inner_test(m, 2**32) and inner_test(m, 2**64)

# P-256 scalar field
assert(tighter_bound_criterion(0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551) == True)

# P-256 base field
assert(tighter_bound_criterion(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff) == True)

Conclusion

Our analysis demonstrates that the error bound for the quotient approximation $\tilde{q}$ can be tightened from $[q-2, q]$ to $[q-1, q]$ for almost all moduli used in practice. This tighter bound eliminates the need for a second subtraction in most cases, enabling faster and more efficient implementations.

We showed how this optimization applies to real-world cryptographic libraries, such as RustCrypto's P-256 scalar field implementation, where removing the unnecessary subtraction improved performance significantly. These findings are broadly applicable to other cryptographic systems and zero-knowledge proof frameworks that rely on fixed moduli.

Keep reading
Latest

Variants of KZG: Part III, Multilinear Commitments with Zeromorph

In this blog post, we extend univariate KZG commitments to multilinear polynomials through Zeromorph. We introduce the univariatization map, encode the multilinear quotient identity as a univariate identity, and explain why the quotient encodings require degree checks. We then show how Zeromorph batches these checks into a single degree-bounded KZG opening and walk through its end-to-end opening protocol. We conclude by examining its proof size, prover cost, and verifier cost.

Varun Thakore · August 04, 2026

Variants of KZG: Part II, Multilinear Commitments with PST

In this blog post, we extend the ideas behind univariate KZG commitments to multilinear polynomials through the PST commitment scheme. We derive the multilinear quotient identity, explain how PST commits to and opens multilinear polynomials using a specialized multilinear setup and walk through its opening protocol. We conclude by examining the proof size, prover and verifier costs, and the limitations that motivate other multilinear polynomial commitment schemes.

Varun Thakore · July 28, 2026

Threshold ECDSA: Building CGGMP from scratch

A step-by-step build of CGGMP, an n-of-n threshold ECDSA scheme where parties jointly produce a signature without ever reconstructing the private key. We start from the multiplicative-to-additive (MtA) protocol and a semi-honest version of the signing protocol, then harden it into a maliciously secure one by layering in zero-knowledge proofs at each step. Along the way we cover the auxiliary Ring-Pedersen and Paillier parameters and the proofs that make them safe to use.

Samuel Tang · July 27, 2026
Recommended

Circle STARKs: Part I, Mersenne

Discover the intriguing world of Circle STARKs and how they can supercharge zero-knowledge proofs. This blog post sets the stage for a fascinating series about utilizing Mersenne prime fields to achieve lightning-fast arithmetic operations in STARK systems. You'll explore recent breakthroughs that make these fields more practical despite their previous limitations, and you'll get a sneak peek at what’s to come, including delving into group structures and implementing circle FFTs. If you're keen on cryptography and zero-knowledge proofs, this series will unveil how modern advancements are pushing the boundaries of what's possible.

Mathias Hall-Andersen · June 03, 2024

Accelerating ZK Proving with WebGPU: Techniques and Challenges

Hey there! We're diving into how leveraging WebGPU can revolutionize client-side proving for privacy-preserving zero-knowledge apps. By tackling the usual time and memory bottlenecks with innovative techniques like using GPUs, we're achieving significant performance gains. We'll share our experiences using WebGPU with various frameworks, offering insights into optimizing operations and managing data transfer efficiently. Plus, learn about the challenges and exciting potential of integrating WebGPU into zero-knowledge frameworks. Join us to explore the future of privacy tech!

Jaehun Kim, Jason Park · April 25, 2025

Faster Sumchecks: Part I

In this blog post, we explore how to optimize the sumcheck protocol, particularly when working with values in a small field and randomness from a large field, as often needed in zkVMs. We introduce various algorithms aimed at reducing expensive operations, focusing on minimizing large multiplications. Starting from using simple evaluation tables to more sophisticated techniques like precomputing accumulators and leveraging Lagrange interpolation, we demonstrate how to efficiently organize computations to speed up proving times. Readers will gain insights into handling arithmetic operations within the sumcheck protocol and learn about optimizing specific cases in zero-knowledge proofs.

Jason Park · November 21, 2025
More to explore

A Gentle Introduction to the MPC-in-the-Head Transformation

In this blog post, we dive into the fascinating world of zero-knowledge proofs using the MPC-in-the-Head transformation, a clever method that constructs proof systems from any secure multiparty computation protocol. Originally proposed in 2007, this transformation uses a creative approach involving "imaginary parties" to prove knowledge without revealing it. We explain how this technique can be applied to develop post-quantum signature schemes, providing insights into its practical implications and efficiency. By exploring these concepts, readers will uncover a unique intersection of cryptography and computer science.

Giorgio Dell'Immagine · February 20, 2025

noname meets Ethereum: Integration with SnarkJS

We're excited to share that our programming language, noname, now supports R1CS, making it easier to write zero-knowledge (ZK) circuits and deploy them on Ethereum using SnarkJS. This update introduces an alternative to the common Circom language, with a simple and intuitive syntax inspired by Rust and Golang. In this post, we illustrate how to deploy a noname-based Sudoku circuit on Ethereum, demonstrating core benefits like proving a solution's correctness without revealing it. Dive in to explore how noname could potentially unify the fragmented zkSNARK ecosystem and simplify your circuit writing process!

Katat Choi · June 01, 2024

Announcing mpcsec.org: What Goes Wrong When You Implement MPC

mpcsec.org is a new collaborative reference for common pitfalls in MPC implementations and the cryptographic primitives they rely on, built with contributors from zkSecurity, Trail of Bits, Partisia, and Zama. If you build, audit, or deploy threshold signatures, distributed key generation, or other MPC protocols, it's a starting point for the mistakes you don't want to repeat.

ZK/SEC · May 25, 2026