Skip to content

Commit 0046469

Browse files
committed
Regenerate SP sources: constant-time sp_*_from_mp
Regenerated the single-precision C sources so that sp_<N>_from_mp() converts secret inputs (ECDH/ECDSA private keys and nonces) in constant time: a fixed-count loop bounded by the output size with masked reads at/after a->used, instead of looping a->used times (which leaked the value's magnitude through the executed-instruction count). Fixes the ct-callgrind constant-time failures for P-521 (ec_p521_kex, ec_p521_sign) and hardens the same pattern across all curves and key sizes (108 sp_*_from_mp functions in sp_c32/sp_c64, sp_arm32/sp_arm64/sp_armthumb/ sp_cortexm and sp_x86_64). Verified (--enable-sp, gcc 15.2): ec_p521_kex diff 156 -> 0, ec_p521_sign diff 367 -> 55 (tol 300); testwolfcrypt RSA/ECC KATs pass. Generated by wolfSSL/scripts#626
1 parent e87f7e8 commit 0046469

7 files changed

Lines changed: 1350 additions & 378 deletions

File tree

wolfcrypt/src/sp_arm32.c

Lines changed: 175 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -206,27 +206,45 @@ static void sp_2048_from_mp(sp_digit* r, int size, const mp_int* a)
206206
#elif DIGIT_BIT > 32
207207
unsigned int i;
208208
int j = 0;
209+
int o;
210+
int last = (int)a->used - 1;
209211
word32 s = 0;
210-
212+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
213+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
214+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
215+
mp_digit d;
216+
mp_digit mask;
217+
218+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
219+
last &= 0 - (a->used > 0);
211220
r[0] = 0;
212-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
213-
r[j] |= ((sp_uint32)a->dp[i] << s);
221+
/* Loop a fixed number of times (bounded by the output size, not by
222+
* a->used). Clamp the read index to a valid digit and mask digits at or
223+
* after a->used to zero, so a secret value is converted in constant time
224+
* without reading past the mp_int digit array. */
225+
for (i = 0; j < size; i++) {
226+
/* mask = all ones while i < a->used, else zero (branchless). */
227+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
228+
(sizeof(mp_digit) * 8 - 1));
229+
/* o = i while i < a->used, else the last valid index (in bounds). */
230+
o = (int)(((unsigned int)i & (unsigned int)mask) |
231+
((unsigned int)last & ~(unsigned int)mask));
232+
d = a->dp[o] & mask;
233+
r[j] |= (sp_digit)(d << s);
214234
r[j] &= 0xffffffff;
215235
s = 32U - s;
216236
if (j + 1 >= size) {
217237
break;
218238
}
219-
/* lint allow cast of mismatch word32 and mp_digit */
220-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
239+
r[++j] = (sp_digit)(d >> s);
221240
while ((s + 32U) <= (word32)DIGIT_BIT) {
222241
s += 32U;
223242
r[j] &= 0xffffffff;
224243
if (j + 1 >= size) {
225244
break;
226245
}
227246
if (s < (word32)DIGIT_BIT) {
228-
/* lint allow cast of mismatch word32 and mp_digit */
229-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
247+
r[++j] = (sp_digit)(d >> s);
230248
}
231249
else {
232250
r[++j] = (sp_digit)0;
@@ -18967,27 +18985,45 @@ static void sp_3072_from_mp(sp_digit* r, int size, const mp_int* a)
1896718985
#elif DIGIT_BIT > 32
1896818986
unsigned int i;
1896918987
int j = 0;
18988+
int o;
18989+
int last = (int)a->used - 1;
1897018990
word32 s = 0;
18971-
18991+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
18992+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
18993+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
18994+
mp_digit d;
18995+
mp_digit mask;
18996+
18997+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
18998+
last &= 0 - (a->used > 0);
1897218999
r[0] = 0;
18973-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
18974-
r[j] |= ((sp_uint32)a->dp[i] << s);
19000+
/* Loop a fixed number of times (bounded by the output size, not by
19001+
* a->used). Clamp the read index to a valid digit and mask digits at or
19002+
* after a->used to zero, so a secret value is converted in constant time
19003+
* without reading past the mp_int digit array. */
19004+
for (i = 0; j < size; i++) {
19005+
/* mask = all ones while i < a->used, else zero (branchless). */
19006+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
19007+
(sizeof(mp_digit) * 8 - 1));
19008+
/* o = i while i < a->used, else the last valid index (in bounds). */
19009+
o = (int)(((unsigned int)i & (unsigned int)mask) |
19010+
((unsigned int)last & ~(unsigned int)mask));
19011+
d = a->dp[o] & mask;
19012+
r[j] |= (sp_digit)(d << s);
1897519013
r[j] &= 0xffffffff;
1897619014
s = 32U - s;
1897719015
if (j + 1 >= size) {
1897819016
break;
1897919017
}
18980-
/* lint allow cast of mismatch word32 and mp_digit */
18981-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
19018+
r[++j] = (sp_digit)(d >> s);
1898219019
while ((s + 32U) <= (word32)DIGIT_BIT) {
1898319020
s += 32U;
1898419021
r[j] &= 0xffffffff;
1898519022
if (j + 1 >= size) {
1898619023
break;
1898719024
}
1898819025
if (s < (word32)DIGIT_BIT) {
18989-
/* lint allow cast of mismatch word32 and mp_digit */
18990-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
19026+
r[++j] = (sp_digit)(d >> s);
1899119027
}
1899219028
else {
1899319029
r[++j] = (sp_digit)0;
@@ -46995,27 +47031,45 @@ static void sp_4096_from_mp(sp_digit* r, int size, const mp_int* a)
4699547031
#elif DIGIT_BIT > 32
4699647032
unsigned int i;
4699747033
int j = 0;
47034+
int o;
47035+
int last = (int)a->used - 1;
4699847036
word32 s = 0;
46999-
47037+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
47038+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
47039+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
47040+
mp_digit d;
47041+
mp_digit mask;
47042+
47043+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
47044+
last &= 0 - (a->used > 0);
4700047045
r[0] = 0;
47001-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
47002-
r[j] |= ((sp_uint32)a->dp[i] << s);
47046+
/* Loop a fixed number of times (bounded by the output size, not by
47047+
* a->used). Clamp the read index to a valid digit and mask digits at or
47048+
* after a->used to zero, so a secret value is converted in constant time
47049+
* without reading past the mp_int digit array. */
47050+
for (i = 0; j < size; i++) {
47051+
/* mask = all ones while i < a->used, else zero (branchless). */
47052+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
47053+
(sizeof(mp_digit) * 8 - 1));
47054+
/* o = i while i < a->used, else the last valid index (in bounds). */
47055+
o = (int)(((unsigned int)i & (unsigned int)mask) |
47056+
((unsigned int)last & ~(unsigned int)mask));
47057+
d = a->dp[o] & mask;
47058+
r[j] |= (sp_digit)(d << s);
4700347059
r[j] &= 0xffffffff;
4700447060
s = 32U - s;
4700547061
if (j + 1 >= size) {
4700647062
break;
4700747063
}
47008-
/* lint allow cast of mismatch word32 and mp_digit */
47009-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
47064+
r[++j] = (sp_digit)(d >> s);
4701047065
while ((s + 32U) <= (word32)DIGIT_BIT) {
4701147066
s += 32U;
4701247067
r[j] &= 0xffffffff;
4701347068
if (j + 1 >= size) {
4701447069
break;
4701547070
}
4701647071
if (s < (word32)DIGIT_BIT) {
47017-
/* lint allow cast of mismatch word32 and mp_digit */
47018-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
47072+
r[++j] = (sp_digit)(d >> s);
4701947073
}
4702047074
else {
4702147075
r[++j] = (sp_digit)0;
@@ -67752,27 +67806,45 @@ static void sp_256_from_mp(sp_digit* r, int size, const mp_int* a)
6775267806
#elif DIGIT_BIT > 32
6775367807
unsigned int i;
6775467808
int j = 0;
67809+
int o;
67810+
int last = (int)a->used - 1;
6775567811
word32 s = 0;
67756-
67812+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
67813+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
67814+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
67815+
mp_digit d;
67816+
mp_digit mask;
67817+
67818+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
67819+
last &= 0 - (a->used > 0);
6775767820
r[0] = 0;
67758-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
67759-
r[j] |= ((sp_uint32)a->dp[i] << s);
67821+
/* Loop a fixed number of times (bounded by the output size, not by
67822+
* a->used). Clamp the read index to a valid digit and mask digits at or
67823+
* after a->used to zero, so a secret value is converted in constant time
67824+
* without reading past the mp_int digit array. */
67825+
for (i = 0; j < size; i++) {
67826+
/* mask = all ones while i < a->used, else zero (branchless). */
67827+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
67828+
(sizeof(mp_digit) * 8 - 1));
67829+
/* o = i while i < a->used, else the last valid index (in bounds). */
67830+
o = (int)(((unsigned int)i & (unsigned int)mask) |
67831+
((unsigned int)last & ~(unsigned int)mask));
67832+
d = a->dp[o] & mask;
67833+
r[j] |= (sp_digit)(d << s);
6776067834
r[j] &= 0xffffffff;
6776167835
s = 32U - s;
6776267836
if (j + 1 >= size) {
6776367837
break;
6776467838
}
67765-
/* lint allow cast of mismatch word32 and mp_digit */
67766-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
67839+
r[++j] = (sp_digit)(d >> s);
6776767840
while ((s + 32U) <= (word32)DIGIT_BIT) {
6776867841
s += 32U;
6776967842
r[j] &= 0xffffffff;
6777067843
if (j + 1 >= size) {
6777167844
break;
6777267845
}
6777367846
if (s < (word32)DIGIT_BIT) {
67774-
/* lint allow cast of mismatch word32 and mp_digit */
67775-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
67847+
r[++j] = (sp_digit)(d >> s);
6777667848
}
6777767849
else {
6777867850
r[++j] = (sp_digit)0;
@@ -90882,27 +90954,45 @@ static void sp_384_from_mp(sp_digit* r, int size, const mp_int* a)
9088290954
#elif DIGIT_BIT > 32
9088390955
unsigned int i;
9088490956
int j = 0;
90957+
int o;
90958+
int last = (int)a->used - 1;
9088590959
word32 s = 0;
90886-
90960+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
90961+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
90962+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
90963+
mp_digit d;
90964+
mp_digit mask;
90965+
90966+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
90967+
last &= 0 - (a->used > 0);
9088790968
r[0] = 0;
90888-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
90889-
r[j] |= ((sp_uint32)a->dp[i] << s);
90969+
/* Loop a fixed number of times (bounded by the output size, not by
90970+
* a->used). Clamp the read index to a valid digit and mask digits at or
90971+
* after a->used to zero, so a secret value is converted in constant time
90972+
* without reading past the mp_int digit array. */
90973+
for (i = 0; j < size; i++) {
90974+
/* mask = all ones while i < a->used, else zero (branchless). */
90975+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
90976+
(sizeof(mp_digit) * 8 - 1));
90977+
/* o = i while i < a->used, else the last valid index (in bounds). */
90978+
o = (int)(((unsigned int)i & (unsigned int)mask) |
90979+
((unsigned int)last & ~(unsigned int)mask));
90980+
d = a->dp[o] & mask;
90981+
r[j] |= (sp_digit)(d << s);
9089090982
r[j] &= 0xffffffff;
9089190983
s = 32U - s;
9089290984
if (j + 1 >= size) {
9089390985
break;
9089490986
}
90895-
/* lint allow cast of mismatch word32 and mp_digit */
90896-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
90987+
r[++j] = (sp_digit)(d >> s);
9089790988
while ((s + 32U) <= (word32)DIGIT_BIT) {
9089890989
s += 32U;
9089990990
r[j] &= 0xffffffff;
9090090991
if (j + 1 >= size) {
9090190992
break;
9090290993
}
9090390994
if (s < (word32)DIGIT_BIT) {
90904-
/* lint allow cast of mismatch word32 and mp_digit */
90905-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
90995+
r[++j] = (sp_digit)(d >> s);
9090690996
}
9090790997
else {
9090890998
r[++j] = (sp_digit)0;
@@ -117735,27 +117825,45 @@ static void sp_521_from_mp(sp_digit* r, int size, const mp_int* a)
117735117825
#elif DIGIT_BIT > 32
117736117826
unsigned int i;
117737117827
int j = 0;
117828+
int o;
117829+
int last = (int)a->used - 1;
117738117830
word32 s = 0;
117739-
117831+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
117832+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
117833+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
117834+
mp_digit d;
117835+
mp_digit mask;
117836+
117837+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
117838+
last &= 0 - (a->used > 0);
117740117839
r[0] = 0;
117741-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
117742-
r[j] |= ((sp_uint32)a->dp[i] << s);
117840+
/* Loop a fixed number of times (bounded by the output size, not by
117841+
* a->used). Clamp the read index to a valid digit and mask digits at or
117842+
* after a->used to zero, so a secret value is converted in constant time
117843+
* without reading past the mp_int digit array. */
117844+
for (i = 0; j < size; i++) {
117845+
/* mask = all ones while i < a->used, else zero (branchless). */
117846+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
117847+
(sizeof(mp_digit) * 8 - 1));
117848+
/* o = i while i < a->used, else the last valid index (in bounds). */
117849+
o = (int)(((unsigned int)i & (unsigned int)mask) |
117850+
((unsigned int)last & ~(unsigned int)mask));
117851+
d = a->dp[o] & mask;
117852+
r[j] |= (sp_digit)(d << s);
117743117853
r[j] &= 0xffffffff;
117744117854
s = 32U - s;
117745117855
if (j + 1 >= size) {
117746117856
break;
117747117857
}
117748-
/* lint allow cast of mismatch word32 and mp_digit */
117749-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
117858+
r[++j] = (sp_digit)(d >> s);
117750117859
while ((s + 32U) <= (word32)DIGIT_BIT) {
117751117860
s += 32U;
117752117861
r[j] &= 0xffffffff;
117753117862
if (j + 1 >= size) {
117754117863
break;
117755117864
}
117756117865
if (s < (word32)DIGIT_BIT) {
117757-
/* lint allow cast of mismatch word32 and mp_digit */
117758-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
117866+
r[++j] = (sp_digit)(d >> s);
117759117867
}
117760117868
else {
117761117869
r[++j] = (sp_digit)0;
@@ -147538,27 +147646,45 @@ static void sp_1024_from_mp(sp_digit* r, int size, const mp_int* a)
147538147646
#elif DIGIT_BIT > 32
147539147647
unsigned int i;
147540147648
int j = 0;
147649+
int o;
147650+
int last = (int)a->used - 1;
147541147651
word32 s = 0;
147542-
147652+
/* Digit holder and mask are full mp_digit width (the type of a->dp[]) so
147653+
* the wide-digit split shifts below are not truncated when DIGIT_BIT is
147654+
* wider than the sp word (e.g. sp_c32.c over a 64-bit mp_digit). */
147655+
mp_digit d;
147656+
mp_digit mask;
147657+
147658+
/* Last valid digit index; 0 when a->used == 0 (as in the == branch). */
147659+
last &= 0 - (a->used > 0);
147543147660
r[0] = 0;
147544-
for (i = 0; i < (unsigned int)a->used && j < size; i++) {
147545-
r[j] |= ((sp_uint32)a->dp[i] << s);
147661+
/* Loop a fixed number of times (bounded by the output size, not by
147662+
* a->used). Clamp the read index to a valid digit and mask digits at or
147663+
* after a->used to zero, so a secret value is converted in constant time
147664+
* without reading past the mp_int digit array. */
147665+
for (i = 0; j < size; i++) {
147666+
/* mask = all ones while i < a->used, else zero (branchless). */
147667+
mask = (mp_digit)0 - (((mp_digit)i - (mp_digit)(unsigned int)a->used) >>
147668+
(sizeof(mp_digit) * 8 - 1));
147669+
/* o = i while i < a->used, else the last valid index (in bounds). */
147670+
o = (int)(((unsigned int)i & (unsigned int)mask) |
147671+
((unsigned int)last & ~(unsigned int)mask));
147672+
d = a->dp[o] & mask;
147673+
r[j] |= (sp_digit)(d << s);
147546147674
r[j] &= 0xffffffff;
147547147675
s = 32U - s;
147548147676
if (j + 1 >= size) {
147549147677
break;
147550147678
}
147551-
/* lint allow cast of mismatch word32 and mp_digit */
147552-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
147679+
r[++j] = (sp_digit)(d >> s);
147553147680
while ((s + 32U) <= (word32)DIGIT_BIT) {
147554147681
s += 32U;
147555147682
r[j] &= 0xffffffff;
147556147683
if (j + 1 >= size) {
147557147684
break;
147558147685
}
147559147686
if (s < (word32)DIGIT_BIT) {
147560-
/* lint allow cast of mismatch word32 and mp_digit */
147561-
r[++j] = (sp_digit)(a->dp[i] >> s); /*lint !e9033*/
147687+
r[++j] = (sp_digit)(d >> s);
147562147688
}
147563147689
else {
147564147690
r[++j] = (sp_digit)0;

0 commit comments

Comments
 (0)