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
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 Year of ZK Security

A year after launching, we've grown and evolved alongside the world of zero-knowledge proofs, uncovering bugs and learning the ins and outs of ZK technology. From circuit audits to developing our own tools like Circomscribe, it’s been a wild ride. We've discovered how easy it is to misstep with ZK code, especially as these systems grow complex and impact financial security. As zkVMs gain popularity, we're excited about the challenges ahead and are expanding our expertise. Want to dive into the world of ZK with us? Check out our latest projects and even take on our zkBank challenge!

David Wong · May 30, 2024

Partnership with StarkWare

We're teaming up with StarkWare to enhance Ethereum's scalability using an exciting tool called the EVM adapter. This innovative open-source project takes proofs from the Stone Prover and makes them verifiable on Ethereum, showcasing the power of Cairo bootloader programs for Layer 2 scaling. By diving into our collaboration, you'll get a glimpse of StarkNet's ability to streamline transactions efficiently and how our joint efforts are driving this tech forward. Plus, our Stark Book offers a deeper technical dive for the curious minds!

ZK/SEC · April 05, 2024

Proximity Gaps: What Happened and How Does It Affect our SNARKs

A series of recent papers just disproved the proximity gaps conjecture, which has everyone wondering if hash-based SNARKs are in trouble. We break down what actually happened using some helpful visuals. Think of it as understanding which parameter choices are safe versus which ones are now confirmed to be risky. The post walks you through the different security zones (proven safe, conjectured safe, and definitely not safe), explains how these new results connect to other open math problems, and shows what it means for real-world SNARKs in terms of proof sizes and performance trade-offs.

Nicolas Mohnblatt · November 14, 2025