Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1# The safegcd implementation in libsecp256k1 explained3This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.4It is based on the paper5["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)6by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.8The actual implementation is in C of course, but for demonstration purposes Python3 is used here.9Most implementation aspects and optimizations are explained, except those that depend on the specific10number representation used in the C code.12## 1. Computing the Greatest Common Divisor (GCD) using divsteps14The algorithm from the paper (section 11), at a very high level, is this:16```python17def gcd(f, g):18"""Compute the GCD of an odd integer f and another integer g."""19assert f & 1 # require f to be odd20delta = 1 # additional state variable21while g != 0:22assert f & 1 # f will be odd in every iteration23if delta > 0 and g & 1:24delta, f, g = 1 - delta, g, (g - f) // 225elif g & 1:26delta, f, g = 1 + delta, f, (g + f) // 227else:28delta, f, g = 1 + delta, f, (g ) // 229return abs(f)30```32It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop33keeps rewriting the variables *f* and *g* alongside a state variable *δ* that starts at *1*, until34*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a35"division step" (referred to as divstep in what follows).37For example, *gcd(21, 14)* would be computed as:38- Start with *δ=1 f=21 g=14*39- Take the third branch: *δ=2 f=21 g=7*40- Take the first branch: *δ=-1 f=7 g=-7*41- Take the second branch: *δ=0 f=7 g=0*42- The answer *|f| = 7*.44Why it works:45- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper):46- (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*.47- (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even).48- Neither of those two operations change the GCD:49- For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a c* and *g=b c* for some integers *a*50and *b*. As *(g,g-f)=(b c,(b-a)c)* and *(f,f+g)=(a c,(a+b)c)*, the result clearly still has51common factor *c*. Reasoning in the other direction shows that no common factor can be added by52doing so either.53- For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove54it from *g*.55- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3).56- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the57gcd of *f'* and *0* is *|f'|* by definition, that is our answer.59Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at60the low-order bits of the variables to decide the next steps, and being easy to make61constant-time (in more low-level languages than Python). The *δ* parameter is necessary to62guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look63at high order bits.65Properties that will become important later:66- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*.67- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we68do not need to worry about rounding.69- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N*70bits of *f* and *g*, and on *δ*.73## 2. From GCDs to modular inverses75We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a x=176mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is77prime and *0 < x < M*. In what follows, assume that the modular inverse exists.78It turns out this inverse can be computed as a side effect of computing the GCD by keeping track79of how the internal variables can be written as linear combinations of the inputs at every step80(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)).81Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a x + b M = 1*.82Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x83mod M*.85A similar approach can be used to calculate modular inverses using the divsteps-based GCD86algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping87track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*.88*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M*89and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M90= 1*).92```python93def div2(M, x):94"""Helper routine to compute x/2 mod M (where M is odd)."""95assert M & 196if x & 1: # If x is odd, make it even by adding M.97x += M98# x must be even now, so a clean division by 2 is possible.99return x // 2101def modinv(M, x):102"""Compute the inverse of x mod M (given that it exists, and M is odd)."""103assert M & 1104delta, f, g, d, e = 1, M, x, 0, 1105while g != 0:106# Note that while division by two for f and g is only ever done on even inputs, this is107# not true for d and e, so we need the div2 helper function.108if delta > 0 and g & 1:109delta, f, g, d, e = 1 - delta, g, (g - f) // 2, e, div2(M, e - d)110elif g & 1:111delta, f, g, d, e = 1 + delta, f, (g + f) // 2, d, div2(M, e + d)112else:113delta, f, g, d, e = 1 + delta, f, (g ) // 2, d, div2(M, e )114# Verify that the invariants d=f/x mod M, e=g/x mod M are maintained.115assert f % M == (d * x) % M116assert g % M == (e * x) % M117assert f == 1 or f == -1 # |f| is the GCD, it must be 1118# Because of invariant d = f/x (mod M), 1/x = d/f (mod M). As |f|=1, d/f = d*f.119return (d * f) % M120```122Also note that this approach to track *d* and *e* throughout the computation to determine the inverse123is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the124entire computation is determined (see section 3 below) and the inverse is computed from that.125The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to126be faster at the level of optimization we're able to do in C.129## 3. Batching multiple divsteps131Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)*132to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper):134```135t = [ u, v ]136[ q, r ]138[ out_f ] = (1/2 * t) * [ in_f ]139[ out_g ] = [ in_g ]141[ out_d ] = (1/2 * t) * [ in_d ] (mod M)142[ out_e ] [ in_e ]143```145where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is146taken. As above, the resulting *f* and *g* are always integers.148Performing multiple divsteps corresponds to a multiplication with the product of all the149individual divsteps' transition matrices. As each transition matrix consists of integers150divided by *2*, the product of these matrices will consist of integers divided by *2<sup>N</sup>* (see also151theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay152them: we compute the integer coefficients of the combined transition matrix scaled by *2<sup>N</sup>*, and153do one division by *2<sup>N</sup>* as a final step:155```python156def divsteps_n_matrix(delta, f, g):157"""Compute delta and transition matrix t after N divsteps (multiplied by 2^N)."""158u, v, q, r = 1, 0, 0, 1 # start with identity matrix159for _ in range(N):160if delta > 0 and g & 1:161delta, f, g, u, v, q, r = 1 - delta, g, (g - f) // 2, 2*q, 2*r, q-u, r-v162elif g & 1:163delta, f, g, u, v, q, r = 1 + delta, f, (g + f) // 2, 2*u, 2*v, q+u, r+v164else:165delta, f, g, u, v, q, r = 1 + delta, f, (g ) // 2, 2*u, 2*v, q , r166return delta, (u, v, q, r)167```169As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this170function to compute the transition matrix only needs to see those bottom bits. Furthermore all171intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*,172*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit173integers could set *N=62* and compute the full transition matrix for 62 steps at once without any174big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs175to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps.177We still need functions to compute:179```180[ out_f ] = (1/2^N * [ u, v ]) * [ in_f ]181[ out_g ] ( [ q, r ]) [ in_g ]183[ out_d ] = (1/2^N * [ u, v ]) * [ in_d ] (mod M)184[ out_e ] ( [ q, r ]) [ in_e ]185```187Because the divsteps transformation only ever divides even numbers by two, the result of *t [f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f*188and *g* will be multiple of *2<sup>N</sup>*, and division by *2<sup>N</sup>* is simply shifting them down:190```python191def update_fg(f, g, t):192"""Multiply matrix t/2^N with [f, g]."""193u, v, q, r = t194cf, cg = u*f + v*g, q*f + r*g195# (t / 2^N) should cleanly apply to [f,g] so the result of t*[f,g] should have N zero196# bottom bits.197assert cf % 2**N == 0198assert cg % 2**N == 0199return cf >> N, cg >> N200```202The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2<sup>N</sup> mod M*.203This is easy if we have precomputed *1/M mod 2<sup>N</sup>* (which always exists for odd *M*):205```python206def div2n(M, Mi, x):207"""Compute x/2^N mod M, given Mi = 1/M mod 2^N."""208assert (M * Mi) % 2**N == 1209# Find a factor m such that m*M has the same bottom N bits as x. We want:210# (m * M) mod 2^N = x mod 2^N211# <=> m mod 2^N = (x / M) mod 2^N212# <=> m mod 2^N = (x * Mi) mod 2^N213m = (Mi * x) % 2**N214# Subtract that multiple from x, cancelling its bottom N bits.215x -= m * M216# Now a clean division by 2^N is possible.217assert x % 2**N == 0218return (x >> N) % M220def update_de(d, e, t, M, Mi):221"""Multiply matrix t/2^N with [d, e], modulo M."""222u, v, q, r = t223cd, ce = u*d + v*e, q*d + r*e224return div2n(M, Mi, cd), div2n(M, Mi, ce)225```227With all of those, we can write a version of `modinv` that performs *N* divsteps at once:229```python3230def modinv(M, Mi, x):231"""Compute the modular inverse of x mod M, given Mi=1/M mod 2^N."""232assert M & 1233delta, f, g, d, e = 1, M, x, 0, 1234while g != 0:235# Compute the delta and transition matrix t for the next N divsteps (this only needs236# (N+1)-bit signed integer arithmetic).237delta, t = divsteps_n_matrix(delta, f % 2**N, g % 2**N)238# Apply the transition matrix t to [f, g]:239f, g = update_fg(f, g, t)240# Apply the transition matrix t to [d, e]:241d, e = update_de(d, e, t, M, Mi)242return (d * f) % M243```245This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem246because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *δ* keeps247increasing). For variable time code such excess iterations will be mostly optimized away in later248sections.
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.