Skip to content

Commit 1e0e885

Browse files
committed
Make field/scalar code use the new modinv modules for inverses
1 parent 436281a commit 1e0e885

File tree

5 files changed

+268
-548
lines changed

5 files changed

+268
-548
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ Implementation details
3434
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
3535
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
3636
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
37-
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
3837
* Scalar operations
3938
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
4039
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
4140
* Using 8 32-bit limbs.
41+
* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman).
4242
* Group operations
4343
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
4444
* Use addition between points in Jacobian and affine coordinates where possible.

src/field_10x26_impl.h

Lines changed: 74 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "util.h"
1111
#include "field.h"
12+
#include "modinv32_impl.h"
1213

1314
#ifdef VERIFY
1415
static void secp256k1_fe_verify(const secp256k1_fe *a) {
@@ -1164,131 +1165,92 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
11641165
#endif
11651166
}
11661167

1167-
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
1168-
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
1169-
int j;
1168+
static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) {
1169+
const uint32_t M26 = UINT32_MAX >> 6;
1170+
const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4],
1171+
a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8];
11701172

1171-
/** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
1172-
* { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
1173-
* [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
1173+
/* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and
1174+
* have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8).
11741175
*/
1176+
VERIFY_CHECK(a0 >> 30 == 0);
1177+
VERIFY_CHECK(a1 >> 30 == 0);
1178+
VERIFY_CHECK(a2 >> 30 == 0);
1179+
VERIFY_CHECK(a3 >> 30 == 0);
1180+
VERIFY_CHECK(a4 >> 30 == 0);
1181+
VERIFY_CHECK(a5 >> 30 == 0);
1182+
VERIFY_CHECK(a6 >> 30 == 0);
1183+
VERIFY_CHECK(a7 >> 30 == 0);
1184+
VERIFY_CHECK(a8 >> 16 == 0);
1185+
1186+
r->n[0] = a0 & M26;
1187+
r->n[1] = (a0 >> 26 | a1 << 4) & M26;
1188+
r->n[2] = (a1 >> 22 | a2 << 8) & M26;
1189+
r->n[3] = (a2 >> 18 | a3 << 12) & M26;
1190+
r->n[4] = (a3 >> 14 | a4 << 16) & M26;
1191+
r->n[5] = (a4 >> 10 | a5 << 20) & M26;
1192+
r->n[6] = (a5 >> 6 | a6 << 24) & M26;
1193+
r->n[7] = (a6 >> 2 ) & M26;
1194+
r->n[8] = (a6 >> 28 | a7 << 2) & M26;
1195+
r->n[9] = (a7 >> 24 | a8 << 6);
11751196

1176-
secp256k1_fe_sqr(&x2, a);
1177-
secp256k1_fe_mul(&x2, &x2, a);
1178-
1179-
secp256k1_fe_sqr(&x3, &x2);
1180-
secp256k1_fe_mul(&x3, &x3, a);
1181-
1182-
x6 = x3;
1183-
for (j=0; j<3; j++) {
1184-
secp256k1_fe_sqr(&x6, &x6);
1185-
}
1186-
secp256k1_fe_mul(&x6, &x6, &x3);
1187-
1188-
x9 = x6;
1189-
for (j=0; j<3; j++) {
1190-
secp256k1_fe_sqr(&x9, &x9);
1191-
}
1192-
secp256k1_fe_mul(&x9, &x9, &x3);
1197+
#ifdef VERIFY
1198+
r->magnitude = 1;
1199+
r->normalized = 1;
1200+
secp256k1_fe_verify(r);
1201+
#endif
1202+
}
11931203

1194-
x11 = x9;
1195-
for (j=0; j<2; j++) {
1196-
secp256k1_fe_sqr(&x11, &x11);
1197-
}
1198-
secp256k1_fe_mul(&x11, &x11, &x2);
1204+
static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) {
1205+
const uint32_t M30 = UINT32_MAX >> 2;
1206+
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4],
1207+
a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9];
11991208

1200-
x22 = x11;
1201-
for (j=0; j<11; j++) {
1202-
secp256k1_fe_sqr(&x22, &x22);
1203-
}
1204-
secp256k1_fe_mul(&x22, &x22, &x11);
1209+
#ifdef VERIFY
1210+
VERIFY_CHECK(a->normalized);
1211+
#endif
12051212

1206-
x44 = x22;
1207-
for (j=0; j<22; j++) {
1208-
secp256k1_fe_sqr(&x44, &x44);
1209-
}
1210-
secp256k1_fe_mul(&x44, &x44, &x22);
1213+
r->v[0] = (a0 | a1 << 26) & M30;
1214+
r->v[1] = (a1 >> 4 | a2 << 22) & M30;
1215+
r->v[2] = (a2 >> 8 | a3 << 18) & M30;
1216+
r->v[3] = (a3 >> 12 | a4 << 14) & M30;
1217+
r->v[4] = (a4 >> 16 | a5 << 10) & M30;
1218+
r->v[5] = (a5 >> 20 | a6 << 6) & M30;
1219+
r->v[6] = (a6 >> 24 | a7 << 2
1220+
| a8 << 28) & M30;
1221+
r->v[7] = (a8 >> 2 | a9 << 24) & M30;
1222+
r->v[8] = a9 >> 6;
1223+
}
12111224

