|
1 | 1 | # The safegcd implementation in libsecp256k1 explained
|
2 | 2 |
|
3 |
| -This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based |
4 |
| -on the paper |
| 3 | +This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files. |
| 4 | +It is based on the paper |
5 | 5 | ["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
|
6 | 6 | by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
|
7 | 7 |
|
@@ -769,3 +769,51 @@ def modinv_var(M, Mi, x):
|
769 | 769 | d, e = update_de(d, e, t, M, Mi)
|
770 | 770 | return normalize(f, d, Mi)
|
771 | 771 | ```
|
| 772 | + |
| 773 | +## 8. From GCDs to Jacobi symbol |
| 774 | + |
| 775 | +We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an |
| 776 | +extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we |
| 777 | +make corresponding updates to *j* using |
| 778 | +[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties): |
| 779 | +* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*). |
| 780 | +* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*). |
| 781 | + |
| 782 | +These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied |
| 783 | +very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this |
| 784 | +calculation is slightly simpler than the one for the modular inverse because we no longer need to |
| 785 | +keep track of *d* and *e*. |
| 786 | + |
| 787 | +However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for |
| 788 | +positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative |
| 789 | +values. We resolve this by using the following modified steps: |
| 790 | + |
| 791 | +```python |
| 792 | + # Before |
| 793 | + if delta > 0 and g & 1: |
| 794 | + delta, f, g = 1 - delta, g, (g - f) // 2 |
| 795 | + |
| 796 | + # After |
| 797 | + if delta > 0 and g & 1: |
| 798 | + delta, f, g = 1 - delta, g, (g + f) // 2 |
| 799 | +``` |
| 800 | + |
| 801 | +The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 |
| 802 | +and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm |
| 803 | +will converge. The justification for posdivsteps is completely empirical: in practice, it appears |
| 804 | +that the vast majority of nonzero inputs converge to *f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)* in a |
| 805 | +number of steps proportional to their logarithm. |
| 806 | + |
| 807 | +Note that: |
| 808 | +- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached. |
| 809 | +- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect. |
| 810 | +- We need to update the termination condition from *g=0* to *f=1*. |
| 811 | + |
| 812 | +We account for the possibility of nonconvergence by only performing a bounded number of |
| 813 | +posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not |
| 814 | +yet been found. |
| 815 | + |
| 816 | +The optimizations in sections 3-7 above are described in the context of the original divsteps, but |
| 817 | +in the C implementation we also adapt most of them (not including "avoiding modulus operations", |
| 818 | +since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate |
| 819 | +Jacobi symbols for secret data) to the posdivsteps version. |
0 commit comments