1212-
x88 = x44;
1213-
for (j=0; j<44; j++) {
1214-
secp256k1_fe_sqr(&x88, &x88);
1215-
}
1216-
secp256k1_fe_mul(&x88, &x88, &x44);
1225+
static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = {
1226+
{{-0x3D1, -4, 0, 0, 0, 0, 0, 0, 65536}},
1227+
0x2DDACACFL
1228+
};
12171229

1218-
x176 = x88;
1219-
for (j=0; j<88; j++) {
1220-
secp256k1_fe_sqr(&x176, &x176);
1221-
}
1222-
secp256k1_fe_mul(&x176, &x176, &x88);
1230+
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
1231+
secp256k1_fe tmp;
1232+
secp256k1_modinv32_signed30 s;
12231233

1224-
x220 = x176;
1225-
for (j=0; j<44; j++) {
1226-
secp256k1_fe_sqr(&x220, &x220);
1227-
}
1228-
secp256k1_fe_mul(&x220, &x220, &x44);
1234+
tmp = *x;
1235+
secp256k1_fe_normalize(&tmp);
1236+
secp256k1_fe_to_signed30(&s, &tmp);
1237+
secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe);
1238+
secp256k1_fe_from_signed30(r, &s);
12291239

1230-
x223 = x220;
1231-
for (j=0; j<3; j++) {
1232-
secp256k1_fe_sqr(&x223, &x223);
1233-
}
1234-
secp256k1_fe_mul(&x223, &x223, &x3);
1240+
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
1241+
}
12351242

1236-
/* The final result is then assembled using a sliding window over the blocks. */
1243+
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
1244+
secp256k1_fe tmp;
1245+
secp256k1_modinv32_signed30 s;
12371246

1238-
t1 = x223;
1239-
for (j=0; j<23; j++) {
1240-
secp256k1_fe_sqr(&t1, &t1);
1241-
}
1242-
secp256k1_fe_mul(&t1, &t1, &x22);
1243-
for (j=0; j<5; j++) {
1244-
secp256k1_fe_sqr(&t1, &t1);
1245-
}
1246-
secp256k1_fe_mul(&t1, &t1, a);
1247-
for (j=0; j<3; j++) {
1248-
secp256k1_fe_sqr(&t1, &t1);
1249-
}
1250-
secp256k1_fe_mul(&t1, &t1, &x2);
1251-
for (j=0; j<2; j++) {
1252-
secp256k1_fe_sqr(&t1, &t1);
1253-
}
1254-
secp256k1_fe_mul(r, a, &t1);
1255-
}
1247+
tmp = *x;
1248+
secp256k1_fe_normalize_var(&tmp);
1249+
secp256k1_fe_to_signed30(&s, &tmp);
1250+
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe);
1251+
secp256k1_fe_from_signed30(r, &s);
12561252

1257-
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {
1258-
#if defined(USE_FIELD_INV_BUILTIN)
1259-
secp256k1_fe_inv(r, a);
1260-
#elif defined(USE_FIELD_INV_NUM)
1261-
secp256k1_num n, m;
1262-
static const secp256k1_fe negone = SECP256K1_FE_CONST(
1263-
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
1264-
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL
1265-
);
1266-
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
1267-
static const unsigned char prime[32] = {
1268-
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1269-
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1270-
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1271-
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
1272-
};
1273-
unsigned char b[32];
1274-
int res;
1275-
secp256k1_fe c = *a;
1276-
secp256k1_fe_normalize_var(&c);
1277-
secp256k1_fe_get_b32(b, &c);
1278-
secp256k1_num_set_bin(&n, b, 32);
1279-
secp256k1_num_set_bin(&m, prime, 32);
1280-
secp256k1_num_mod_inverse(&n, &n, &m);
1281-
secp256k1_num_get_bin(b, 32, &n);
1282-
res = secp256k1_fe_set_b32(r, b);
1283-
(void)res;
1284-
VERIFY_CHECK(res);
1285-
/* Verify the result is the (unique) valid inverse using non-GMP code. */
1286-
secp256k1_fe_mul(&c, &c, r);
1287-
secp256k1_fe_add(&c, &negone);
1288-
CHECK(secp256k1_fe_normalizes_to_zero_var(&c));
1289-
#else
1290-
#error "Please select field inverse implementation"
1291-
#endif
1253+
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
12921254
}
12931255

12941256
#endif /* SECP256K1_FIELD_REPR_IMPL_H */

0 commit comments

Comments
 (0)