Compare commits
69 commits
master
...
feature/os
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95b4936aa1 | ||
|
|
7a88869224 | ||
|
|
74084eb28e | ||
|
|
10a5bb87dc | ||
|
|
18a19d81b9 | ||
|
|
ab42643c66 | ||
|
|
82b214d9bc | ||
|
|
1588f1f3eb | ||
|
|
d0e86cb69e | ||
|
|
9cc605f48e | ||
|
|
97618c446f | ||
|
|
60551b673b | ||
|
|
ed9ea9710d | ||
|
|
10d074a041 | ||
|
|
c6866fa3d3 | ||
|
|
7593990ddf | ||
|
|
b5aa70d2c1 | ||
|
|
12929d3852 | ||
|
|
496092d36f | ||
|
|
9ff9bf1c0a | ||
|
|
3923fd51b1 | ||
|
|
5c2f95c4b0 | ||
|
|
0df3c5e1de | ||
|
|
312250036e | ||
|
|
9a90994e39 | ||
|
|
ebc87a83dc | ||
|
|
d8f17e7d37 | ||
|
|
3b2c8afdc1 | ||
|
|
910c2fcfc0 | ||
|
|
e3a6ede280 | ||
|
|
d07d760f8c | ||
|
|
0b478aba2c | ||
|
|
04566a1781 | ||
|
|
ac0e2da45e | ||
|
|
0e8b647fdb | ||
|
|
5678648723 | ||
|
|
3a5594d70e | ||
|
|
e77ef33428 | ||
|
|
277448082d | ||
|
|
96609d570a | ||
|
|
76f93f270e | ||
|
|
f03efd47b7 | ||
|
|
54f13a2ef7 | ||
|
|
f53cc8e213 | ||
|
|
17c4d15971 | ||
|
|
7d5084df86 | ||
|
|
f52bf9d167 | ||
|
|
929db7822d | ||
|
|
7e7280f1b2 | ||
|
|
ded391d6ce | ||
|
|
ab79f54114 | ||
|
|
8f77f825fa | ||
|
|
5ea9b46e95 | ||
|
|
12e7939872 | ||
|
|
2532cdf821 | ||
|
|
74ebdc1535 | ||
|
|
504fb345af | ||
|
|
cf738674e1 | ||
|
|
e148c8a233 | ||
|
|
e3ae863a2d | ||
|
|
1bde024e9b | ||
|
|
23fdb656c3 | ||
|
|
96dc6a9ac8 | ||
|
|
133420b172 | ||
|
|
2ccd86a0b1 | ||
|
|
2a691a034e | ||
|
|
584e7138af | ||
|
|
a5b9c8d60f | ||
|
|
8e4c928280 |
67 changed files with 79786 additions and 933 deletions
|
|
@ -599,6 +599,8 @@ TypeNames:
|
|||
- "ossl_finish_mutate_cb"
|
||||
- "OSSL_FIPS_IND"
|
||||
- "OSSL_FIPS_IND_CHECK_CB"
|
||||
- "OSSL_FN_CTX"
|
||||
- "OSSL_FN_ULONG"
|
||||
- "OSSL_FUNC"
|
||||
- "OSSL_HANDSHAKE_STATE"
|
||||
- "OSSL_HASH"
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1t.h>
|
||||
#include "crypto/cryptlib.h"
|
||||
|
||||
#define COPY_SIZE(a, b) (sizeof(a) < sizeof(b) ? sizeof(a) : sizeof(b))
|
||||
|
||||
|
|
@ -56,31 +56,6 @@ static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
|
|||
memcpy(pval, &it->size, COPY_SIZE(*pval, it->size));
|
||||
}
|
||||
|
||||
/*
|
||||
* Originally BN_num_bits_word was called to perform this operation, but
|
||||
* trouble is that there is no guarantee that sizeof(long) equals to
|
||||
* sizeof(BN_ULONG). BN_ULONG is a configurable type that can be as wide
|
||||
* as long, but also double or half...
|
||||
*/
|
||||
static int num_bits_ulong(unsigned long value)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long ret = 0;
|
||||
|
||||
/*
|
||||
* It is argued that *on average* constant counter loop performs
|
||||
* not worse [if not better] than one with conditional break or
|
||||
* mask-n-table-lookup-style, because of branch misprediction
|
||||
* penalties.
|
||||
*/
|
||||
for (i = 0; i < sizeof(value) * 8; i++) {
|
||||
ret += (value != 0);
|
||||
value >>= 1;
|
||||
}
|
||||
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
static int long_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
|
||||
const ASN1_ITEM *it)
|
||||
{
|
||||
|
|
@ -103,7 +78,7 @@ static int long_i2c(const ASN1_VALUE **pval, unsigned char *cont, int *putype,
|
|||
sign = 0;
|
||||
utmp = ltmp;
|
||||
}
|
||||
clen = num_bits_ulong(utmp);
|
||||
clen = (int)ossl_num_bits(utmp);
|
||||
/* If MSB of leading octet set we need to pad */
|
||||
if (!(clen & 0x7))
|
||||
pad = 1;
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
|||
#else
|
||||
/* Simics 1.4<7 has buggy sbbq:-( */
|
||||
#define BN_MASK2 0xffffffffffffffffL
|
||||
BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
|
||||
BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)
|
||||
{
|
||||
BN_ULONG t1, t2;
|
||||
int c = 0;
|
||||
|
|
@ -408,7 +408,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
|
|||
#define sqr_add_c2(a, i, j, c0, c1, c2) \
|
||||
mul_add_c2((a)[i], (a)[j], c0, c1, c2)
|
||||
|
||||
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
||||
void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
|
||||
{
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
|
|
@ -511,7 +511,7 @@ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
|||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
||||
void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
|
||||
{
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
|
|||
if (bn_wexpand(r, max + 1) == NULL)
|
||||
return 0;
|
||||
|
||||
r->top = max;
|
||||
bn_set_top(r, max);
|
||||
|
||||
ap = a->d;
|
||||
bp = b->d;
|
||||
|
|
@ -114,7 +114,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
|
|||
carry &= (t2 == 0);
|
||||
}
|
||||
*rp = carry;
|
||||
r->top += (int)carry;
|
||||
bn_set_top(r, r->top + (int)carry);
|
||||
|
||||
r->neg = 0;
|
||||
bn_check_top(r);
|
||||
|
|
@ -162,9 +162,8 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
|
|||
while (max && *--rp == 0)
|
||||
max--;
|
||||
|
||||
r->top = max;
|
||||
bn_set_top(r, max);
|
||||
r->neg = 0;
|
||||
bn_pollute(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -622,7 +622,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
|||
mul_add_c2((a)[i], (a)[j], c0, c1, c2)
|
||||
#endif /* !BN_LLONG */
|
||||
|
||||
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
||||
void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
|
||||
{
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
|
|
@ -725,7 +725,7 @@ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
|||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
||||
void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
|
||||
{
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
|
|
@ -1006,7 +1006,7 @@ void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a)
|
|||
bn_sqr_normal(r, a, 8, t);
|
||||
}
|
||||
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
||||
void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
|
||||
{
|
||||
r[4] = bn_mul_words(&(r[0]), a, 4, b[0]);
|
||||
r[5] = bn_mul_add_words(&(r[1]), a, 4, b[1]);
|
||||
|
|
@ -1014,7 +1014,7 @@ void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
|||
r[7] = bn_mul_add_words(&(r[3]), a, 4, b[3]);
|
||||
}
|
||||
|
||||
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
|
||||
void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b)
|
||||
{
|
||||
r[8] = bn_mul_words(&(r[0]), a, 8, b[0]);
|
||||
r[9] = bn_mul_add_words(&(r[1]), a, 8, b[1]);
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
|
|||
}
|
||||
mask = (BN_ULONG)0 - ((rtop - ntop) >> (8 * sizeof(ntop) - 1));
|
||||
/* always true, if (rtop >= ntop) n->top = r->top; */
|
||||
n->top = (int)((rtop & ~mask) | (ntop & mask));
|
||||
bn_set_top(n, (int)((rtop & ~mask) | (ntop & mask)));
|
||||
n->flags |= (BN_FLG_FIXED_TOP & ~mask);
|
||||
}
|
||||
ret = bn_mul_mont_fixed_top(n, n, r, b->m_ctx, ctx);
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ int BN_hex2bn(BIGNUM **bn, const char *a)
|
|||
}
|
||||
j -= BN_BYTES * 2;
|
||||
}
|
||||
ret->top = h;
|
||||
bn_set_top(ret, h);
|
||||
bn_correct_top(ret);
|
||||
|
||||
*bn = ret;
|
||||
|
|
|
|||
|
|
@ -1374,50 +1374,53 @@ static const BN_ULONG ffdhe8192_q[] = {
|
|||
#define make_dh_bn(x) \
|
||||
extern const BIGNUM ossl_bignum_##x; \
|
||||
const BIGNUM ossl_bignum_##x = { \
|
||||
(BN_ULONG *)x, \
|
||||
OSSL_NELEM(x), \
|
||||
OSSL_NELEM(x), \
|
||||
0, BN_FLG_STATIC_DATA \
|
||||
};
|
||||
.d = (BN_ULONG *)x, \
|
||||
.top = OSSL_NELEM(x), \
|
||||
.dmax = OSSL_NELEM(x), \
|
||||
.flags = BN_FLG_STATIC_DATA, \
|
||||
}
|
||||
|
||||
static const BN_ULONG value_2 = 2;
|
||||
|
||||
const BIGNUM ossl_bignum_const_2 = {
|
||||
(BN_ULONG *)&value_2, 1, 1, 0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)&value_2,
|
||||
.top = 1,
|
||||
.dmax = 1,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
make_dh_bn(dh1024_160_p)
|
||||
make_dh_bn(dh1024_160_q)
|
||||
make_dh_bn(dh1024_160_g)
|
||||
make_dh_bn(dh2048_224_p)
|
||||
make_dh_bn(dh2048_224_q)
|
||||
make_dh_bn(dh2048_224_g)
|
||||
make_dh_bn(dh2048_256_p)
|
||||
make_dh_bn(dh2048_256_q)
|
||||
make_dh_bn(dh2048_256_g)
|
||||
make_dh_bn(dh1024_160_p);
|
||||
make_dh_bn(dh1024_160_q);
|
||||
make_dh_bn(dh1024_160_g);
|
||||
make_dh_bn(dh2048_224_p);
|
||||
make_dh_bn(dh2048_224_q);
|
||||
make_dh_bn(dh2048_224_g);
|
||||
make_dh_bn(dh2048_256_p);
|
||||
make_dh_bn(dh2048_256_q);
|
||||
make_dh_bn(dh2048_256_g);
|
||||
|
||||
make_dh_bn(ffdhe2048_p)
|
||||
make_dh_bn(ffdhe2048_q)
|
||||
make_dh_bn(ffdhe3072_p)
|
||||
make_dh_bn(ffdhe3072_q)
|
||||
make_dh_bn(ffdhe4096_p)
|
||||
make_dh_bn(ffdhe4096_q)
|
||||
make_dh_bn(ffdhe6144_p)
|
||||
make_dh_bn(ffdhe6144_q)
|
||||
make_dh_bn(ffdhe8192_p)
|
||||
make_dh_bn(ffdhe8192_q)
|
||||
make_dh_bn(ffdhe2048_p);
|
||||
make_dh_bn(ffdhe2048_q);
|
||||
make_dh_bn(ffdhe3072_p);
|
||||
make_dh_bn(ffdhe3072_q);
|
||||
make_dh_bn(ffdhe4096_p);
|
||||
make_dh_bn(ffdhe4096_q);
|
||||
make_dh_bn(ffdhe6144_p);
|
||||
make_dh_bn(ffdhe6144_q);
|
||||
make_dh_bn(ffdhe8192_p);
|
||||
make_dh_bn(ffdhe8192_q);
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
make_dh_bn(modp_1536_p)
|
||||
make_dh_bn(modp_1536_q)
|
||||
make_dh_bn(modp_1536_p);
|
||||
make_dh_bn(modp_1536_q);
|
||||
#endif
|
||||
make_dh_bn(modp_2048_p)
|
||||
make_dh_bn(modp_2048_q)
|
||||
make_dh_bn(modp_3072_p)
|
||||
make_dh_bn(modp_3072_q)
|
||||
make_dh_bn(modp_4096_p)
|
||||
make_dh_bn(modp_4096_q)
|
||||
make_dh_bn(modp_6144_p)
|
||||
make_dh_bn(modp_6144_q)
|
||||
make_dh_bn(modp_8192_p)
|
||||
make_dh_bn(modp_8192_q)
|
||||
make_dh_bn(modp_2048_p);
|
||||
make_dh_bn(modp_2048_q);
|
||||
make_dh_bn(modp_3072_p);
|
||||
make_dh_bn(modp_3072_q);
|
||||
make_dh_bn(modp_4096_p);
|
||||
make_dh_bn(modp_4096_q);
|
||||
make_dh_bn(modp_6144_p);
|
||||
make_dh_bn(modp_6144_q);
|
||||
make_dh_bn(modp_8192_p);
|
||||
make_dh_bn(modp_8192_q);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
|
|||
BN_zero(dv);
|
||||
if (bn_wexpand(dv, 1) == NULL)
|
||||
goto end;
|
||||
dv->top = 1;
|
||||
bn_set_top(dv, 1);
|
||||
|
||||
if (!BN_lshift(D, D, nm - nd))
|
||||
goto end;
|
||||
|
|
@ -310,7 +310,9 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num,
|
|||
if (bn_wexpand(snum, div_n + 1) == NULL)
|
||||
goto err;
|
||||
memset(&(snum->d[num_n]), 0, (div_n - num_n + 1) * sizeof(BN_ULONG));
|
||||
snum->top = num_n = div_n + 1;
|
||||
num_n = div_n + 1;
|
||||
bn_set_top(snum, num_n);
|
||||
snum->flags |= BN_FLG_FIXED_TOP;
|
||||
}
|
||||
|
||||
loop = num_n - div_n;
|
||||
|
|
@ -330,13 +332,15 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num,
|
|||
goto err;
|
||||
num_neg = num->neg;
|
||||
res->neg = (num_neg ^ divisor->neg);
|
||||
res->top = loop;
|
||||
bn_set_top(res, loop);
|
||||
res->flags |= BN_FLG_FIXED_TOP;
|
||||
resp = &(res->d[loop]);
|
||||
|
||||
/* space for temp */
|
||||
if (!bn_wexpand(tmp, (div_n + 1)))
|
||||
goto err;
|
||||
tmp->top = div_n + 1;
|
||||
tmp->flags |= BN_FLG_FIXED_TOP;
|
||||
|
||||
for (i = 0; i < loop; i++, wnumtop--) {
|
||||
BN_ULONG q, l0;
|
||||
|
|
@ -446,7 +450,7 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num,
|
|||
}
|
||||
/* snum holds remainder, it's as wide as divisor */
|
||||
snum->neg = num_neg;
|
||||
snum->top = div_n;
|
||||
bn_set_top(snum, div_n);
|
||||
snum->flags |= BN_FLG_FIXED_TOP;
|
||||
|
||||
if (rm != NULL && bn_rshift_fixed_top(rm, snum, norm_shift) == 0)
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
|||
r->d[0] = (0 - m->d[0]) & BN_MASK2;
|
||||
for (i = 1; i < j; i++)
|
||||
r->d[i] = (~m->d[i]) & BN_MASK2;
|
||||
r->top = j;
|
||||
bn_set_top(r, j);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
} else
|
||||
#endif
|
||||
|
|
@ -468,7 +468,8 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
|||
val[0]->d[0] = 1; /* borrow val[0] */
|
||||
for (i = 1; i < j; i++)
|
||||
val[0]->d[i] = 0;
|
||||
val[0]->top = j;
|
||||
bn_set_top(val[0], j);
|
||||
val[0]->flags |= BN_FLG_FIXED_TOP;
|
||||
if (!BN_mod_mul_montgomery(rr, r, val[0], mont, ctx))
|
||||
goto err;
|
||||
} else
|
||||
|
|
@ -581,7 +582,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top,
|
|||
}
|
||||
}
|
||||
|
||||
b->top = top;
|
||||
bn_set_top(b, top);
|
||||
b->flags |= BN_FLG_FIXED_TOP;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -612,7 +613,7 @@ int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
|||
unsigned char *powerbufFree = NULL;
|
||||
int powerbufLen = 0;
|
||||
unsigned char *powerbuf = NULL;
|
||||
BIGNUM tmp, am;
|
||||
BIGNUM tmp = { .data = NULL }, am = { .data = NULL };
|
||||
#if defined(SPARC_T4_MONT)
|
||||
unsigned int t4 = 0;
|
||||
#endif
|
||||
|
|
@ -681,7 +682,7 @@ int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
|||
goto err;
|
||||
RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d,
|
||||
mont->n0[0]);
|
||||
rr->top = 16;
|
||||
bn_set_top(rr, 16);
|
||||
rr->neg = 0;
|
||||
bn_correct_top(rr);
|
||||
ret = 1;
|
||||
|
|
@ -690,7 +691,7 @@ int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
|||
if (NULL == bn_wexpand(rr, 8))
|
||||
goto err;
|
||||
RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d);
|
||||
rr->top = 8;
|
||||
bn_set_top(rr, 8);
|
||||
rr->neg = 0;
|
||||
bn_correct_top(rr);
|
||||
ret = 1;
|
||||
|
|
@ -1488,12 +1489,12 @@ int BN_mod_exp_mont_consttime_x2(BIGNUM *rr1, const BIGNUM *a1, const BIGNUM *p1
|
|||
mont2->RR.d, mont2->n0[0],
|
||||
mod_bits);
|
||||
|
||||
rr1->top = topn;
|
||||
bn_set_top(rr1, topn);
|
||||
rr1->neg = 0;
|
||||
bn_correct_top(rr1);
|
||||
bn_check_top(rr1);
|
||||
|
||||
rr2->top = topn;
|
||||
bn_set_top(rr2, topn);
|
||||
rr2->neg = 0;
|
||||
bn_correct_top(rr2);
|
||||
bn_check_top(rr2);
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ int BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
|
|||
r->d[i] = at->d[i];
|
||||
}
|
||||
|
||||
r->top = at->top;
|
||||
bn_set_top(r, at->top);
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
|
|
@ -305,7 +305,7 @@ int BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const int p[])
|
|||
for (j = 0; j < a->top; j++) {
|
||||
r->d[j] = a->d[j];
|
||||
}
|
||||
r->top = a->top;
|
||||
bn_set_top(r, a->top);
|
||||
}
|
||||
z = r->d;
|
||||
|
||||
|
|
@ -419,7 +419,7 @@ int BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
|
|||
zlen = a->top + b->top + 4;
|
||||
if (!bn_wexpand(s, zlen))
|
||||
goto err;
|
||||
s->top = zlen;
|
||||
bn_set_top(s, zlen);
|
||||
|
||||
for (i = 0; i < zlen; i++)
|
||||
s->d[i] = 0;
|
||||
|
|
@ -498,7 +498,7 @@ int BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const int p[],
|
|||
s->d[2 * i] = SQR0(a->d[i]);
|
||||
}
|
||||
|
||||
s->top = 2 * a->top;
|
||||
bn_set_top(s, 2 * a->top);
|
||||
bn_correct_top(s);
|
||||
if (!BN_GF2m_mod_arr(r, s, p))
|
||||
goto err;
|
||||
|
|
@ -618,20 +618,20 @@ static int BN_GF2m_mod_inv_vartime(BIGNUM *r, const BIGNUM *a,
|
|||
udp = u->d;
|
||||
for (i = u->top; i < top; i++)
|
||||
udp[i] = 0;
|
||||
u->top = top;
|
||||
bn_set_top(u, top);
|
||||
if (!bn_wexpand(b, top))
|
||||
goto err;
|
||||
bdp = b->d;
|
||||
bdp[0] = 1;
|
||||
for (i = 1; i < top; i++)
|
||||
bdp[i] = 0;
|
||||
b->top = top;
|
||||
bn_set_top(b, top);
|
||||
if (!bn_wexpand(c, top))
|
||||
goto err;
|
||||
cdp = c->d;
|
||||
for (i = 0; i < top; i++)
|
||||
cdp[i] = 0;
|
||||
c->top = top;
|
||||
bn_set_top(c, top);
|
||||
vdp = v->d; /* It pays off to "cache" *->d pointers,
|
||||
* because it allows optimizer to be more
|
||||
* aggressive. But we don't have to "cache"
|
||||
|
|
|
|||
|
|
@ -174,7 +174,9 @@ void bn_set_static_words(BIGNUM *a, const BN_ULONG *words, int size)
|
|||
* |const| qualifier omission is compensated by BN_FLG_STATIC_DATA
|
||||
* flag, which effectively means "read-only data".
|
||||
*/
|
||||
a->data = NULL;
|
||||
a->d = (BN_ULONG *)words;
|
||||
/* No need to call bn_set_top() in this case */
|
||||
a->dmax = a->top = size;
|
||||
a->neg = 0;
|
||||
a->flags |= BN_FLG_STATIC_DATA;
|
||||
|
|
@ -188,8 +190,10 @@ int bn_set_words(BIGNUM *a, const BN_ULONG *words, int num_words)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* TODO(FIXNUM): In the future, we'll use an OSSL_FN function on a->data */
|
||||
memcpy(a->d, words, sizeof(BN_ULONG) * num_words);
|
||||
a->top = num_words;
|
||||
|
||||
bn_set_top(a, num_words);
|
||||
bn_correct_top(a);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/endian.h"
|
||||
#include "bn_local.h"
|
||||
#include <openssl/opensslconf.h>
|
||||
#include "internal/constant_time.h"
|
||||
#include "crypto/fn.h"
|
||||
#include "bn_local.h"
|
||||
|
||||
/* This stuff appears to be completely unused, so is deprecated */
|
||||
#ifndef OPENSSL_NO_DEPRECATED_0_9_8
|
||||
|
|
@ -83,7 +86,10 @@ const BIGNUM *BN_value_one(void)
|
|||
{
|
||||
static const BN_ULONG data_one = 1L;
|
||||
static const BIGNUM const_one = {
|
||||
(BN_ULONG *)&data_one, 1, 1, 0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)&data_one,
|
||||
.top = 1,
|
||||
.dmax = 1,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
return &const_one;
|
||||
|
|
@ -199,7 +205,7 @@ int BN_num_bits(const BIGNUM *a)
|
|||
return ((i * BN_BITS2) + BN_num_bits_word(a->d[i]));
|
||||
}
|
||||
|
||||
static void bn_free_d(BIGNUM *a, int clear)
|
||||
static void bn_free_d(BIGNUM *a, bool clear)
|
||||
{
|
||||
if (BN_get_flags(a, BN_FLG_SECURE))
|
||||
OPENSSL_secure_clear_free(a->d, a->dmax * sizeof(a->d[0]));
|
||||
|
|
@ -213,8 +219,12 @@ void BN_clear_free(BIGNUM *a)
|
|||
{
|
||||
if (a == NULL)
|
||||
return;
|
||||
if (a->d != NULL && !BN_get_flags(a, BN_FLG_STATIC_DATA))
|
||||
bn_free_d(a, 1);
|
||||
if (!BN_get_flags(a, BN_FLG_STATIC_DATA)) {
|
||||
if (a->data != NULL)
|
||||
OSSL_FN_clear_free(a->data);
|
||||
else
|
||||
bn_free_d(a, true);
|
||||
}
|
||||
if (BN_get_flags(a, BN_FLG_MALLOCED)) {
|
||||
OPENSSL_cleanse(a, sizeof(*a));
|
||||
OPENSSL_free(a);
|
||||
|
|
@ -225,8 +235,12 @@ void BN_free(BIGNUM *a)
|
|||
{
|
||||
if (a == NULL)
|
||||
return;
|
||||
if (!BN_get_flags(a, BN_FLG_STATIC_DATA))
|
||||
bn_free_d(a, 0);
|
||||
if (!BN_get_flags(a, BN_FLG_STATIC_DATA)) {
|
||||
if (a->data != NULL)
|
||||
OSSL_FN_free(a->data);
|
||||
else
|
||||
bn_free_d(a, false);
|
||||
}
|
||||
if (a->flags & BN_FLG_MALLOCED)
|
||||
OPENSSL_free(a);
|
||||
}
|
||||
|
|
@ -261,11 +275,11 @@ BIGNUM *BN_secure_new(void)
|
|||
|
||||
/* This is used by bn_expand2() */
|
||||
/* The caller MUST check that words > b->dmax before calling this */
|
||||
static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
|
||||
static OSSL_FN *bn_expand_internal(const BIGNUM *b, int words)
|
||||
{
|
||||
BN_ULONG *a = NULL;
|
||||
OSSL_FN *a = NULL;
|
||||
|
||||
if (ossl_unlikely(words > (INT_MAX / (4 * BN_BITS2)))) {
|
||||
if (ossl_unlikely(words > BN_MAX_WORDS)) {
|
||||
ERR_raise(ERR_LIB_BN, BN_R_BIGNUM_TOO_LONG);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -274,15 +288,19 @@ static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
|
|||
return NULL;
|
||||
}
|
||||
if (BN_get_flags(b, BN_FLG_SECURE))
|
||||
a = OPENSSL_secure_calloc(words, sizeof(*a));
|
||||
a = OSSL_FN_secure_new_limbs(words);
|
||||
else
|
||||
a = OPENSSL_calloc(words, sizeof(*a));
|
||||
a = OSSL_FN_new_limbs(words);
|
||||
if (ossl_unlikely(a == NULL))
|
||||
return NULL;
|
||||
|
||||
assert(b->top <= words);
|
||||
if (b->top > 0)
|
||||
memcpy(a, b->d, sizeof(*a) * b->top);
|
||||
if (b->top > 0) {
|
||||
if (b->data != NULL)
|
||||
ossl_fn_copy_internal(a, b->data, -1);
|
||||
else if (b->d != NULL)
|
||||
ossl_fn_copy_internal_limbs(a, b->d, b->top);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
|
@ -298,19 +316,58 @@ static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
|
|||
BIGNUM *bn_expand2(BIGNUM *b, int words)
|
||||
{
|
||||
if (ossl_likely(words > b->dmax)) {
|
||||
BN_ULONG *a = bn_expand_internal(b, words);
|
||||
OSSL_FN *a = bn_expand_internal(b, words);
|
||||
|
||||
if (ossl_unlikely(!a))
|
||||
return NULL;
|
||||
if (b->d != NULL)
|
||||
bn_free_d(b, 1);
|
||||
b->d = a;
|
||||
b->dmax = words;
|
||||
if (b->data != NULL)
|
||||
OSSL_FN_clear_free(b->data);
|
||||
else if (b->d != NULL)
|
||||
bn_free_d(b, true);
|
||||
b->data = a;
|
||||
/* TODO(FIXNUM) The following is TO BE REMOVED */
|
||||
b->d = b->data->d;
|
||||
b->dmax = b->data->dsize;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
OSSL_FN *bn_acquire_ossl_fn(BIGNUM *b, int limbs)
|
||||
{
|
||||
if (ossl_unlikely(b == NULL))
|
||||
return NULL;
|
||||
|
||||
if (bn_wexpand(b, limbs) == NULL)
|
||||
return NULL;
|
||||
/* TODO(FIXNUM): should we add a flag bit for this in b->flags ? */
|
||||
return b->data;
|
||||
}
|
||||
|
||||
void bn_release(BIGNUM *b, int limbs)
|
||||
{
|
||||
if (ossl_unlikely(b == NULL || b->data == NULL))
|
||||
return;
|
||||
|
||||
int fixed_top = (b->flags & BN_FLG_FIXED_TOP) != 0;
|
||||
|
||||
bn_set_top(b, limbs);
|
||||
|
||||
/* Don't correct top if BN_FLG_FIXED_TOP was set */
|
||||
if (fixed_top)
|
||||
return;
|
||||
|
||||
bn_correct_top(b);
|
||||
}
|
||||
|
||||
OSSL_FN *bn_get_ossl_fn(const BIGNUM *bn)
|
||||
{
|
||||
if (ossl_unlikely(bn == NULL))
|
||||
return NULL;
|
||||
|
||||
return bn->data;
|
||||
}
|
||||
|
||||
BIGNUM *BN_dup(const BIGNUM *a)
|
||||
{
|
||||
BIGNUM *t;
|
||||
|
|
@ -343,11 +400,14 @@ BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
|
|||
if (ossl_unlikely(bn_wexpand(a, bn_words) == NULL))
|
||||
return NULL;
|
||||
|
||||
if (ossl_likely(b->top > 0))
|
||||
memcpy(a->d, b->d, sizeof(b->d[0]) * bn_words);
|
||||
|
||||
if (ossl_likely(bn_words > 0)) {
|
||||
if (b->data != NULL)
|
||||
ossl_fn_copy_internal(a->data, b->data, bn_words);
|
||||
else if (b->d != NULL)
|
||||
ossl_fn_copy_internal_limbs(a->data, b->d, bn_words);
|
||||
}
|
||||
a->neg = b->neg;
|
||||
a->top = b->top;
|
||||
bn_set_top(a, b->top);
|
||||
a->flags |= b->flags & BN_FLG_FIXED_TOP;
|
||||
bn_check_top(a);
|
||||
return a;
|
||||
|
|
@ -359,6 +419,7 @@ BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
|
|||
void BN_swap(BIGNUM *a, BIGNUM *b)
|
||||
{
|
||||
int flags_old_a, flags_old_b;
|
||||
OSSL_FN *tmp_data;
|
||||
BN_ULONG *tmp_d;
|
||||
int tmp_top, tmp_dmax, tmp_neg;
|
||||
|
||||
|
|
@ -368,16 +429,19 @@ void BN_swap(BIGNUM *a, BIGNUM *b)
|
|||
flags_old_a = a->flags;
|
||||
flags_old_b = b->flags;
|
||||
|
||||
tmp_data = a->data;
|
||||
tmp_d = a->d;
|
||||
tmp_top = a->top;
|
||||
tmp_dmax = a->dmax;
|
||||
tmp_neg = a->neg;
|
||||
|
||||
a->data = b->data;
|
||||
a->d = b->d;
|
||||
a->top = b->top;
|
||||
a->dmax = b->dmax;
|
||||
a->neg = b->neg;
|
||||
|
||||
b->data = tmp_data;
|
||||
b->d = tmp_d;
|
||||
b->top = tmp_top;
|
||||
b->dmax = tmp_dmax;
|
||||
|
|
@ -394,10 +458,12 @@ void BN_clear(BIGNUM *a)
|
|||
if (a == NULL)
|
||||
return;
|
||||
bn_check_top(a);
|
||||
if (a->d != NULL)
|
||||
if (a->data != NULL)
|
||||
OSSL_FN_clear(a->data);
|
||||
else if (a->d != NULL)
|
||||
OPENSSL_cleanse(a->d, sizeof(*a->d) * a->dmax);
|
||||
a->neg = 0;
|
||||
a->top = 0;
|
||||
bn_set_top(a, 0);
|
||||
a->flags &= ~BN_FLG_FIXED_TOP;
|
||||
}
|
||||
|
||||
|
|
@ -414,11 +480,11 @@ BN_ULONG BN_get_word(const BIGNUM *a)
|
|||
int BN_set_word(BIGNUM *a, BN_ULONG w)
|
||||
{
|
||||
bn_check_top(a);
|
||||
if (bn_expand(a, (int)sizeof(BN_ULONG) * 8) == NULL)
|
||||
if (bn_wexpand(a, 1) == NULL)
|
||||
return 0;
|
||||
a->neg = 0;
|
||||
a->d[0] = w;
|
||||
a->top = (w ? 1 : 0);
|
||||
bn_set_top(a, (w ? 1 : 0));
|
||||
a->flags &= ~BN_FLG_FIXED_TOP;
|
||||
bn_check_top(a);
|
||||
return 1;
|
||||
|
|
@ -500,7 +566,7 @@ static BIGNUM *bin2bn(const unsigned char *s, int len, BIGNUM *ret,
|
|||
}
|
||||
/* If it was all zeros, we're done */
|
||||
if (len == 0) {
|
||||
ret->top = 0;
|
||||
bn_set_top(ret, 0);
|
||||
return ret;
|
||||
}
|
||||
n = ((len - 1) / BN_BYTES) + 1; /* Number of resulting bignum chunks */
|
||||
|
|
@ -508,7 +574,7 @@ static BIGNUM *bin2bn(const unsigned char *s, int len, BIGNUM *ret,
|
|||
BN_free(bn);
|
||||
return NULL;
|
||||
}
|
||||
ret->top = n;
|
||||
bn_set_top(ret, n);
|
||||
ret->neg = neg;
|
||||
for (i = 0; n-- > 0; i++) {
|
||||
BN_ULONG l = 0; /* Accumulator */
|
||||
|
|
@ -789,7 +855,7 @@ int BN_cmp(const BIGNUM *a, const BIGNUM *b)
|
|||
|
||||
int BN_set_bit(BIGNUM *a, int n)
|
||||
{
|
||||
int i, j, k;
|
||||
int i, j;
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
|
|
@ -799,9 +865,12 @@ int BN_set_bit(BIGNUM *a, int n)
|
|||
if (a->top <= i) {
|
||||
if (bn_wexpand(a, i + 1) == NULL)
|
||||
return 0;
|
||||
for (k = a->top; k < i + 1; k++)
|
||||
a->d[k] = 0;
|
||||
a->top = i + 1;
|
||||
/*
|
||||
* If 'a' is actually expanded, we know that the expanded
|
||||
* part of the 'd' array is zeroed during allocation, so
|
||||
* no need to zero it again here.
|
||||
*/
|
||||
bn_set_top(a, i + 1);
|
||||
a->flags &= ~BN_FLG_FIXED_TOP;
|
||||
}
|
||||
|
||||
|
|
@ -854,9 +923,9 @@ int ossl_bn_mask_bits_fixed_top(BIGNUM *a, int n)
|
|||
if (w >= a->top)
|
||||
return 0;
|
||||
if (b == 0)
|
||||
a->top = w;
|
||||
bn_set_top(a, w);
|
||||
else {
|
||||
a->top = w + 1;
|
||||
bn_set_top(a, w + 1);
|
||||
a->d[w] &= ~(BN_MASK2 << b);
|
||||
}
|
||||
a->flags |= BN_FLG_FIXED_TOP;
|
||||
|
|
@ -1023,7 +1092,7 @@ int BN_security_bits(int L, int N)
|
|||
void BN_zero_ex(BIGNUM *a)
|
||||
{
|
||||
a->neg = 0;
|
||||
a->top = 0;
|
||||
bn_set_top(a, 0);
|
||||
a->flags &= ~BN_FLG_FIXED_TOP;
|
||||
}
|
||||
|
||||
|
|
@ -1034,7 +1103,12 @@ int BN_abs_is_word(const BIGNUM *a, const BN_ULONG w)
|
|||
|
||||
int BN_is_zero(const BIGNUM *a)
|
||||
{
|
||||
return a->top == 0;
|
||||
if ((a->flags & BN_FLG_FIXED_TOP) == 0)
|
||||
return a->top == 0;
|
||||
for (size_t i = a->top; i-- > 0;)
|
||||
if (a->d[i] != (BN_ULONG)0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_is_one(const BIGNUM *a)
|
||||
|
|
@ -1081,6 +1155,7 @@ int BN_to_montgomery(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
|
|||
|
||||
void BN_with_flags(BIGNUM *dest, const BIGNUM *b, int flags)
|
||||
{
|
||||
dest->data = b->data;
|
||||
dest->d = b->d;
|
||||
dest->top = b->top;
|
||||
dest->dmax = b->dmax;
|
||||
|
|
@ -1164,6 +1239,11 @@ void bn_correct_top_consttime(BIGNUM *a)
|
|||
}
|
||||
|
||||
mask = constant_time_eq_int(atop, 0);
|
||||
/*
|
||||
* We just went through the whole 'd' array to identify where
|
||||
* any leading set of zeros are located, so there's no need to
|
||||
* call bn_set_top() here.
|
||||
*/
|
||||
a->top = atop;
|
||||
a->neg = constant_time_select_int(mask, 0, a->neg);
|
||||
a->flags &= ~BN_FLG_FIXED_TOP;
|
||||
|
|
@ -1180,10 +1260,14 @@ void bn_correct_top(BIGNUM *a)
|
|||
if (*ftl != 0)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* We just verified that the BN_ULONGs between a->top and
|
||||
* tmp_top are all zero, so there's no need to call
|
||||
* bn_set_top() here.
|
||||
*/
|
||||
a->top = tmp_top;
|
||||
}
|
||||
if (a->top == 0)
|
||||
a->neg = 0;
|
||||
a->flags &= ~BN_FLG_FIXED_TOP;
|
||||
bn_pollute(a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,27 +10,24 @@
|
|||
#ifndef OSSL_CRYPTO_BN_LOCAL_H
|
||||
#define OSSL_CRYPTO_BN_LOCAL_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/numbers.h"
|
||||
#include "crypto/bn.h"
|
||||
|
||||
#include "../fn/fn_local.h"
|
||||
|
||||
/*
|
||||
* These preprocessor symbols control various aspects of the bignum headers
|
||||
* and library code. They're not defined by any "normal" configuration, as
|
||||
* they are intended for development and testing purposes. NB: defining
|
||||
* them can be useful for debugging application code as well as openssl
|
||||
* itself. BN_DEBUG - turn on various debugging alterations to the bignum
|
||||
* code BN_RAND_DEBUG - uses random poisoning of unused words to trip up
|
||||
* mismanagement of bignum internals. Enable BN_RAND_DEBUG is known to
|
||||
* break some of the OpenSSL tests.
|
||||
* BN_RAND_DEBUG was historically used to poison unused words in bignum data,
|
||||
* for integrity debugging purposes. This isn't done any more, but enabling
|
||||
* BN_RAND_DEBUG also defined BN_DEBUG, which we preserve for the moment.
|
||||
*/
|
||||
#if defined(BN_RAND_DEBUG) && !defined(BN_DEBUG)
|
||||
#define BN_DEBUG
|
||||
#endif
|
||||
#if defined(BN_RAND_DEBUG)
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This should limit the stack usage due to alloca to about 4K.
|
||||
|
|
@ -120,32 +117,65 @@ typedef unsigned long long BN_ULLONG;
|
|||
#define BN_DEC_FMT2 "%09u"
|
||||
#endif
|
||||
|
||||
#define BN_MAX_WORDS (INT_MAX / (4 * BN_BITS2))
|
||||
|
||||
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
|
||||
BN_ULONG w);
|
||||
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
|
||||
void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
|
||||
BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
|
||||
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int num);
|
||||
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int num);
|
||||
|
||||
struct bignum_st {
|
||||
/* The number itself is a FIXNUM */
|
||||
OSSL_FN *data;
|
||||
|
||||
/* Some of these flags are replicated in OSSL_FN, some are not */
|
||||
int flags;
|
||||
|
||||
BN_ULONG *d; /* Pointer to |data->d| */
|
||||
int top; /* Index of last used d +1. */
|
||||
/* The next are internal book keeping for bn_expand. */
|
||||
int dmax; /* Copy of |data->dsize| */
|
||||
int neg; /* One if the number is negative */
|
||||
};
|
||||
|
||||
/*-
|
||||
* Bignum consistency macros
|
||||
*
|
||||
* There is one "API" macro, bn_fix_top(), for stripping leading zeroes from
|
||||
* bignum data after direct manipulations on the data. There is also an
|
||||
* "internal" macro, bn_check_top(), for verifying that there are no leading
|
||||
* zeroes. Unfortunately, some auditing is required due to the fact that
|
||||
* bn_fix_top() has become an overabused duct-tape because bignum data is
|
||||
* occasionally passed around in an inconsistent state. So the following
|
||||
* changes have been made to sort this out;
|
||||
* zeroes, and in case the BIGNUM has an integrated OSSL_FN, check the
|
||||
* consistency of the integration, including that the unused part of the
|
||||
* data is all zeros.
|
||||
*
|
||||
* Unfortunately, some auditing is required due to the fact that bn_fix_top()
|
||||
* has become an overabused duck-tape because bignum data is occasionally
|
||||
* passed around in an inconsistent state. So the following changes have been
|
||||
* made to sort this out;
|
||||
*
|
||||
* - bn_fix_top()s implementation has been moved to bn_correct_top()
|
||||
* - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and
|
||||
* bn_check_top() is as before.
|
||||
* - if BN_DEBUG *is* defined;
|
||||
* - bn_check_top() tries to pollute unused words even if the bignum 'top' is
|
||||
* consistent. (ed: only if BN_RAND_DEBUG is defined)
|
||||
* - if BN_DEBUG isn't defined:
|
||||
* - bn_check_top() does nothing.
|
||||
* - bn_fix_top() maps to bn_correct_top()
|
||||
* - if BN_DEBUG is defined:
|
||||
* - bn_check_top() performs its consistency checks
|
||||
* - bn_fix_top() maps to bn_check_top() rather than "fixing" anything.
|
||||
*
|
||||
* The idea is to have debug builds flag up inconsistent bignums when they
|
||||
* occur. If that occurs in a bn_fix_top(), we examine the code in question; if
|
||||
* the use of bn_fix_top() was appropriate (ie. it follows directly after code
|
||||
* that manipulates the bignum) it is converted to bn_correct_top(), and if it
|
||||
* was not appropriate, we convert it permanently to bn_check_top() and track
|
||||
* down the cause of the bug. Eventually, no internal code should be using the
|
||||
* bn_fix_top() macro. External applications and libraries should try this with
|
||||
* their own code too, both in terms of building against the openssl headers
|
||||
* with BN_DEBUG defined *and* linking with a version of OpenSSL built with it
|
||||
* defined. This not only improves external code, it provides more test
|
||||
* occur. If that occurs in a bn_fix_top(), we examine the code in question;
|
||||
* if the use of bn_fix_top() was appropriate (ie. it follows directly after
|
||||
* code that manipulates the bignum) it is converted to bn_correct_top(),
|
||||
* and if it was not appropriate, we convert it permanently to bn_check_top()
|
||||
* and track down the cause of the bug. Eventually, no internal code should be
|
||||
* using the bn_fix_top() macro. External applications and libraries should try
|
||||
* this with their own code too, both in terms of building against the openssl
|
||||
* headers with BN_DEBUG defined *and* linking with a version of OpenSSL built
|
||||
* with it defined. This not only improves external code, it provides more test
|
||||
* coverage for openssl's own code.
|
||||
*/
|
||||
|
||||
|
|
@ -164,54 +194,49 @@ typedef unsigned long long BN_ULLONG;
|
|||
* all operations manipulating the bit in question in non-BN_DEBUG build.
|
||||
*/
|
||||
#define BN_FLG_FIXED_TOP 0x10000
|
||||
#ifdef BN_RAND_DEBUG
|
||||
#define bn_pollute(a) \
|
||||
do { \
|
||||
const BIGNUM *_bnum1 = (a); \
|
||||
if (_bnum1->top < _bnum1->dmax) { \
|
||||
unsigned char _tmp_char; \
|
||||
/* We cast away const without the compiler knowing, any \
|
||||
* *genuinely* constant variables that aren't mutable \
|
||||
* wouldn't be constructed with top!=dmax. */ \
|
||||
BN_ULONG *_not_const; \
|
||||
memcpy(&_not_const, &_bnum1->d, sizeof(_not_const)); \
|
||||
(void)RAND_bytes(&_tmp_char, 1); /* Debug only - safe to ignore error return */ \
|
||||
memset(_not_const + _bnum1->top, _tmp_char, \
|
||||
sizeof(*_not_const) * (_bnum1->dmax - _bnum1->top)); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define bn_pollute(a)
|
||||
#endif
|
||||
#define bn_check_top(a) \
|
||||
do { \
|
||||
const BIGNUM *_bnum2 = (a); \
|
||||
if (_bnum2 != NULL) { \
|
||||
int _top = _bnum2->top; \
|
||||
if (_top == 0) { \
|
||||
assert(!_bnum2->neg); \
|
||||
} else if ((_bnum2->flags & BN_FLG_FIXED_TOP) == 0) { \
|
||||
assert(_bnum2->d[_top - 1] != 0); \
|
||||
} \
|
||||
bn_pollute(_bnum2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static ossl_inline bool bn_check_zero(BN_ULONG *words, int num_words)
|
||||
{
|
||||
for (int i = 0; i < num_words; i++)
|
||||
if (words[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ossl_inline void bn_check_top(const BIGNUM *bn)
|
||||
{
|
||||
if (bn != NULL) {
|
||||
/* BIGNUM <-> OSSL_FN compat checks */
|
||||
if (bn->data != NULL) {
|
||||
/* TODO(FIXNUM): Assertion for the future */
|
||||
/* assert(_bnum2->d == NULL); */
|
||||
assert(bn->d == bn->data->d);
|
||||
assert(bn->dmax == bn->data->dsize);
|
||||
assert(bn_check_zero(&bn->d[bn->top], bn->dmax - bn->top));
|
||||
}
|
||||
/* BIGNUM specific checks */
|
||||
if (bn->top == 0) {
|
||||
assert(!bn->neg);
|
||||
} else if ((bn->flags & BN_FLG_FIXED_TOP) == 0) {
|
||||
assert(bn->d[bn->top - 1] != 0);
|
||||
}
|
||||
assert(bn->dmax >= 0 && bn->dmax <= BN_MAX_WORDS);
|
||||
}
|
||||
}
|
||||
|
||||
#define bn_fix_top(a) bn_check_top(a)
|
||||
|
||||
static ossl_inline void bn_wcheck_size(const BIGNUM *bn, int words)
|
||||
{
|
||||
assert(words <= bn->dmax);
|
||||
assert(words >= bn->top);
|
||||
}
|
||||
|
||||
#define bn_check_size(bn, bits) bn_wcheck_size(bn, ((bits + BN_BITS2 - 1)) / BN_BITS2)
|
||||
#define bn_wcheck_size(bn, words) \
|
||||
do { \
|
||||
const BIGNUM *_bnum2 = (bn); \
|
||||
assert((words) <= (_bnum2)->dmax && (words) >= (_bnum2)->top); \
|
||||
/* avoid unused variable warning with NDEBUG */ \
|
||||
(void)(_bnum2); \
|
||||
} while (0)
|
||||
|
||||
#else /* !BN_DEBUG */
|
||||
|
||||
#define BN_FLG_FIXED_TOP 0
|
||||
#define bn_pollute(a)
|
||||
#define bn_check_top(a)
|
||||
#define bn_fix_top(a) bn_correct_top(a)
|
||||
#define bn_check_size(bn, bits)
|
||||
|
|
@ -219,29 +244,6 @@ typedef unsigned long long BN_ULLONG;
|
|||
|
||||
#endif
|
||||
|
||||
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
|
||||
BN_ULONG w);
|
||||
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
|
||||
void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
|
||||
BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
|
||||
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int num);
|
||||
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int num);
|
||||
|
||||
struct bignum_st {
|
||||
BN_ULONG *d; /*
|
||||
* Pointer to an array of 'BN_BITS2' bit
|
||||
* chunks. These chunks are organised in
|
||||
* a least significant chunk first order.
|
||||
*/
|
||||
int top; /* Index of last used d +1. */
|
||||
/* The next are internal book keeping for bn_expand. */
|
||||
int dmax; /* Size of the d array. */
|
||||
int neg; /* one if the number is negative */
|
||||
int flags;
|
||||
};
|
||||
|
||||
/* Used for montgomery multiplication */
|
||||
struct bn_mont_ctx_st {
|
||||
BIGNUM RR; /* used to convert to montgomery form,
|
||||
|
|
@ -643,21 +645,21 @@ void BN_RECP_CTX_init(BN_RECP_CTX *recp);
|
|||
void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
|
||||
|
||||
void bn_init(BIGNUM *a);
|
||||
void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb);
|
||||
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
|
||||
void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, int na, const BN_ULONG *b, int nb);
|
||||
void bn_mul_comba8(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
|
||||
void bn_mul_comba4(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b);
|
||||
void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp);
|
||||
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
|
||||
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
|
||||
int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
|
||||
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
|
||||
void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n2,
|
||||
int dna, int dnb, BN_ULONG *t);
|
||||
void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b,
|
||||
void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int n, int tna, int tnb, BN_ULONG *t);
|
||||
void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t);
|
||||
void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n);
|
||||
void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
void bn_mul_low_normal(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n);
|
||||
void bn_mul_low_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n2,
|
||||
BN_ULONG *t);
|
||||
BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int cl, int dl);
|
||||
|
|
@ -667,6 +669,7 @@ void bn_correct_top_consttime(BIGNUM *a);
|
|||
BIGNUM *int_bn_mod_inverse(BIGNUM *in,
|
||||
const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx,
|
||||
int *noinv);
|
||||
void bn_mul_truncated(BN_ULONG *r, int nr, const BN_ULONG *a, int na, const BN_ULONG *b, int nb);
|
||||
|
||||
static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits)
|
||||
{
|
||||
|
|
@ -682,4 +685,29 @@ static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits)
|
|||
int ossl_bn_check_prime(const BIGNUM *w, int checks, BN_CTX *ctx,
|
||||
int do_trial_division, BN_GENCB *cb);
|
||||
|
||||
/**
|
||||
* Set top on a given BIGNUM. If it has an associated OSSL_FN (the 'data'
|
||||
* field is non-NULL), and the new 'top' is less than the existing 'top',
|
||||
* zeroise the space between them.
|
||||
*
|
||||
* @param[in] b The BIGNUM instance to zeroise
|
||||
* @param[in] newtop The new 'top'
|
||||
* @returns the new 'top'
|
||||
* @pre b must not be NULL and newtop must be zero or positive
|
||||
*/
|
||||
static ossl_inline int bn_set_top(BIGNUM *b, int newtop)
|
||||
{
|
||||
assert(b != NULL && newtop >= 0);
|
||||
|
||||
if (b->data != NULL && newtop < b->top) {
|
||||
BN_ULONG *start = &(b->d[newtop]);
|
||||
size_t bytes = sizeof(BN_ULONG) * (b->top - newtop);
|
||||
|
||||
memset(start, 0, bytes);
|
||||
}
|
||||
|
||||
b->top = newtop;
|
||||
return b->top;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ int bn_mod_add_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
|
|||
rp[i] = (carry & tp[i]) | (~carry & rp[i]);
|
||||
((volatile BN_ULONG *)tp)[i] = 0;
|
||||
}
|
||||
r->top = (int)mtop;
|
||||
bn_set_top(r, (int)mtop);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
r->neg = 0;
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ int bn_mod_sub_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
|
|||
carry += (rp[i] < ta);
|
||||
}
|
||||
|
||||
r->top = (int)mtop;
|
||||
bn_set_top(r, (int)mtop);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
r->neg = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ int bn_mul_mont_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
|
|||
return 0;
|
||||
if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
|
||||
r->neg = a->neg ^ b->neg;
|
||||
r->top = num;
|
||||
bn_set_top(r, num);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
|
|||
n = &(mont->N);
|
||||
nl = n->top;
|
||||
if (nl == 0) {
|
||||
ret->top = 0;
|
||||
bn_set_top(ret, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
|
|||
rp[i] &= v;
|
||||
}
|
||||
|
||||
r->top = max;
|
||||
bn_set_top(r, max);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
n0 = mont->n0[0];
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont)
|
|||
|
||||
if (bn_wexpand(ret, nl) == NULL)
|
||||
return 0;
|
||||
ret->top = nl;
|
||||
bn_set_top(ret, nl);
|
||||
ret->flags |= BN_FLG_FIXED_TOP;
|
||||
ret->neg = r->neg;
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
|
|||
Ri->neg = 0;
|
||||
Ri->d[0] = BN_MASK2;
|
||||
Ri->d[1] = BN_MASK2;
|
||||
Ri->top = 2;
|
||||
bn_set_top(Ri, 2);
|
||||
}
|
||||
if (!BN_div(Ri, NULL, Ri, &tmod, ctx))
|
||||
goto err;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ BIGNUM *BN_mpi2bn(const unsigned char *d, int n, BIGNUM *ain)
|
|||
|
||||
if (len == 0) {
|
||||
a->neg = 0;
|
||||
a->top = 0;
|
||||
bn_set_top(a, 0);
|
||||
return a;
|
||||
}
|
||||
d += 4;
|
||||
|
|
|
|||
|
|
@ -11,479 +11,6 @@
|
|||
#include "internal/cryptlib.h"
|
||||
#include "bn_local.h"
|
||||
|
||||
#if defined(OPENSSL_NO_ASM) || !defined(OPENSSL_BN_ASM_PART_WORDS)
|
||||
/*
|
||||
* Here follows specialised variants of bn_add_words() and bn_sub_words().
|
||||
* They have the property performing operations on arrays of different sizes.
|
||||
* The sizes of those arrays is expressed through cl, which is the common
|
||||
* length ( basically, min(len(a),len(b)) ), and dl, which is the delta
|
||||
* between the two lengths, calculated as len(a)-len(b). All lengths are the
|
||||
* number of BN_ULONGs... For the operations that require a result array as
|
||||
* parameter, it must have the length cl+abs(dl). These functions should
|
||||
* probably end up in bn_asm.c as soon as there are assembler counterparts
|
||||
* for the systems that use assembler files.
|
||||
*/
|
||||
|
||||
BN_ULONG bn_sub_part_words(BN_ULONG *r,
|
||||
const BN_ULONG *a, const BN_ULONG *b,
|
||||
int cl, int dl)
|
||||
{
|
||||
BN_ULONG c, t;
|
||||
|
||||
assert(cl >= 0);
|
||||
c = bn_sub_words(r, a, b, cl);
|
||||
|
||||
if (dl == 0)
|
||||
return c;
|
||||
|
||||
r += cl;
|
||||
a += cl;
|
||||
b += cl;
|
||||
|
||||
if (dl < 0) {
|
||||
for (;;) {
|
||||
t = b[0];
|
||||
r[0] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
t = b[1];
|
||||
r[1] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
t = b[2];
|
||||
r[2] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
t = b[3];
|
||||
r[3] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
b += 4;
|
||||
r += 4;
|
||||
}
|
||||
} else {
|
||||
int save_dl = dl;
|
||||
while (c) {
|
||||
t = a[0];
|
||||
r[0] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
t = a[1];
|
||||
r[1] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
t = a[2];
|
||||
r[2] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
t = a[3];
|
||||
r[3] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
save_dl = dl;
|
||||
a += 4;
|
||||
r += 4;
|
||||
}
|
||||
if (dl > 0) {
|
||||
if (save_dl > dl) {
|
||||
switch (save_dl - dl) {
|
||||
case 1:
|
||||
r[1] = a[1];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
/* fall through */
|
||||
case 2:
|
||||
r[2] = a[2];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
/* fall through */
|
||||
case 3:
|
||||
r[3] = a[3];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
}
|
||||
a += 4;
|
||||
r += 4;
|
||||
}
|
||||
}
|
||||
if (dl > 0) {
|
||||
for (;;) {
|
||||
r[0] = a[0];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
r[1] = a[1];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
r[2] = a[2];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
r[3] = a[3];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
a += 4;
|
||||
r += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_SMALL_FOOTPRINT
|
||||
/*
|
||||
* Karatsuba recursive multiplication algorithm (cf. Knuth, The Art of
|
||||
* Computer Programming, Vol. 2)
|
||||
*/
|
||||
|
||||
/*-
|
||||
* r is 2*n2 words in size,
|
||||
* a and b are both n2 words in size.
|
||||
* n2 must be a power of 2.
|
||||
* We multiply and return the result.
|
||||
* t must be 2*n2 words in size
|
||||
* We calculate
|
||||
* a[0]*b[0]
|
||||
* a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
|
||||
* a[1]*b[1]
|
||||
*/
|
||||
/* dnX may not be positive, but n2/2+dnX has to be */
|
||||
void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
int dna, int dnb, BN_ULONG *t)
|
||||
{
|
||||
int n = n2 / 2, c1, c2;
|
||||
int tna = n + dna, tnb = n + dnb;
|
||||
unsigned int neg, zero;
|
||||
BN_ULONG ln, lo, *p;
|
||||
|
||||
/*
|
||||
* Only call bn_mul_comba 8 if n2 == 8 and the two arrays are complete
|
||||
* [steve]
|
||||
*/
|
||||
if (n2 == 8 && dna == 0 && dnb == 0) {
|
||||
bn_mul_comba8(r, a, b);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else do normal multiply */
|
||||
if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
|
||||
bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
|
||||
if ((dna + dnb) < 0)
|
||||
memset(&r[2 * n2 + dna + dnb], 0,
|
||||
sizeof(BN_ULONG) * -(dna + dnb));
|
||||
return;
|
||||
}
|
||||
/* r=(a[0]-a[1])*(b[1]-b[0]) */
|
||||
c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
|
||||
c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
|
||||
zero = neg = 0;
|
||||
switch (c1 * 3 + c2) {
|
||||
case -4:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
break;
|
||||
case -3:
|
||||
zero = 1;
|
||||
break;
|
||||
case -2:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
|
||||
neg = 1;
|
||||
break;
|
||||
case -1:
|
||||
case 0:
|
||||
case 1:
|
||||
zero = 1;
|
||||
break;
|
||||
case 2:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
neg = 1;
|
||||
break;
|
||||
case 3:
|
||||
zero = 1;
|
||||
break;
|
||||
case 4:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 4 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba4 could take
|
||||
* extra args to do this well */
|
||||
if (!zero)
|
||||
bn_mul_comba4(&(t[n2]), t, &(t[n]));
|
||||
else
|
||||
memset(&t[n2], 0, sizeof(*t) * 8);
|
||||
|
||||
bn_mul_comba4(r, a, b);
|
||||
bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
|
||||
} else if (n == 8 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba8 could
|
||||
* take extra args to do
|
||||
* this well */
|
||||
if (!zero)
|
||||
bn_mul_comba8(&(t[n2]), t, &(t[n]));
|
||||
else
|
||||
memset(&t[n2], 0, sizeof(*t) * 16);
|
||||
|
||||
bn_mul_comba8(r, a, b);
|
||||
bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
|
||||
} else {
|
||||
p = &(t[n2 * 2]);
|
||||
if (!zero)
|
||||
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
|
||||
else
|
||||
memset(&t[n2], 0, sizeof(*t) * n2);
|
||||
bn_mul_recursive(r, a, b, n, 0, 0, p);
|
||||
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
*/
|
||||
|
||||
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
|
||||
|
||||
if (neg) { /* if t[32] is negative */
|
||||
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
|
||||
} else {
|
||||
/* Might have a carry */
|
||||
c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
* c1 holds the carry bits
|
||||
*/
|
||||
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
*p = ln;
|
||||
|
||||
/*
|
||||
* The overflow will stop before we over write words we should not
|
||||
* overwrite
|
||||
*/
|
||||
if (ln < (BN_ULONG)c1) {
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* n+tn is the word length t needs to be n*4 is size, as does r
|
||||
*/
|
||||
/* tnX may not be negative but less than n */
|
||||
void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
|
||||
int tna, int tnb, BN_ULONG *t)
|
||||
{
|
||||
int i, j, n2 = n * 2;
|
||||
int c1, c2, neg;
|
||||
BN_ULONG ln, lo, *p;
|
||||
|
||||
if (n < 8) {
|
||||
bn_mul_normal(r, a, n + tna, b, n + tnb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* r=(a[0]-a[1])*(b[1]-b[0]) */
|
||||
c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
|
||||
c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
|
||||
neg = 0;
|
||||
switch (c1 * 3 + c2) {
|
||||
case -4:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
break;
|
||||
case -3:
|
||||
case -2:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
|
||||
neg = 1;
|
||||
break;
|
||||
case -1:
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
neg = 1;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The zero case isn't yet implemented here. The speedup would probably
|
||||
* be negligible.
|
||||
*/
|
||||
#if 0
|
||||
if (n == 4) {
|
||||
bn_mul_comba4(&(t[n2]), t, &(t[n]));
|
||||
bn_mul_comba4(r, a, b);
|
||||
bn_mul_normal(&(r[n2]), &(a[n]), tn, &(b[n]), tn);
|
||||
memset(&r[n2 + tn * 2], 0, sizeof(*r) * (n2 - tn * 2));
|
||||
} else
|
||||
#endif
|
||||
if (n == 8) {
|
||||
bn_mul_comba8(&(t[n2]), t, &(t[n]));
|
||||
bn_mul_comba8(r, a, b);
|
||||
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
|
||||
memset(&r[n2 + tna + tnb], 0, sizeof(*r) * (n2 - tna - tnb));
|
||||
} else {
|
||||
p = &(t[n2 * 2]);
|
||||
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
|
||||
bn_mul_recursive(r, a, b, n, 0, 0, p);
|
||||
i = n / 2;
|
||||
/*
|
||||
* If there is only a bottom half to the number, just do it
|
||||
*/
|
||||
if (tna > tnb)
|
||||
j = tna - i;
|
||||
else
|
||||
j = tnb - i;
|
||||
if (j == 0) {
|
||||
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
memset(&r[n2 + i * 2], 0, sizeof(*r) * (n2 - i * 2));
|
||||
} else if (j > 0) { /* eg, n == 16, i == 8 and tn == 11 */
|
||||
bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
memset(&(r[n2 + tna + tnb]), 0,
|
||||
sizeof(BN_ULONG) * (n2 - tna - tnb));
|
||||
} else { /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
|
||||
|
||||
memset(&r[n2], 0, sizeof(*r) * n2);
|
||||
if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL
|
||||
&& tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
|
||||
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
|
||||
} else {
|
||||
for (;;) {
|
||||
i /= 2;
|
||||
/*
|
||||
* these simplified conditions work exclusively because
|
||||
* difference between tna and tnb is 1 or 0
|
||||
*/
|
||||
if (i < tna || i < tnb) {
|
||||
bn_mul_part_recursive(&(r[n2]),
|
||||
&(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
break;
|
||||
} else if (i == tna || i == tnb) {
|
||||
bn_mul_recursive(&(r[n2]),
|
||||
&(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
*/
|
||||
|
||||
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
|
||||
|
||||
if (neg) { /* if t[32] is negative */
|
||||
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
|
||||
} else {
|
||||
/* Might have a carry */
|
||||
c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
* c1 holds the carry bits
|
||||
*/
|
||||
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
*p = ln;
|
||||
|
||||
/*
|
||||
* The overflow will stop before we over write words we should not
|
||||
* overwrite
|
||||
*/
|
||||
if (ln < (BN_ULONG)c1) {
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-
|
||||
* a and b must be the same size, which is n2.
|
||||
* r needs to be n2 words and t needs to be n2*2
|
||||
*/
|
||||
void bn_mul_low_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
BN_ULONG *t)
|
||||
{
|
||||
int n = n2 / 2;
|
||||
|
||||
bn_mul_recursive(r, a, b, n, 0, 0, &(t[0]));
|
||||
if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) {
|
||||
bn_mul_low_recursive(&(t[0]), &(a[0]), &(b[n]), n, &(t[n2]));
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
|
||||
bn_mul_low_recursive(&(t[0]), &(a[n]), &(b[0]), n, &(t[n2]));
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
|
||||
} else {
|
||||
bn_mul_low_normal(&(t[0]), &(a[0]), &(b[n]), n);
|
||||
bn_mul_low_normal(&(t[n]), &(a[n]), &(b[0]), n);
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[n]), n);
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_SMALL_FOOTPRINT */
|
||||
|
||||
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
||||
{
|
||||
int ret = bn_mul_fixed_top(r, a, b, ctx);
|
||||
|
|
@ -501,8 +28,6 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|||
BIGNUM *rr;
|
||||
#if !defined(OPENSSL_SMALL_FOOTPRINT)
|
||||
int i;
|
||||
BIGNUM *t = NULL;
|
||||
int j = 0, k;
|
||||
#endif
|
||||
|
||||
bn_check_top(a);
|
||||
|
|
@ -533,7 +58,8 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|||
if (al == 4) {
|
||||
if (bn_wexpand(rr, 8) == NULL)
|
||||
goto err;
|
||||
rr->top = 8;
|
||||
rr->flags |= BN_FLG_FIXED_TOP;
|
||||
bn_set_top(rr, 8);
|
||||
bn_mul_comba4(rr->d, a->d, b->d);
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -541,7 +67,8 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|||
if (al == 8) {
|
||||
if (bn_wexpand(rr, 16) == NULL)
|
||||
goto err;
|
||||
rr->top = 16;
|
||||
rr->flags |= BN_FLG_FIXED_TOP;
|
||||
bn_set_top(rr, 16);
|
||||
bn_mul_comba8(rr->d, a->d, b->d);
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -549,6 +76,9 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|||
|
||||
if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) {
|
||||
if (i >= -1 && i <= 1) {
|
||||
BIGNUM *t = NULL;
|
||||
int j = 0, k;
|
||||
|
||||
/*
|
||||
* Find out the power of two lower or equal to the longest of the
|
||||
* two numbers
|
||||
|
|
@ -568,26 +98,33 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
|
|||
if (al > j || bl > j) {
|
||||
if (bn_wexpand(t, k * 4) == NULL)
|
||||
goto err;
|
||||
t->top = k * 4;
|
||||
t->flags |= BN_FLG_FIXED_TOP;
|
||||
if (bn_wexpand(rr, k * 4) == NULL)
|
||||
goto err;
|
||||
bn_set_top(rr, k * 4);
|
||||
rr->flags |= BN_FLG_FIXED_TOP;
|
||||
bn_mul_part_recursive(rr->d, a->d, b->d,
|
||||
j, al - j, bl - j, t->d);
|
||||
} else { /* al <= j || bl <= j */
|
||||
|
||||
if (bn_wexpand(t, k * 2) == NULL)
|
||||
goto err;
|
||||
t->top = k * 2;
|
||||
t->flags |= BN_FLG_FIXED_TOP;
|
||||
if (bn_wexpand(rr, k * 2) == NULL)
|
||||
goto err;
|
||||
bn_set_top(rr, k * 2);
|
||||
rr->flags |= BN_FLG_FIXED_TOP;
|
||||
bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
|
||||
}
|
||||
rr->top = top;
|
||||
bn_set_top(rr, top);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_SMALL_FOOTPRINT */
|
||||
if (bn_wexpand(rr, top) == NULL)
|
||||
goto err;
|
||||
rr->top = top;
|
||||
bn_set_top(rr, top);
|
||||
bn_mul_normal(rr->d, a->d, al, b->d, bl);
|
||||
|
||||
#if !defined(OPENSSL_SMALL_FOOTPRINT)
|
||||
|
|
@ -604,66 +141,3 @@ err:
|
|||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb)
|
||||
{
|
||||
BN_ULONG *rr;
|
||||
|
||||
if (na < nb) {
|
||||
int itmp;
|
||||
BN_ULONG *ltmp;
|
||||
|
||||
itmp = na;
|
||||
na = nb;
|
||||
nb = itmp;
|
||||
ltmp = a;
|
||||
a = b;
|
||||
b = ltmp;
|
||||
}
|
||||
rr = &(r[na]);
|
||||
if (nb <= 0) {
|
||||
(void)bn_mul_words(r, a, na, 0);
|
||||
return;
|
||||
} else
|
||||
rr[0] = bn_mul_words(r, a, na, b[0]);
|
||||
|
||||
for (;;) {
|
||||
if (--nb <= 0)
|
||||
return;
|
||||
rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
|
||||
if (--nb <= 0)
|
||||
return;
|
||||
rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
|
||||
if (--nb <= 0)
|
||||
return;
|
||||
rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
|
||||
if (--nb <= 0)
|
||||
return;
|
||||
rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
|
||||
rr += 4;
|
||||
r += 4;
|
||||
b += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
|
||||
{
|
||||
bn_mul_words(r, a, n, b[0]);
|
||||
|
||||
for (;;) {
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[1]), a, n, b[1]);
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[2]), a, n, b[2]);
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[3]), a, n, b[3]);
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[4]), a, n, b[4]);
|
||||
r += 4;
|
||||
b += 4;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,43 +184,38 @@ static const BN_ULONG _nist_p_521_sqr[] = {
|
|||
#endif
|
||||
|
||||
static const BIGNUM ossl_bignum_nist_p_192 = {
|
||||
(BN_ULONG *)_nist_p_192[0],
|
||||
BN_NIST_192_TOP,
|
||||
BN_NIST_192_TOP,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_192[0],
|
||||
.top = BN_NIST_192_TOP,
|
||||
.dmax = BN_NIST_192_TOP,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BIGNUM ossl_bignum_nist_p_224 = {
|
||||
(BN_ULONG *)_nist_p_224[0],
|
||||
BN_NIST_224_TOP,
|
||||
BN_NIST_224_TOP,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_224[0],
|
||||
.top = BN_NIST_224_TOP,
|
||||
.dmax = BN_NIST_224_TOP,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BIGNUM ossl_bignum_nist_p_256 = {
|
||||
(BN_ULONG *)_nist_p_256[0],
|
||||
BN_NIST_256_TOP,
|
||||
BN_NIST_256_TOP,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_256[0],
|
||||
.top = BN_NIST_256_TOP,
|
||||
.dmax = BN_NIST_256_TOP,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BIGNUM ossl_bignum_nist_p_384 = {
|
||||
(BN_ULONG *)_nist_p_384[0],
|
||||
BN_NIST_384_TOP,
|
||||
BN_NIST_384_TOP,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_384[0],
|
||||
.top = BN_NIST_384_TOP,
|
||||
.dmax = BN_NIST_384_TOP,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BIGNUM ossl_bignum_nist_p_521 = {
|
||||
(BN_ULONG *)_nist_p_521,
|
||||
BN_NIST_521_TOP,
|
||||
BN_NIST_521_TOP,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_521,
|
||||
.top = BN_NIST_521_TOP,
|
||||
.dmax = BN_NIST_521_TOP,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
const BIGNUM *BN_get0_nist_prime_192(void)
|
||||
|
|
@ -359,10 +354,10 @@ int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
} buf;
|
||||
BN_ULONG c_d[BN_NIST_192_TOP], *res;
|
||||
static const BIGNUM ossl_bignum_nist_p_192_sqr = {
|
||||
(BN_ULONG *)_nist_p_192_sqr,
|
||||
OSSL_NELEM(_nist_p_192_sqr),
|
||||
OSSL_NELEM(_nist_p_192_sqr),
|
||||
0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_192_sqr,
|
||||
.top = OSSL_NELEM(_nist_p_192_sqr),
|
||||
.dmax = OSSL_NELEM(_nist_p_192_sqr),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
field = &ossl_bignum_nist_p_192; /* just to make sure */
|
||||
|
|
@ -462,7 +457,7 @@ int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
? r_d
|
||||
: c_d;
|
||||
nist_cp_bn(r_d, res, BN_NIST_192_TOP);
|
||||
r->top = BN_NIST_192_TOP;
|
||||
bn_set_top(r, BN_NIST_192_TOP);
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
|
|
@ -495,10 +490,10 @@ int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
BN_ULONG c_d[BN_NIST_224_TOP], *res;
|
||||
bn_addsub_f adjust;
|
||||
static const BIGNUM ossl_bignum_nist_p_224_sqr = {
|
||||
(BN_ULONG *)_nist_p_224_sqr,
|
||||
OSSL_NELEM(_nist_p_224_sqr),
|
||||
OSSL_NELEM(_nist_p_224_sqr),
|
||||
0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_224_sqr,
|
||||
.top = OSSL_NELEM(_nist_p_224_sqr),
|
||||
.dmax = OSSL_NELEM(_nist_p_224_sqr),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
field = &ossl_bignum_nist_p_224; /* just to make sure */
|
||||
|
|
@ -630,7 +625,7 @@ int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
? r_d
|
||||
: c_d;
|
||||
nist_cp_bn(r_d, res, BN_NIST_224_TOP);
|
||||
r->top = BN_NIST_224_TOP;
|
||||
bn_set_top(r, BN_NIST_224_TOP);
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
|
|
@ -661,10 +656,10 @@ int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
BN_ULONG c_d[BN_NIST_256_TOP], *res;
|
||||
bn_addsub_f adjust;
|
||||
static const BIGNUM ossl_bignum_nist_p_256_sqr = {
|
||||
(BN_ULONG *)_nist_p_256_sqr,
|
||||
OSSL_NELEM(_nist_p_256_sqr),
|
||||
OSSL_NELEM(_nist_p_256_sqr),
|
||||
0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_256_sqr,
|
||||
.top = OSSL_NELEM(_nist_p_256_sqr),
|
||||
.dmax = OSSL_NELEM(_nist_p_256_sqr),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
field = &ossl_bignum_nist_p_256; /* just to make sure */
|
||||
|
|
@ -859,7 +854,7 @@ int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
? r_d
|
||||
: c_d;
|
||||
nist_cp_bn(r_d, res, BN_NIST_256_TOP);
|
||||
r->top = BN_NIST_256_TOP;
|
||||
bn_set_top(r, BN_NIST_256_TOP);
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
|
|
@ -894,10 +889,10 @@ int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
BN_ULONG c_d[BN_NIST_384_TOP], *res;
|
||||
bn_addsub_f adjust;
|
||||
static const BIGNUM ossl_bignum_nist_p_384_sqr = {
|
||||
(BN_ULONG *)_nist_p_384_sqr,
|
||||
OSSL_NELEM(_nist_p_384_sqr),
|
||||
OSSL_NELEM(_nist_p_384_sqr),
|
||||
0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_384_sqr,
|
||||
.top = OSSL_NELEM(_nist_p_384_sqr),
|
||||
.dmax = OSSL_NELEM(_nist_p_384_sqr),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
field = &ossl_bignum_nist_p_384; /* just to make sure */
|
||||
|
|
@ -1126,7 +1121,7 @@ int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
? r_d
|
||||
: c_d;
|
||||
nist_cp_bn(r_d, res, BN_NIST_384_TOP);
|
||||
r->top = BN_NIST_384_TOP;
|
||||
bn_set_top(r, BN_NIST_384_TOP);
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
|
|
@ -1142,10 +1137,10 @@ int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
int top = a->top, i;
|
||||
BN_ULONG *r_d, *a_d = a->d, t_d[BN_NIST_521_TOP], val, tmp, *res;
|
||||
static const BIGNUM ossl_bignum_nist_p_521_sqr = {
|
||||
(BN_ULONG *)_nist_p_521_sqr,
|
||||
OSSL_NELEM(_nist_p_521_sqr),
|
||||
OSSL_NELEM(_nist_p_521_sqr),
|
||||
0, BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)_nist_p_521_sqr,
|
||||
.top = OSSL_NELEM(_nist_p_521_sqr),
|
||||
.dmax = OSSL_NELEM(_nist_p_521_sqr),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
field = &ossl_bignum_nist_p_521; /* just to make sure */
|
||||
|
|
@ -1197,7 +1192,7 @@ int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *field,
|
|||
? r_d
|
||||
: t_d;
|
||||
nist_cp_bn(r_d, res, BN_NIST_521_TOP);
|
||||
r->top = BN_NIST_521_TOP;
|
||||
bn_set_top(r, BN_NIST_521_TOP);
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -55,11 +55,10 @@ static const BN_ULONG small_prime_factors[] = {
|
|||
|
||||
#define BN_SMALL_PRIME_FACTORS_TOP OSSL_NELEM(small_prime_factors)
|
||||
static const BIGNUM _bignum_small_prime_factors = {
|
||||
(BN_ULONG *)small_prime_factors,
|
||||
BN_SMALL_PRIME_FACTORS_TOP,
|
||||
BN_SMALL_PRIME_FACTORS_TOP,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)small_prime_factors,
|
||||
.top = BN_SMALL_PRIME_FACTORS_TOP,
|
||||
.dmax = BN_SMALL_PRIME_FACTORS_TOP,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
const BIGNUM *ossl_bn_get0_small_factors(void)
|
||||
|
|
|
|||
|
|
@ -41,11 +41,10 @@ static const BN_ULONG inv_sqrt_2_val[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_inv_sqrt_2 = {
|
||||
(BN_ULONG *)inv_sqrt_2_val,
|
||||
OSSL_NELEM(inv_sqrt_2_val),
|
||||
OSSL_NELEM(inv_sqrt_2_val),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)inv_sqrt_2_val,
|
||||
.top = OSSL_NELEM(inv_sqrt_2_val),
|
||||
.dmax = OSSL_NELEM(inv_sqrt_2_val),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a)
|
|||
r->neg = a->neg;
|
||||
if (bn_wexpand(r, a->top + 1) == NULL)
|
||||
return 0;
|
||||
r->top = a->top;
|
||||
bn_set_top(r, a->top);
|
||||
} else {
|
||||
if (bn_wexpand(r, a->top + 1) == NULL)
|
||||
return 0;
|
||||
|
|
@ -37,7 +37,7 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a)
|
|||
c = t >> (BN_BITS2 - 1);
|
||||
}
|
||||
*rp = c;
|
||||
r->top += (int)c;
|
||||
bn_set_top(r, r->top + (int)c);
|
||||
bn_check_top(r);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -62,11 +62,10 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a)
|
|||
r->neg = a->neg;
|
||||
}
|
||||
rp = r->d;
|
||||
r->top = i;
|
||||
t = ap[--i];
|
||||
rp[i] = t >> 1;
|
||||
c = t << (BN_BITS2 - 1);
|
||||
r->top -= (t == 1);
|
||||
bn_set_top(r, i + (t > 1));
|
||||
while (i > 0) {
|
||||
t = ap[--i];
|
||||
rp[i] = ((t >> 1) & BN_MASK2) | c;
|
||||
|
|
@ -141,7 +140,7 @@ int bn_lshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n)
|
|||
memset(r->d, 0, sizeof(*t) * nw);
|
||||
|
||||
r->neg = a->neg;
|
||||
r->top = a->top + nw + 1;
|
||||
bn_set_top(r, a->top + nw + 1);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
|
||||
return 1;
|
||||
|
|
@ -209,7 +208,7 @@ int bn_rshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n)
|
|||
t[i] = l >> rb;
|
||||
|
||||
r->neg = a->neg;
|
||||
r->top = top;
|
||||
bn_set_top(r, top);
|
||||
r->flags |= BN_FLG_FIXED_TOP;
|
||||
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
|
|||
|
||||
al = a->top;
|
||||
if (al <= 0) {
|
||||
r->top = 0;
|
||||
bn_set_top(r, 0);
|
||||
r->neg = 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -91,8 +91,12 @@ int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Ensure that tmp won't cause any trouble */
|
||||
tmp->top = tmp->dmax;
|
||||
tmp->flags |= BN_FLG_FIXED_TOP;
|
||||
|
||||
rr->neg = 0;
|
||||
rr->top = max;
|
||||
bn_set_top(rr, max);
|
||||
rr->flags |= BN_FLG_FIXED_TOP;
|
||||
if (r != rr && BN_copy(r, rr) == NULL)
|
||||
goto err;
|
||||
|
|
@ -100,7 +104,6 @@ int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
|
|||
ret = 1;
|
||||
err:
|
||||
bn_check_top(rr);
|
||||
bn_check_top(tmp);
|
||||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,11 +49,10 @@ static const BN_ULONG bn_group_1024_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_1024 = {
|
||||
(BN_ULONG *)bn_group_1024_value,
|
||||
OSSL_NELEM(bn_group_1024_value),
|
||||
OSSL_NELEM(bn_group_1024_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_1024_value,
|
||||
.top = OSSL_NELEM(bn_group_1024_value),
|
||||
.dmax = OSSL_NELEM(bn_group_1024_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_group_1536_value[] = {
|
||||
|
|
@ -84,11 +83,10 @@ static const BN_ULONG bn_group_1536_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_1536 = {
|
||||
(BN_ULONG *)bn_group_1536_value,
|
||||
OSSL_NELEM(bn_group_1536_value),
|
||||
OSSL_NELEM(bn_group_1536_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_1536_value,
|
||||
.top = OSSL_NELEM(bn_group_1536_value),
|
||||
.dmax = OSSL_NELEM(bn_group_1536_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_group_2048_value[] = {
|
||||
|
|
@ -127,11 +125,10 @@ static const BN_ULONG bn_group_2048_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_2048 = {
|
||||
(BN_ULONG *)bn_group_2048_value,
|
||||
OSSL_NELEM(bn_group_2048_value),
|
||||
OSSL_NELEM(bn_group_2048_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_2048_value,
|
||||
.top = OSSL_NELEM(bn_group_2048_value),
|
||||
.dmax = OSSL_NELEM(bn_group_2048_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_group_3072_value[] = {
|
||||
|
|
@ -186,11 +183,10 @@ static const BN_ULONG bn_group_3072_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_3072 = {
|
||||
(BN_ULONG *)bn_group_3072_value,
|
||||
OSSL_NELEM(bn_group_3072_value),
|
||||
OSSL_NELEM(bn_group_3072_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_3072_value,
|
||||
.top = OSSL_NELEM(bn_group_3072_value),
|
||||
.dmax = OSSL_NELEM(bn_group_3072_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_group_4096_value[] = {
|
||||
|
|
@ -261,11 +257,10 @@ static const BN_ULONG bn_group_4096_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_4096 = {
|
||||
(BN_ULONG *)bn_group_4096_value,
|
||||
OSSL_NELEM(bn_group_4096_value),
|
||||
OSSL_NELEM(bn_group_4096_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_4096_value,
|
||||
.top = OSSL_NELEM(bn_group_4096_value),
|
||||
.dmax = OSSL_NELEM(bn_group_4096_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_group_6144_value[] = {
|
||||
|
|
@ -368,11 +363,10 @@ static const BN_ULONG bn_group_6144_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_6144 = {
|
||||
(BN_ULONG *)bn_group_6144_value,
|
||||
OSSL_NELEM(bn_group_6144_value),
|
||||
OSSL_NELEM(bn_group_6144_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_6144_value,
|
||||
.top = OSSL_NELEM(bn_group_6144_value),
|
||||
.dmax = OSSL_NELEM(bn_group_6144_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_group_8192_value[] = {
|
||||
|
|
@ -507,39 +501,35 @@ static const BN_ULONG bn_group_8192_value[] = {
|
|||
};
|
||||
|
||||
const BIGNUM ossl_bn_group_8192 = {
|
||||
(BN_ULONG *)bn_group_8192_value,
|
||||
OSSL_NELEM(bn_group_8192_value),
|
||||
OSSL_NELEM(bn_group_8192_value),
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_group_8192_value,
|
||||
.top = OSSL_NELEM(bn_group_8192_value),
|
||||
.dmax = OSSL_NELEM(bn_group_8192_value),
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
static const BN_ULONG bn_generator_19_value[] = { 19 };
|
||||
|
||||
const BIGNUM ossl_bn_generator_19 = {
|
||||
(BN_ULONG *)bn_generator_19_value,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_generator_19_value,
|
||||
.top = 1,
|
||||
.dmax = 1,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
static const BN_ULONG bn_generator_5_value[] = { 5 };
|
||||
|
||||
const BIGNUM ossl_bn_generator_5 = {
|
||||
(BN_ULONG *)bn_generator_5_value,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_generator_5_value,
|
||||
.top = 1,
|
||||
.dmax = 1,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
static const BN_ULONG bn_generator_2_value[] = { 2 };
|
||||
|
||||
const BIGNUM ossl_bn_generator_2 = {
|
||||
(BN_ULONG *)bn_generator_2_value,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
BN_FLG_STATIC_DATA
|
||||
.d = (BN_ULONG *)bn_generator_2_value,
|
||||
.top = 1,
|
||||
.dmax = 1,
|
||||
.flags = BN_FLG_STATIC_DATA,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
407
crypto/bn/bnw_mul.c
Normal file
407
crypto/bn/bnw_mul.c
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "bn_local.h"
|
||||
|
||||
#ifndef OPENSSL_SMALL_FOOTPRINT
|
||||
/*
|
||||
* Karatsuba recursive multiplication algorithm (cf. Knuth, The Art of
|
||||
* Computer Programming, Vol. 2)
|
||||
*/
|
||||
|
||||
/*-
|
||||
* r is 2*n2 words in size,
|
||||
* a and b are both n2 words in size.
|
||||
* n2 must be a power of 2.
|
||||
* We multiply and return the result.
|
||||
* t must be 2*n2 words in size
|
||||
* We calculate
|
||||
* a[0]*b[0]
|
||||
* a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
|
||||
* a[1]*b[1]
|
||||
*/
|
||||
/* dnX may not be positive, but n2/2+dnX has to be */
|
||||
void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n2,
|
||||
int dna, int dnb, BN_ULONG *t)
|
||||
{
|
||||
int n = n2 / 2, c1, c2;
|
||||
int tna = n + dna, tnb = n + dnb;
|
||||
unsigned int neg, zero;
|
||||
BN_ULONG ln, lo, *p;
|
||||
|
||||
/*
|
||||
* Only call bn_mul_comba 8 if n2 == 8 and the two arrays are complete
|
||||
* [steve]
|
||||
*/
|
||||
if (n2 == 8 && dna == 0 && dnb == 0) {
|
||||
bn_mul_comba8(r, a, b);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else do normal multiply */
|
||||
if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
|
||||
bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
|
||||
if ((dna + dnb) < 0)
|
||||
memset(&r[2 * n2 + dna + dnb], 0,
|
||||
sizeof(BN_ULONG) * -(dna + dnb));
|
||||
return;
|
||||
}
|
||||
/* r=(a[0]-a[1])*(b[1]-b[0]) */
|
||||
c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
|
||||
c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
|
||||
zero = neg = 0;
|
||||
switch (c1 * 3 + c2) {
|
||||
case -4:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
break;
|
||||
case -3:
|
||||
zero = 1;
|
||||
break;
|
||||
case -2:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
|
||||
neg = 1;
|
||||
break;
|
||||
case -1:
|
||||
case 0:
|
||||
case 1:
|
||||
zero = 1;
|
||||
break;
|
||||
case 2:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
neg = 1;
|
||||
break;
|
||||
case 3:
|
||||
zero = 1;
|
||||
break;
|
||||
case 4:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 4 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba4 could take
|
||||
* extra args to do this well */
|
||||
if (!zero)
|
||||
bn_mul_comba4(&(t[n2]), t, &(t[n]));
|
||||
else
|
||||
memset(&t[n2], 0, sizeof(*t) * 8);
|
||||
|
||||
bn_mul_comba4(r, a, b);
|
||||
bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
|
||||
} else if (n == 8 && dna == 0 && dnb == 0) { /* XXX: bn_mul_comba8 could
|
||||
* take extra args to do
|
||||
* this well */
|
||||
if (!zero)
|
||||
bn_mul_comba8(&(t[n2]), t, &(t[n]));
|
||||
else
|
||||
memset(&t[n2], 0, sizeof(*t) * 16);
|
||||
|
||||
bn_mul_comba8(r, a, b);
|
||||
bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
|
||||
} else {
|
||||
p = &(t[n2 * 2]);
|
||||
if (!zero)
|
||||
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
|
||||
else
|
||||
memset(&t[n2], 0, sizeof(*t) * n2);
|
||||
bn_mul_recursive(r, a, b, n, 0, 0, p);
|
||||
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
*/
|
||||
|
||||
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
|
||||
|
||||
if (neg) { /* if t[32] is negative */
|
||||
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
|
||||
} else {
|
||||
/* Might have a carry */
|
||||
c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
* c1 holds the carry bits
|
||||
*/
|
||||
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
*p = ln;
|
||||
|
||||
/*
|
||||
* The overflow will stop before we over write words we should not
|
||||
* overwrite
|
||||
*/
|
||||
if (ln < (BN_ULONG)c1) {
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* n+tn is the word length t needs to be n*4 is size, as does r
|
||||
*/
|
||||
/* tnX may not be negative but less than n */
|
||||
void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int n, int tna, int tnb, BN_ULONG *t)
|
||||
{
|
||||
int i, j, n2 = n * 2;
|
||||
int c1, c2, neg;
|
||||
BN_ULONG ln, lo, *p;
|
||||
|
||||
if (n < 8) {
|
||||
bn_mul_normal(r, a, n + tna, b, n + tnb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* r=(a[0]-a[1])*(b[1]-b[0]) */
|
||||
c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
|
||||
c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
|
||||
neg = 0;
|
||||
switch (c1 * 3 + c2) {
|
||||
case -4:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
break;
|
||||
case -3:
|
||||
case -2:
|
||||
bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
|
||||
neg = 1;
|
||||
break;
|
||||
case -1:
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
|
||||
bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
|
||||
neg = 1;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
|
||||
bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The zero case isn't yet implemented here. The speedup would probably
|
||||
* be negligible.
|
||||
*/
|
||||
#if 0
|
||||
if (n == 4) {
|
||||
bn_mul_comba4(&(t[n2]), t, &(t[n]));
|
||||
bn_mul_comba4(r, a, b);
|
||||
bn_mul_normal(&(r[n2]), &(a[n]), tn, &(b[n]), tn);
|
||||
memset(&r[n2 + tn * 2], 0, sizeof(*r) * (n2 - tn * 2));
|
||||
} else
|
||||
#endif
|
||||
if (n == 8) {
|
||||
bn_mul_comba8(&(t[n2]), t, &(t[n]));
|
||||
bn_mul_comba8(r, a, b);
|
||||
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
|
||||
memset(&r[n2 + tna + tnb], 0, sizeof(*r) * (n2 - tna - tnb));
|
||||
} else {
|
||||
p = &(t[n2 * 2]);
|
||||
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
|
||||
bn_mul_recursive(r, a, b, n, 0, 0, p);
|
||||
i = n / 2;
|
||||
/*
|
||||
* If there is only a bottom half to the number, just do it
|
||||
*/
|
||||
if (tna > tnb)
|
||||
j = tna - i;
|
||||
else
|
||||
j = tnb - i;
|
||||
if (j == 0) {
|
||||
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
memset(&r[n2 + i * 2], 0, sizeof(*r) * (n2 - i * 2));
|
||||
} else if (j > 0) { /* eg, n == 16, i == 8 and tn == 11 */
|
||||
bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
memset(&(r[n2 + tna + tnb]), 0,
|
||||
sizeof(BN_ULONG) * (n2 - tna - tnb));
|
||||
} else { /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
|
||||
|
||||
memset(&r[n2], 0, sizeof(*r) * n2);
|
||||
if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL
|
||||
&& tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
|
||||
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
|
||||
} else {
|
||||
for (;;) {
|
||||
i /= 2;
|
||||
/*
|
||||
* these simplified conditions work exclusively because
|
||||
* difference between tna and tnb is 1 or 0
|
||||
*/
|
||||
if (i < tna || i < tnb) {
|
||||
bn_mul_part_recursive(&(r[n2]),
|
||||
&(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
break;
|
||||
} else if (i == tna || i == tnb) {
|
||||
bn_mul_recursive(&(r[n2]),
|
||||
&(a[n]), &(b[n]),
|
||||
i, tna - i, tnb - i, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
*/
|
||||
|
||||
c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
|
||||
|
||||
if (neg) { /* if t[32] is negative */
|
||||
c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
|
||||
} else {
|
||||
/* Might have a carry */
|
||||
c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
|
||||
}
|
||||
|
||||
/*-
|
||||
* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
|
||||
* r[10] holds (a[0]*b[0])
|
||||
* r[32] holds (b[1]*b[1])
|
||||
* c1 holds the carry bits
|
||||
*/
|
||||
c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
*p = ln;
|
||||
|
||||
/*
|
||||
* The overflow will stop before we over write words we should not
|
||||
* overwrite
|
||||
*/
|
||||
if (ln < (BN_ULONG)c1) {
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-
|
||||
* a and b must be the same size, which is n2.
|
||||
* r needs to be n2 words and t needs to be n2*2
|
||||
*/
|
||||
void bn_mul_low_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int n2, BN_ULONG *t)
|
||||
{
|
||||
int n = n2 / 2;
|
||||
|
||||
bn_mul_recursive(r, a, b, n, 0, 0, &(t[0]));
|
||||
if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) {
|
||||
bn_mul_low_recursive(&(t[0]), &(a[0]), &(b[n]), n, &(t[n2]));
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
|
||||
bn_mul_low_recursive(&(t[0]), &(a[n]), &(b[0]), n, &(t[n2]));
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
|
||||
} else {
|
||||
bn_mul_low_normal(&(t[0]), &(a[0]), &(b[n]), n);
|
||||
bn_mul_low_normal(&(t[n]), &(a[n]), &(b[0]), n);
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[0]), n);
|
||||
bn_add_words(&(r[n]), &(r[n]), &(t[n]), n);
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_SMALL_FOOTPRINT */
|
||||
|
||||
/*
|
||||
* This function doesn't zero out the rest of r in case of nr>na+nb;
|
||||
* it's the calling function's responsibility to do so.
|
||||
*/
|
||||
void bn_mul_truncated(BN_ULONG *r, int nr, const BN_ULONG *a, int na,
|
||||
const BN_ULONG *b, int nb)
|
||||
{
|
||||
BN_ULONG tmp, *carryp = NULL;
|
||||
int n; /* Number of words to use in the current iteration */
|
||||
|
||||
if (na < nb) {
|
||||
int itmp;
|
||||
const BN_ULONG *ltmp;
|
||||
|
||||
itmp = na;
|
||||
na = nb;
|
||||
nb = itmp;
|
||||
ltmp = a;
|
||||
a = b;
|
||||
b = ltmp;
|
||||
}
|
||||
n = (na < nr) ? na : nr;
|
||||
if (nb <= 0) {
|
||||
(void)bn_mul_words(r, a, n, 0);
|
||||
return;
|
||||
} else {
|
||||
carryp = (na < nr) ? &r[na] : &tmp;
|
||||
*carryp = bn_mul_words(r, a, n, b[0]);
|
||||
}
|
||||
|
||||
for (int i = 1; i < nb && i < nr; i++) {
|
||||
int rspace = nr - i;
|
||||
n = (na < rspace) ? na : rspace;
|
||||
carryp = (na < rspace) ? &r[i + na] : &tmp;
|
||||
*carryp = bn_mul_add_words(&(r[i]), a, n, b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, int na, const BN_ULONG *b,
|
||||
int nb)
|
||||
{
|
||||
bn_mul_truncated(r, na + nb, a, na, b, nb);
|
||||
}
|
||||
|
||||
void bn_mul_low_normal(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)
|
||||
{
|
||||
bn_mul_words(r, a, n, b[0]);
|
||||
|
||||
for (;;) {
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[1]), a, n, b[1]);
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[2]), a, n, b[2]);
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[3]), a, n, b[3]);
|
||||
if (--n <= 0)
|
||||
return;
|
||||
bn_mul_add_words(&(r[4]), a, n, b[4]);
|
||||
r += 4;
|
||||
b += 4;
|
||||
}
|
||||
}
|
||||
155
crypto/bn/bnw_sub.c
Normal file
155
crypto/bn/bnw_sub.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "bn_local.h"
|
||||
|
||||
#if defined(OPENSSL_NO_ASM) || !defined(OPENSSL_BN_ASM_PART_WORDS)
|
||||
/*
|
||||
* Here follows specialised variants of bn_add_words() and bn_sub_words().
|
||||
* They have the property performing operations on arrays of different sizes.
|
||||
* The sizes of those arrays is expressed through cl, which is the common
|
||||
* length ( basically, min(len(a),len(b)) ), and dl, which is the delta
|
||||
* between the two lengths, calculated as len(a)-len(b). All lengths are the
|
||||
* number of BN_ULONGs... For the operations that require a result array as
|
||||
* parameter, it must have the length cl+abs(dl).
|
||||
*
|
||||
* These functions should probably end up in bn_asm.c as soon as there are
|
||||
* assembler counterparts for the systems that use assembler files.
|
||||
*/
|
||||
|
||||
BN_ULONG bn_sub_part_words(BN_ULONG *r,
|
||||
const BN_ULONG *a, const BN_ULONG *b,
|
||||
int cl, int dl)
|
||||
{
|
||||
BN_ULONG c, t;
|
||||
|
||||
assert(cl >= 0);
|
||||
c = bn_sub_words(r, a, b, cl);
|
||||
|
||||
if (dl == 0)
|
||||
return c;
|
||||
|
||||
r += cl;
|
||||
a += cl;
|
||||
b += cl;
|
||||
|
||||
if (dl < 0) {
|
||||
for (;;) {
|
||||
t = b[0];
|
||||
r[0] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
t = b[1];
|
||||
r[1] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
t = b[2];
|
||||
r[2] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
t = b[3];
|
||||
r[3] = (0 - t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 1;
|
||||
if (++dl >= 0)
|
||||
break;
|
||||
|
||||
b += 4;
|
||||
r += 4;
|
||||
}
|
||||
} else {
|
||||
int save_dl = dl;
|
||||
while (c) {
|
||||
t = a[0];
|
||||
r[0] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
t = a[1];
|
||||
r[1] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
t = a[2];
|
||||
r[2] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
t = a[3];
|
||||
r[3] = (t - c) & BN_MASK2;
|
||||
if (t != 0)
|
||||
c = 0;
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
save_dl = dl;
|
||||
a += 4;
|
||||
r += 4;
|
||||
}
|
||||
if (dl > 0) {
|
||||
if (save_dl > dl) {
|
||||
switch (save_dl - dl) {
|
||||
case 1:
|
||||
r[1] = a[1];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
/* fall through */
|
||||
case 2:
|
||||
r[2] = a[2];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
/* fall through */
|
||||
case 3:
|
||||
r[3] = a[3];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
}
|
||||
a += 4;
|
||||
r += 4;
|
||||
}
|
||||
}
|
||||
if (dl > 0) {
|
||||
for (;;) {
|
||||
r[0] = a[0];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
r[1] = a[1];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
r[2] = a[2];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
r[3] = a[3];
|
||||
if (--dl <= 0)
|
||||
break;
|
||||
|
||||
a += 4;
|
||||
r += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -105,11 +105,18 @@ IF[{- !$disabled{asm} -}]
|
|||
ENDIF
|
||||
ENDIF
|
||||
|
||||
$COMMON=bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c \
|
||||
$COMMON_BN=bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c \
|
||||
bn_mod.c bn_conv.c bn_rand.c bn_shift.c bn_word.c bn_blind.c \
|
||||
bn_kron.c bn_sqrt.c bn_gcd.c bn_prime.c bn_sqr.c \
|
||||
bn_recp.c bn_mont.c bn_mpi.c bn_exp2.c bn_gf2m.c bn_nist.c \
|
||||
bn_intern.c bn_dh.c bn_rsa_fips186_5.c bn_const.c
|
||||
# bnw_*.c is a growing collection of files with routines that operate on
|
||||
# BN_ULONG only. They were helper routines dispersed in bn_*.c, and are
|
||||
# often routines that don't have an assembler implementation, and therefore
|
||||
# didn't fit into bn_asm.c.
|
||||
$COMMON_BNW=bnw_sub.c bnw_mul.c
|
||||
$COMMON=$COMMON_BN $COMMON_BNW
|
||||
|
||||
SOURCE[../../libcrypto]=$COMMON $BNASM bn_print.c bn_err.c bn_srp.c
|
||||
DEFINE[../../libcrypto]=$BNDEF
|
||||
IF[{- !$disabled{'deprecated-0.9.8'} -}]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ SUBDIRS=objects buffer bio stack lhash hashtable rand evp asn1 pem x509 conf \
|
|||
txt_db pkcs7 pkcs12 ui kdf store property \
|
||||
md2 md4 md5 sha mdc2 ml_kem hmac ripemd whrlpool poly1305 \
|
||||
siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
|
||||
seed sm4 chacha modes bn ec rsa dsa dh sm2 dso \
|
||||
seed sm4 chacha modes fn bn ec rsa dsa dh sm2 dso \
|
||||
err comp http ocsp cms ts srp cmac ct async ess crmf cmp encode_decode \
|
||||
ffc hpke thread lms ml_dsa slh_dsa
|
||||
|
||||
|
|
@ -99,7 +99,8 @@ $UTIL_COMMON=\
|
|||
threads_pthread.c threads_win.c threads_none.c threads_common.c \
|
||||
initthread.c context.c sparse_array.c asn1_dsa.c packet.c \
|
||||
param_build.c param_build_set.c der_writer.c threads_lib.c \
|
||||
params_dup.c time.c array_alloc.c aligned_alloc.c deterministic_nonce.c
|
||||
params_dup.c time.c array_alloc.c aligned_alloc.c deterministic_nonce.c \
|
||||
int.c
|
||||
|
||||
SOURCE[../libcrypto]=$UTIL_COMMON \
|
||||
mem.c mem_sec.c \
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "crypto/cryptoerr.h"
|
||||
#include "crypto/asn1err.h"
|
||||
#include "crypto/bnerr.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "crypto/ecerr.h"
|
||||
#include "crypto/buffererr.h"
|
||||
#include "crypto/bioerr.h"
|
||||
|
|
@ -51,6 +52,7 @@ int ossl_err_load_crypto_strings(void)
|
|||
#ifndef OPENSSL_NO_ERR
|
||||
|| ossl_err_load_ERR_strings() == 0 /* include error strings for SYSerr */
|
||||
|| ossl_err_load_BN_strings() == 0
|
||||
|| ossl_err_load_OSSL_FN_strings() == 0
|
||||
|| ossl_err_load_RSA_strings() == 0
|
||||
#ifndef OPENSSL_NO_DH
|
||||
|| ossl_err_load_DH_strings() == 0
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ L PROV include/openssl/proverr.h providers/common/provider_err.c
|
|||
L OSSL_ENCODER include/openssl/encodererr.h crypto/encode_decode/encoder_err.c include/crypto/encodererr.h
|
||||
L OSSL_DECODER include/openssl/decodererr.h crypto/encode_decode/decoder_err.c include/crypto/decodererr.h
|
||||
L HTTP include/openssl/httperr.h crypto/http/http_err.c include/crypto/httperr.h
|
||||
L OSSL_FN NONE crypto/fn/fn_err.c include/crypto/fnerr.h
|
||||
|
||||
# SSL/TLS alerts
|
||||
R SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE 1010
|
||||
|
|
|
|||
|
|
@ -888,6 +888,13 @@ OSSL_ENCODER_R_ENCODER_NOT_FOUND:101:encoder not found
|
|||
OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY:100:incorrect property query
|
||||
OSSL_ENCODER_R_MISSING_GET_PARAMS:102:missing get params
|
||||
OSSL_ENCODER_R_UNKNOWN_PARAMETER_NAME:104:unknown parameter name
|
||||
OSSL_FN_R_DIV_BY_ZERO:101:div by zero
|
||||
OSSL_FN_R_INPUT_NOT_REDUCED:103:input not reduced
|
||||
OSSL_FN_R_BITS_TOO_SMALL:105:bits too small
|
||||
OSSL_FN_R_INVALID_RANGE:106:invalid range
|
||||
OSSL_FN_R_INVALID_SHIFT:102:invalid shift
|
||||
OSSL_FN_R_RESULT_ARG_TOO_SMALL:100:result arg too small
|
||||
OSSL_FN_R_TOO_MANY_ITERATIONS:107:too many iterations
|
||||
OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE:107:ambiguous content type
|
||||
OSSL_STORE_R_BAD_PASSWORD_READ:115:bad password read
|
||||
OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC:113:error verifying pkcs12 mac
|
||||
|
|
|
|||
9
crypto/fn/build.info
Normal file
9
crypto/fn/build.info
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
$LIBCRYPTO=../../libcrypto
|
||||
$LIBFIPS=../../providers/libfips.a
|
||||
LIBS=$LIBCRYPTO
|
||||
|
||||
$COMMON=fn_err.c fn_lib.c fn_ctx.c fn_intern.c fn_addsub.c fn_shift.c fn_mul.c \
|
||||
fn_sqr.c fn_div.c fn_rand.c fn_mod.c
|
||||
|
||||
SOURCE[$LIBCRYPTO]=$COMMON
|
||||
SOURCE[$LIBFIPS]=$COMMON
|
||||
343
crypto/fn/fn_addsub.c
Normal file
343
crypto/fn/fn_addsub.c
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "../bn/bn_local.h" /* For using the low level bignum functions */
|
||||
#include "fn_local.h"
|
||||
|
||||
/*
|
||||
* ossl_fn_add_words and ossl_fn_sub_words perform fixed-width unsigned
|
||||
* addition and subtraction of multi-limb integers.
|
||||
*
|
||||
* The carry or borrow is always propagated through every limb of both
|
||||
* operands (and through any extra result limbs when rl exceeds the operand
|
||||
* sizes). The operation is effectively performed at the precision of the
|
||||
* wider operand, then truncated to rl limbs — analogous to performing an
|
||||
* unsigned operation in the wider of the operand types and then casting
|
||||
* the result to a narrower type.
|
||||
*
|
||||
* The returned carry (addition) or borrow (subtraction) is the true
|
||||
* overflow / borrow out of the most significant processed limb:
|
||||
*
|
||||
* - When rl <= max(al, bl), it is the carry / borrow out of max(al, bl)
|
||||
* limbs. Note that this does NOT indicate whether the result fits in
|
||||
* rl limbs; non-zero high limbs may have been truncated without
|
||||
* generating a carry. If the caller needs the exact magnitude, rl
|
||||
* must be at least max(al, bl).
|
||||
*
|
||||
* - For addition, when rl > max(al, bl), the carry is absorbed into the
|
||||
* result (written to r[max(al,bl)], higher limbs zeroed) and the
|
||||
* function returns 0.
|
||||
*
|
||||
* - For subtraction, when rl > max(al, bl), the borrow is propagated
|
||||
* through all remaining result limbs (two's complement sign extension)
|
||||
* and the function returns the borrow out of rl limbs.
|
||||
*/
|
||||
|
||||
/* unsigned addition of a and b, returns carry if there is one past the result size */
|
||||
OSSL_FN_ULONG ossl_fn_add_words(OSSL_FN_ULONG *r, size_t rl,
|
||||
const OSSL_FN_ULONG *a, size_t al,
|
||||
const OSSL_FN_ULONG *b, size_t bl)
|
||||
{
|
||||
/*
|
||||
* Addition is commutative, so we switch 'a' and 'b' around to
|
||||
* ensure that 'a' is physically the largest, so a maximum of
|
||||
* work is done with 'bn_add_words'
|
||||
*/
|
||||
if (al < bl) {
|
||||
const OSSL_FN_ULONG *tmp;
|
||||
size_t tmpl;
|
||||
|
||||
tmp = a;
|
||||
tmpl = al;
|
||||
a = b;
|
||||
al = bl;
|
||||
b = tmp;
|
||||
bl = tmpl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Four stages.
|
||||
*
|
||||
* For each stage, |stage_limbs| is used to hold the number
|
||||
* of limbs being treated in that stage, |i| is used as an
|
||||
* index into the arrays, and |carry| is used to transport
|
||||
* the carry from one stage to the other.
|
||||
*
|
||||
* Note: |stage_limbs| is passed cast to 'int' when calling
|
||||
* bn_add_words(). This is fine because the maximum size of
|
||||
* any OSSL_FN_ULONG is BN_MAX_WORDS, which is small enough.
|
||||
* Should that change some day, there's trouble ahead.
|
||||
*/
|
||||
size_t stage_limbs;
|
||||
OSSL_FN_ULONG carry;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Stage 1: calculate the least min(rl,bl) limbs
|
||||
*
|
||||
* This uses bn_add_words, with what performance benefits that gives.
|
||||
*/
|
||||
|
||||
stage_limbs = (bl > rl) ? rl : bl;
|
||||
carry = bn_add_words(r, a, b, (int)stage_limbs);
|
||||
|
||||
/* Record the array position past what bn_add_words calculated */
|
||||
i = stage_limbs;
|
||||
|
||||
/*
|
||||
* Stage 2: calculate min(rl,bl) to bl limbs
|
||||
*
|
||||
* Because this loop only engages when rl < bl, it cannot affect r.
|
||||
* The only purpose of this loop is to propagate carry in this particular
|
||||
* scenario.
|
||||
*/
|
||||
|
||||
stage_limbs = bl - stage_limbs;
|
||||
|
||||
for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
|
||||
OSSL_FN_ULONG t1, t2;
|
||||
|
||||
t1 = (a[i] + carry) & OSSL_FN_MASK;
|
||||
carry = (t1 < carry);
|
||||
t2 = (b[i] + t1) & OSSL_FN_MASK;
|
||||
carry |= (t2 < t1);
|
||||
}
|
||||
|
||||
assert(i == bl);
|
||||
|
||||
/*
|
||||
* Stage 3: calculate bl to al limbs
|
||||
*
|
||||
* Note: at any time, the end of r may be reached. This is solved
|
||||
* with a temporary pointer that's set appropriately inside the loop.
|
||||
*/
|
||||
|
||||
stage_limbs = al - bl;
|
||||
|
||||
for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
|
||||
OSSL_FN_ULONG tmp = 0;
|
||||
OSSL_FN_ULONG *rp = (i < rl) ? &r[i] : &tmp;
|
||||
OSSL_FN_ULONG t1;
|
||||
|
||||
t1 = (a[i] + carry) & OSSL_FN_MASK;
|
||||
carry = (t1 < carry);
|
||||
|
||||
*rp = t1;
|
||||
}
|
||||
|
||||
assert(i == al);
|
||||
|
||||
/* If |r| is exhausted, there's nothing more to do */
|
||||
if (i >= rl)
|
||||
return carry;
|
||||
|
||||
/*
|
||||
* Stage 4: calculate a final carry, for when rl > al
|
||||
*
|
||||
* This is relatively simple, compare to earlier loops.
|
||||
*/
|
||||
|
||||
stage_limbs = rl - al;
|
||||
|
||||
for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
|
||||
r[i] = carry;
|
||||
carry = 0;
|
||||
}
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
int OSSL_FN_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b)
|
||||
{
|
||||
(void)ossl_fn_add_words(r->d, r->dsize, a->d, a->dsize, b->d, b->dsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Adds the single-limb word |w| to |a| in place, propagating the carry
|
||||
* through |a|'s limbs and truncating any carry out past a->dsize (OSSL_FN is
|
||||
* fixed-size, so a carry past the last limb is discarded rather than grown
|
||||
* into). The degenerate w == 0 case is a no-op.
|
||||
*
|
||||
* Not constant-time: the carry-propagation loop stops early once the carry
|
||||
* is exhausted, so the number of limbs touched depends on the operand's
|
||||
* value.
|
||||
*/
|
||||
int OSSL_FN_add_word(OSSL_FN *a, OSSL_FN_ULONG w)
|
||||
{
|
||||
size_t i;
|
||||
size_t dsize = (size_t)a->dsize;
|
||||
|
||||
if (w == 0)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < dsize && w != 0; i++) {
|
||||
OSSL_FN_ULONG l = (a->d[i] + w) & OSSL_FN_MASK;
|
||||
|
||||
a->d[i] = l;
|
||||
w = (w > l);
|
||||
}
|
||||
/* Any remaining carry out past dsize is truncated. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* unsigned subtraction of b from a, returns borrow if there is one past the result size */
|
||||
OSSL_FN_ULONG ossl_fn_sub_words(OSSL_FN_ULONG *r, size_t rl,
|
||||
const OSSL_FN_ULONG *a, size_t al,
|
||||
const OSSL_FN_ULONG *b, size_t bl)
|
||||
{
|
||||
size_t max = (al >= bl) ? al : bl;
|
||||
size_t min = (al <= bl) ? al : bl;
|
||||
|
||||
/*
|
||||
* Four stages.
|
||||
*
|
||||
* For each stage, |stage_limbs| is used to hold the number
|
||||
* of limbs being treated in that stage, |i| is used as an
|
||||
* index into the arrays, and |borrow| is used to transport
|
||||
* the borrow from one stage to the other.
|
||||
*
|
||||
* Note: |stage_limbs| is passed cast to 'int' when calling
|
||||
* bn_sub_words(). This is fine because the maximum size of
|
||||
* any OSSL_FN_ULONG is BN_MAX_WORDS, which is small enough.
|
||||
* Should that change some day, there's trouble ahead.
|
||||
*/
|
||||
size_t stage_limbs;
|
||||
OSSL_FN_ULONG borrow;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Stage 1: calculate the least min(rl,al,bl) limbs
|
||||
*
|
||||
* This uses bn_sub_words, with what performance benefits that gives.
|
||||
*/
|
||||
|
||||
stage_limbs = (min > rl) ? rl : min;
|
||||
borrow = bn_sub_words(r, a, b, (int)stage_limbs);
|
||||
|
||||
/* Record the array position past what bn_sub_words calculated */
|
||||
i = stage_limbs;
|
||||
|
||||
/*
|
||||
* Stage 2: calculate the min(rl,al,bl) to min(al,bl) limbs
|
||||
*
|
||||
* Because this loop only engages when rl < min(al,bl), it cannot affect r.
|
||||
* The only purpose of this loop is to propagate borrow in this particular
|
||||
* scenario.
|
||||
*/
|
||||
|
||||
stage_limbs = min - stage_limbs;
|
||||
|
||||
for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
|
||||
OSSL_FN_ULONG t1, t2;
|
||||
|
||||
t1 = a[i];
|
||||
t2 = (t1 - borrow) & OSSL_FN_MASK;
|
||||
borrow = (t2 > t1);
|
||||
t1 = b[i];
|
||||
t1 = (t2 - t1) & OSSL_FN_MASK;
|
||||
borrow |= (t1 > t2);
|
||||
}
|
||||
|
||||
assert(i == min);
|
||||
|
||||
/*
|
||||
* Stage 3: calculate the min(al,bl) to max(al,bl) limbs
|
||||
*
|
||||
* Note: at any time, the end of r may be reached. This is solved
|
||||
* with a temporary pointer that's set appropriately inside the loop.
|
||||
*/
|
||||
|
||||
const OSSL_FN_ULONG *maxp = (al >= bl) ? a : b;
|
||||
const OSSL_FN_ULONG s2_mask1 = (al >= bl) ? OSSL_FN_MASK : 0;
|
||||
const OSSL_FN_ULONG s2_mask2 = ~s2_mask1;
|
||||
|
||||
stage_limbs = max - min;
|
||||
|
||||
/* calculate the result of borrowing from more significant limbs */
|
||||
for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
|
||||
OSSL_FN_ULONG tmp = 0;
|
||||
OSSL_FN_ULONG *rp = (i < rl) ? &r[i] : &tmp;
|
||||
OSSL_FN_ULONG t1, t2;
|
||||
|
||||
t1 = maxp[i] & s2_mask1;
|
||||
t2 = (t1 - borrow) & OSSL_FN_MASK;
|
||||
borrow = (t2 > t1);
|
||||
t1 = maxp[i] & s2_mask2;
|
||||
t1 = (t2 - t1) & OSSL_FN_MASK;
|
||||
borrow |= (t1 > t2);
|
||||
|
||||
*rp = t1;
|
||||
}
|
||||
|
||||
assert(i == max);
|
||||
|
||||
/* If |r| is exhausted, there's nothing more to do */
|
||||
if (i >= rl)
|
||||
return borrow;
|
||||
|
||||
/*
|
||||
* Stage 4: calculate a final borrow, for when rl > max
|
||||
*
|
||||
* This is relatively simple, compare to earlier loops.
|
||||
*/
|
||||
|
||||
stage_limbs = rl - max;
|
||||
|
||||
/* Finally, fill in the rest of the result array by borrowing from zeros */
|
||||
for (size_t dif = stage_limbs; dif > 0; dif--, i++) {
|
||||
OSSL_FN_ULONG t1 = (0 - borrow) & OSSL_FN_MASK;
|
||||
|
||||
borrow = (t1 > 0);
|
||||
|
||||
r[i] = t1;
|
||||
}
|
||||
|
||||
return borrow;
|
||||
}
|
||||
|
||||
int OSSL_FN_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b)
|
||||
{
|
||||
(void)ossl_fn_sub_words(r->d, r->dsize, a->d, a->dsize, b->d, b->dsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Subtracts the single-limb word |w| from |a| in place, propagating the
|
||||
* borrow through |a|'s limbs. If the borrow runs past a->dsize (i.e. the
|
||||
* unsigned value of |a| is less than |w|), the result is the 2's-complement
|
||||
* wrap-around truncated to dsize, per OSSL_FN's fixed-size unsigned
|
||||
* semantics: there is no sign to record, so the wrapped value is kept. The
|
||||
* degenerate w == 0 case is a no-op.
|
||||
*
|
||||
* Not constant-time: the borrow-propagation loop returns early once the
|
||||
* borrow is repaid, so the number of limbs touched depends on the operand's
|
||||
* value.
|
||||
*/
|
||||
int OSSL_FN_sub_word(OSSL_FN *a, OSSL_FN_ULONG w)
|
||||
{
|
||||
size_t i;
|
||||
size_t dsize = (size_t)a->dsize;
|
||||
|
||||
if (w == 0)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < dsize; i++) {
|
||||
if (a->d[i] >= w) {
|
||||
a->d[i] -= w;
|
||||
return 1; /* borrow repaid */
|
||||
}
|
||||
a->d[i] = (a->d[i] - w) & OSSL_FN_MASK;
|
||||
w = 1;
|
||||
}
|
||||
/* Borrow out past dsize is truncated (2's complement). */
|
||||
return 1;
|
||||
}
|
||||
253
crypto/fn/fn_ctx.c
Normal file
253
crypto/fn/fn_ctx.c
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "internal/safe_math.h"
|
||||
#include "crypto/fn.h"
|
||||
#include "fn_local.h"
|
||||
|
||||
OSSL_SAFE_MATH_ADDU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
|
||||
OSSL_SAFE_MATH_MULU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
|
||||
|
||||
/*
|
||||
* An OSSL_FN_CTX is a large pre-allocated chunk of memory that can be used
|
||||
* to quickly allocate OSSL_FN instances. The organization of memory is as
|
||||
* a fairly typical arena, where OSSL_FN instances are "stacked" one after
|
||||
* the other.
|
||||
*
|
||||
* However, there is also the concept of frames, which are arenas within an
|
||||
* arena. This allows easily passing an OSSL_FN_CTX to a function, and for
|
||||
* that function to allocate such a frame for itself, and easily deallocate
|
||||
* it when it's done.
|
||||
*/
|
||||
|
||||
size_t OSSL_FN_CTX_size(size_t max_n_frames, size_t max_n_numbers,
|
||||
size_t max_n_limbs)
|
||||
{
|
||||
int err = 0;
|
||||
size_t frames, numbers, limbs, total;
|
||||
|
||||
/*
|
||||
* A context always needs at least one frame, since every use of an
|
||||
* OSSL_FN_CTX calls OSSL_FN_CTX_start(), which carves out a frame.
|
||||
*/
|
||||
if (max_n_frames == 0)
|
||||
return 0;
|
||||
/*
|
||||
* Number-header and limb budgets must both be present or both absent.
|
||||
* OSSL_FN_CTX_get_limbs() allocates an OSSL_FN header and its limbs
|
||||
* together, so a context with one budget but not the other can never
|
||||
* produce a usable number.
|
||||
*/
|
||||
if ((max_n_numbers == 0) != (max_n_limbs == 0))
|
||||
return 0;
|
||||
|
||||
frames = safe_mul_size_t(max_n_frames,
|
||||
sizeof(struct ossl_fn_ctx_frame_st), &err);
|
||||
numbers = safe_mul_size_t(max_n_numbers, sizeof(OSSL_FN), &err);
|
||||
limbs = safe_mul_size_t(max_n_limbs, OSSL_FN_BYTES, &err);
|
||||
total = safe_add_size_t(frames, numbers, &err);
|
||||
total = safe_add_size_t(total, limbs, &err);
|
||||
|
||||
return err == 0 ? total : 0;
|
||||
}
|
||||
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
|
||||
size_t max_n_numbers, size_t max_n_limbs)
|
||||
{
|
||||
return OSSL_FN_CTX_new_size(libctx,
|
||||
OSSL_FN_CTX_size(max_n_frames, max_n_numbers, max_n_limbs));
|
||||
}
|
||||
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_new_size(OSSL_LIB_CTX *libctx, size_t size)
|
||||
{
|
||||
size_t total_size;
|
||||
OSSL_FN_CTX *ctx;
|
||||
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* A size of 0 is the error return of OSSL_FN_CTX_size() (and the
|
||||
* per-operation ctx-size helpers). Treat it as an error here too, so a
|
||||
* caller does not get back a context with a zero-size arena that it
|
||||
* would then hand to an operation expecting usable scratch space.
|
||||
*/
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
total_size = safe_add_size_t(sizeof(*ctx), size, &err);
|
||||
if (err != 0)
|
||||
return NULL;
|
||||
|
||||
ctx = OPENSSL_zalloc(total_size);
|
||||
|
||||
if (ctx != NULL)
|
||||
ctx->msize = size;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_secure_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
|
||||
size_t max_n_numbers, size_t max_n_limbs)
|
||||
{
|
||||
return OSSL_FN_CTX_secure_new_size(libctx,
|
||||
OSSL_FN_CTX_size(max_n_frames, max_n_numbers, max_n_limbs));
|
||||
}
|
||||
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_secure_new_size(OSSL_LIB_CTX *libctx, size_t size)
|
||||
{
|
||||
size_t total_size;
|
||||
OSSL_FN_CTX *ctx;
|
||||
|
||||
int err = 0;
|
||||
|
||||
/* As in OSSL_FN_CTX_new_size(), a size of 0 is an error. */
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
total_size = safe_add_size_t(sizeof(*ctx), size, &err);
|
||||
if (err != 0)
|
||||
return NULL;
|
||||
|
||||
ctx = OPENSSL_secure_zalloc(total_size);
|
||||
|
||||
if (ctx != NULL) {
|
||||
ctx->msize = size;
|
||||
ctx->is_securely_allocated = 1;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void OSSL_FN_CTX_peak_usage(const OSSL_FN_CTX *ctx, size_t *peak_n_frames,
|
||||
size_t *peak_n_numbers, size_t *peak_n_limbs)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
if (peak_n_frames != NULL)
|
||||
*peak_n_frames = 0;
|
||||
if (peak_n_numbers != NULL)
|
||||
*peak_n_numbers = 0;
|
||||
if (peak_n_limbs != NULL)
|
||||
*peak_n_limbs = 0;
|
||||
return;
|
||||
}
|
||||
if (peak_n_frames != NULL)
|
||||
*peak_n_frames = ctx->peak_n_frames;
|
||||
if (peak_n_numbers != NULL)
|
||||
*peak_n_numbers = ctx->peak_n_numbers;
|
||||
if (peak_n_limbs != NULL)
|
||||
*peak_n_limbs = ctx->peak_n_limbs;
|
||||
}
|
||||
|
||||
void OSSL_FN_CTX_free(OSSL_FN_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
assert(ctx->last_frame == NULL);
|
||||
|
||||
if (ctx->is_securely_allocated)
|
||||
OPENSSL_secure_free(ctx);
|
||||
else
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
const void *OSSL_FN_CTX_start(OSSL_FN_CTX *ctx)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL))
|
||||
return NULL;
|
||||
|
||||
struct ossl_fn_ctx_frame_st *last_frame = ctx->last_frame;
|
||||
size_t used = (last_frame == NULL) ? 0 : last_frame->free_memory - ctx->memory;
|
||||
|
||||
if (ctx->msize - used < sizeof(struct ossl_fn_ctx_frame_st))
|
||||
return NULL;
|
||||
|
||||
if (ctx->last_frame == NULL)
|
||||
ctx->last_frame = (struct ossl_fn_ctx_frame_st *)ctx->memory;
|
||||
else
|
||||
ctx->last_frame = (struct ossl_fn_ctx_frame_st *)last_frame->free_memory;
|
||||
|
||||
struct ossl_fn_ctx_frame_st *frame = ctx->last_frame;
|
||||
frame->arena = ctx;
|
||||
frame->previous_frame = last_frame;
|
||||
frame->free_memory = frame->memory;
|
||||
frame->msize = ctx->msize - used - sizeof(*frame);
|
||||
frame->n_numbers = 0;
|
||||
frame->n_limbs = 0;
|
||||
|
||||
ctx->n_frames++;
|
||||
if (ctx->n_frames > ctx->peak_n_frames)
|
||||
ctx->peak_n_frames = ctx->n_frames;
|
||||
|
||||
return ctx->last_frame;
|
||||
}
|
||||
|
||||
int OSSL_FN_CTX_end(OSSL_FN_CTX *ctx, const void *token)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL) || !ossl_assert(ctx->last_frame != NULL))
|
||||
return 0;
|
||||
|
||||
struct ossl_fn_ctx_frame_st *last_frame = ctx->last_frame;
|
||||
|
||||
if (last_frame != token)
|
||||
return 0;
|
||||
|
||||
ctx->n_numbers -= last_frame->n_numbers;
|
||||
ctx->n_limbs -= last_frame->n_limbs;
|
||||
ctx->n_frames--;
|
||||
ctx->last_frame = last_frame->previous_frame;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_CTX_get_limbs(OSSL_FN_CTX *ctx, size_t limbs)
|
||||
{
|
||||
if (!ossl_assert(ctx != NULL))
|
||||
return NULL;
|
||||
|
||||
struct ossl_fn_ctx_frame_st *frame = ctx->last_frame;
|
||||
|
||||
if (!ossl_assert(frame != NULL))
|
||||
return NULL;
|
||||
|
||||
size_t totalsize = ossl_fn_totalsize(limbs);
|
||||
size_t used = frame->free_memory - frame->memory;
|
||||
if (totalsize == 0 || frame->msize - used < totalsize)
|
||||
return NULL;
|
||||
|
||||
OSSL_FN *fn = (OSSL_FN *)frame->free_memory;
|
||||
frame->free_memory += totalsize;
|
||||
frame->n_numbers++;
|
||||
frame->n_limbs += limbs;
|
||||
|
||||
ctx->n_numbers++;
|
||||
ctx->n_limbs += limbs;
|
||||
if (ctx->n_numbers > ctx->peak_n_numbers)
|
||||
ctx->peak_n_numbers = ctx->n_numbers;
|
||||
if (ctx->n_limbs > ctx->peak_n_limbs)
|
||||
ctx->peak_n_limbs = ctx->n_limbs;
|
||||
|
||||
memset(fn, 0, totalsize);
|
||||
fn->dsize = (int)limbs;
|
||||
fn->is_securely_allocated = ctx->is_securely_allocated;
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_CTX_get_bytes(OSSL_FN_CTX *ctx, size_t bytes)
|
||||
{
|
||||
return OSSL_FN_CTX_get_limbs(ctx, ossl_fn_bytes_to_limbs(bytes));
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_CTX_get_bits(OSSL_FN_CTX *ctx, size_t bits)
|
||||
{
|
||||
return OSSL_FN_CTX_get_bytes(ctx, ossl_fn_bits_to_bytes(bits));
|
||||
}
|
||||
395
crypto/fn/fn_div.c
Normal file
395
crypto/fn/fn_div.c
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/err.h>
|
||||
#include "internal/safe_math.h"
|
||||
#include "crypto/cryptlib.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "../bn/bn_local.h" /* For using the low level bignum functions */
|
||||
#include "fn_local.h"
|
||||
|
||||
OSSL_SAFE_MATH_ADDU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
|
||||
|
||||
#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \
|
||||
&& !defined(PEDANTIC) && !defined(BN_DIV3W)
|
||||
#if defined(__GNUC__) && __GNUC__ >= 2
|
||||
#if defined(__i386) || defined(__i386__)
|
||||
/*-
|
||||
* There were two reasons for implementing this template:
|
||||
* - GNU C generates a call to a function (__udivdi3 to be exact)
|
||||
* in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail
|
||||
* to understand why...);
|
||||
* - divl doesn't only calculate quotient, but also leaves
|
||||
* remainder in %edx which we can definitely use here:-)
|
||||
*/
|
||||
#undef bn_div_words
|
||||
#define bn_div_words(n0, n1, d0) \
|
||||
({ \
|
||||
asm volatile( \
|
||||
"divl %4" \
|
||||
: "=a"(quo), "=d"(rem) \
|
||||
: "a"(n1), "d"(n0), "r"(d0) \
|
||||
: "cc"); \
|
||||
quo; \
|
||||
})
|
||||
#define REMAINDER_IS_ALREADY_CALCULATED
|
||||
#elif defined(__x86_64) && defined(SIXTY_FOUR_BIT_LONG)
|
||||
/*
|
||||
* Same story here, but it's 128-bit by 64-bit division. Wow!
|
||||
*/
|
||||
#undef bn_div_words
|
||||
#define bn_div_words(n0, n1, d0) \
|
||||
({ \
|
||||
asm volatile( \
|
||||
"divq %4" \
|
||||
: "=a"(quo), "=d"(rem) \
|
||||
: "a"(n1), "d"(n0), "r"(d0) \
|
||||
: "cc"); \
|
||||
quo; \
|
||||
})
|
||||
#define REMAINDER_IS_ALREADY_CALCULATED
|
||||
#endif /* __<cpu> */
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* OPENSSL_NO_ASM */
|
||||
|
||||
/*
|
||||
* Copy src to dst and align it to the left using lshift.
|
||||
* lshift is assumed to be less than OSSL_FN_BITS.
|
||||
*/
|
||||
static inline void copy_align_left(OSSL_FN *dst, const OSSL_FN *src, OSSL_FN_ULONG lshift)
|
||||
{
|
||||
OSSL_FN_ULONG rshift = OSSL_FN_BITS - lshift;
|
||||
OSSL_FN_ULONG rmask;
|
||||
OSSL_FN_ULONG m;
|
||||
const OSSL_FN_ULONG *s = src->d;
|
||||
size_t sl = src->dsize;
|
||||
OSSL_FN_ULONG *d = dst->d;
|
||||
size_t dl = dst->dsize;
|
||||
size_t l = (dl < sl) ? dl : sl;
|
||||
size_t i;
|
||||
|
||||
rshift %= OSSL_FN_BITS;
|
||||
|
||||
/* rmask = 0 - (rshift != 0) */
|
||||
rmask = (OSSL_FN_ULONG)0 - rshift;
|
||||
rmask |= rmask >> 8;
|
||||
|
||||
/* src and dst may be the same, that's why this loop is made this way */
|
||||
for (i = 0, m = 0; i < l; i++) {
|
||||
OSSL_FN_ULONG tmp = s[i];
|
||||
d[i] = ((tmp << lshift) | m) & OSSL_FN_MASK;
|
||||
m = (tmp >> rshift) & rmask;
|
||||
}
|
||||
|
||||
for (; i < dl; i++) {
|
||||
d[i] = m;
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy src to dst and align it to the right using rshift.
|
||||
* rshift is assumed to be less than OSSL_FN_BITS.
|
||||
*/
|
||||
static inline void copy_align_right(OSSL_FN *dst, const OSSL_FN *src, OSSL_FN_ULONG rshift)
|
||||
{
|
||||
OSSL_FN_ULONG lshift = OSSL_FN_BITS - rshift;
|
||||
OSSL_FN_ULONG lmask;
|
||||
const OSSL_FN_ULONG *s = src->d;
|
||||
size_t sl = src->dsize;
|
||||
OSSL_FN_ULONG *d = dst->d;
|
||||
size_t dl = dst->dsize;
|
||||
size_t i;
|
||||
size_t l = (dl < sl) ? dl : sl;
|
||||
|
||||
lshift %= OSSL_FN_BITS;
|
||||
|
||||
/* lmask = 0 - (lshift != 0) */
|
||||
lmask = (OSSL_FN_ULONG)0 - lshift;
|
||||
lmask |= lmask >> 8;
|
||||
|
||||
/* Just to be safe */
|
||||
for (i = dl; i-- > l;)
|
||||
d[i] = 0;
|
||||
|
||||
/*
|
||||
* m is a set of bits passed to the next limb down when shifting,
|
||||
* and needs proper bootstrapping: if the source is larger than the
|
||||
* destination, we must consider one source limb beyond the destination
|
||||
* size. If not, m is simply starts with zero.
|
||||
*/
|
||||
OSSL_FN_ULONG m = (dl < sl) ? (s[dl] << lshift) & lmask : 0;
|
||||
|
||||
/* src and dst may be the same, that's why this loop is made this way */
|
||||
for (i = l; i-- > 0;) {
|
||||
OSSL_FN_ULONG tmp = s[i];
|
||||
d[i] = m | ((tmp >> rshift) & OSSL_FN_MASK);
|
||||
m = (tmp << lshift) & lmask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline OSSL_FN_ULONG div_words(OSSL_FN_ULONG *wnumtop, OSSL_FN_ULONG *wnum,
|
||||
OSSL_FN_ULONG d1, OSSL_FN_ULONG d0)
|
||||
{
|
||||
#if defined(BN_DIV3W)
|
||||
return bn_div_3_words(wnumtop, d1, d0);
|
||||
#else
|
||||
OSSL_FN_ULONG n0 = wnumtop[0], n1 = wnumtop[-1], quo = 0, rem = 0;
|
||||
|
||||
if (n0 == d0)
|
||||
quo = OSSL_FN_MASK;
|
||||
else { /* n0 < d0 */
|
||||
OSSL_FN_ULONG n2 = (wnumtop == wnum) ? 0 : wnumtop[-2];
|
||||
#ifdef BN_LLONG
|
||||
BN_ULLONG t2;
|
||||
|
||||
#if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
|
||||
quo = (OSSL_FN_ULONG)(((((BN_ULLONG)n0) << OSSL_FN_BITS) | n1) / d0);
|
||||
#else
|
||||
quo = bn_div_words(n0, n1, d0);
|
||||
#endif
|
||||
|
||||
#ifndef REMAINDER_IS_ALREADY_CALCULATED
|
||||
/*
|
||||
* rem doesn't have to be BN_ULLONG. The least we
|
||||
* know it's less that d0, isn't it?
|
||||
*/
|
||||
rem = (n1 - quo * d0) & BN_MASK2;
|
||||
#endif
|
||||
t2 = (BN_ULLONG)d1 * quo;
|
||||
|
||||
for (;;) {
|
||||
if (t2 <= ((((BN_ULLONG)rem) << OSSL_FN_BITS) | n2))
|
||||
break;
|
||||
quo--;
|
||||
rem += d0;
|
||||
if (rem < d0)
|
||||
break; /* don't let rem overflow */
|
||||
t2 -= d1;
|
||||
}
|
||||
#else /* !BN_LLONG */
|
||||
OSSL_FN_ULONG t2l, t2h;
|
||||
|
||||
quo = bn_div_words(n0, n1, d0);
|
||||
#ifndef REMAINDER_IS_ALREADY_CALCULATED
|
||||
rem = (n1 - quo * d0) & OSSL_FN_MASK;
|
||||
#endif
|
||||
|
||||
#if defined(BN_UMULT_LOHI)
|
||||
BN_UMULT_LOHI(t2l, t2h, d1, quo);
|
||||
#elif defined(BN_UMULT_HIGH)
|
||||
t2l = d1 * quo;
|
||||
t2h = BN_UMULT_HIGH(d1, quo);
|
||||
#else
|
||||
{
|
||||
OSSL_FN_ULONG ql, qh;
|
||||
t2l = LBITS(d1);
|
||||
t2h = HBITS(d1);
|
||||
ql = LBITS(quo);
|
||||
qh = HBITS(quo);
|
||||
mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if ((t2h < rem) || ((t2h == rem) && (t2l <= n2)))
|
||||
break;
|
||||
quo--;
|
||||
rem += d0;
|
||||
if (rem < d0)
|
||||
break; /* don't let rem overflow */
|
||||
if (t2l < d1)
|
||||
t2h--;
|
||||
t2l -= d1;
|
||||
}
|
||||
#endif /* !BN_LLONG */
|
||||
}
|
||||
|
||||
return quo;
|
||||
#endif /* !BN_DIV3W */
|
||||
}
|
||||
|
||||
size_t OSSL_FN_div_ctx_size(const OSSL_FN *q, const OSSL_FN *r,
|
||||
const OSSL_FN *n, const OSSL_FN *d)
|
||||
{
|
||||
if ((q == NULL && r == NULL) || n == NULL || d == NULL)
|
||||
return 0;
|
||||
|
||||
size_t nl = n->dsize;
|
||||
size_t dl = d->dsize;
|
||||
size_t snuml, tmp;
|
||||
int err = 0;
|
||||
|
||||
snuml = safe_add_size_t(nl > dl ? nl : dl, 1, &err);
|
||||
tmp = safe_add_size_t(dl, 1, &err);
|
||||
|
||||
size_t max_ql = nl == 0 ? 1 : nl;
|
||||
size_t ql = (q == NULL || (size_t)q->dsize < max_ql) ? max_ql : 0;
|
||||
size_t max_n_numbers = 3 + (ql != 0);
|
||||
size_t max_n_limbs;
|
||||
|
||||
max_n_limbs = safe_add_size_t(snuml, dl, &err);
|
||||
max_n_limbs = safe_add_size_t(max_n_limbs, tmp, &err);
|
||||
max_n_limbs = safe_add_size_t(max_n_limbs, ql, &err);
|
||||
|
||||
return err == 0 ? OSSL_FN_CTX_size(1, max_n_numbers, max_n_limbs) : 0;
|
||||
}
|
||||
|
||||
/* Trivia: this function implements Knuth's algorithm D */
|
||||
int OSSL_FN_div(OSSL_FN *q, OSSL_FN *r, const OSSL_FN *n, const OSSL_FN *d, OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
|
||||
size_t nl = n->dsize;
|
||||
size_t dl = d->dsize;
|
||||
size_t ql = (q == NULL) ? 0 : q->dsize;
|
||||
|
||||
/*
|
||||
* We need to figure out the significant size of |d|, to avoid division by
|
||||
* zero if the highest limb(s) are zero.
|
||||
*
|
||||
* This doesn't quite give a sense that division can be constant time.
|
||||
* However, in the use cases where constant time is interesting (cryptosystems),
|
||||
* it can be argued that the denominator would have a constant enough size
|
||||
* within each cryptosystem (and size therein), so it's assumed that time
|
||||
* will be constant because of that.
|
||||
*/
|
||||
while (dl > 0 && d->d[dl - 1] == 0)
|
||||
dl--;
|
||||
|
||||
if (dl == 0) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_DIV_BY_ZERO);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because some assembler language instructions have those requirements,
|
||||
* the denominator need to be shifted "left" so the top bit is always 1.
|
||||
* To ensure that we still get correct results, the numerator will have
|
||||
* to be shifted left as many bits. The resulting quotient will end up
|
||||
* correct, but the remainder will have to be shifted "right" before the
|
||||
* end of this function.
|
||||
*/
|
||||
OSSL_FN_ULONG norm_shift = OSSL_FN_BITS - BN_num_bits_word(d->d[dl - 1]);
|
||||
|
||||
/*
|
||||
* Store a copy the numerator in snum, padded with extra zeros if nl <= dl
|
||||
* eventually, this will contain the remainder. Because it may be shifted
|
||||
* up to almost a full limb to the left (worst case scenario), an extra limb
|
||||
* need to be allocated.
|
||||
*/
|
||||
size_t snuml = ((nl <= dl) ? dl : nl) + 1;
|
||||
OSSL_FN *snum = OSSL_FN_CTX_get_limbs(ctx, snuml);
|
||||
if (!ossl_assert(snuml <= INT_MAX && snum != NULL))
|
||||
goto err;
|
||||
copy_align_left(snum, n, norm_shift);
|
||||
|
||||
/*
|
||||
* Store a copy of the denominator in sdiv, shifted left so that its top bit
|
||||
* is always 1. This is necessary to avoid gnarly arithmetic exceptions when
|
||||
* the denominator's highest limb is a very small number.
|
||||
*/
|
||||
size_t sdivl = dl;
|
||||
OSSL_FN *sdiv = OSSL_FN_CTX_get_limbs(ctx, sdivl);
|
||||
if (!ossl_assert(sdivl <= INT_MAX && sdiv != NULL))
|
||||
goto err;
|
||||
copy_align_left(sdiv, d, norm_shift);
|
||||
|
||||
/*
|
||||
* The number of times we will iterate to perform division, i.e.
|
||||
* how often we will "shift" the divisor "window" over the numerator.
|
||||
* This also determines the size of the result.
|
||||
*
|
||||
* For the math oriented:
|
||||
*
|
||||
* snuml - sdivl = ((nl <= dl) ? dl : nl) + 1 - dl
|
||||
* => snuml - sdivl = ((nl <= dl) ? 0 : nl - dl) + 1
|
||||
* => snuml - sdivl = (nl <= dl) ? 1 : nl - dl + 1
|
||||
*/
|
||||
size_t loop = snuml - sdivl;
|
||||
|
||||
/*
|
||||
* Set up the quotient. It will be stored directly in |q| if it has
|
||||
* enough space, otherwise temporary storage is allocated.
|
||||
*/
|
||||
OSSL_FN *res = (ql < loop) ? OSSL_FN_CTX_get_limbs(ctx, loop) : q;
|
||||
if (!ossl_assert(res != NULL))
|
||||
goto err;
|
||||
|
||||
/* Position of the next quotient limb to be calculated, plus one */
|
||||
OSSL_FN_ULONG *resp = &(res->d[loop]);
|
||||
|
||||
/* Intermediary storage */
|
||||
OSSL_FN *tmp = OSSL_FN_CTX_get_limbs(ctx, sdivl + 1);
|
||||
if (!ossl_assert(tmp != NULL))
|
||||
goto err;
|
||||
|
||||
/* Set up the "window" position in snum. */
|
||||
OSSL_FN_ULONG *wnum = &(snum->d[loop]);
|
||||
OSSL_FN_ULONG *wnumtop = &(snum->d[snuml - 1]);
|
||||
|
||||
/* Get the top 2 words of the denominator */
|
||||
OSSL_FN_ULONG d0 = sdiv->d[sdivl - 1];
|
||||
OSSL_FN_ULONG d1 = (sdivl == 1) ? 0 : sdiv->d[sdivl - 2];
|
||||
|
||||
size_t i;
|
||||
|
||||
/* If res is larger than the expected result, zero the limbs above */
|
||||
for (i = res->dsize; i > loop;)
|
||||
res->d[--i] = 0;
|
||||
for (i = 0; i < loop; i++, wnumtop--) {
|
||||
OSSL_FN_ULONG quo, l0;
|
||||
/*
|
||||
* the first part of the loop uses the top two words of snum and sdiv
|
||||
* to calculate a OSSL_FN_ULONG quo such that | wnum - d * q | < d
|
||||
*/
|
||||
quo = div_words(wnumtop, wnum, d1, d0);
|
||||
|
||||
l0 = bn_mul_words(tmp->d, sdiv->d, (int)sdivl, quo);
|
||||
tmp->d[sdivl] = l0;
|
||||
wnum--;
|
||||
|
||||
/*
|
||||
* ignore top values of the bignums just sub the two OSSL_FN_ULONG
|
||||
* arrays with bn_sub_words
|
||||
*/
|
||||
l0 = bn_sub_words(wnum, wnum, tmp->d, (int)sdivl + 1);
|
||||
quo -= l0;
|
||||
|
||||
/*
|
||||
* Note: As we have considered only the leading two OSSL_FN_ULONGs
|
||||
* in the calculation of q, d * q might be greater than wnum
|
||||
* (but then (q-1) * d is less than or equal to wnum)
|
||||
*/
|
||||
size_t j;
|
||||
for (l0 = 0 - l0, j = 0; j < sdivl; j++)
|
||||
tmp->d[j] = sdiv->d[j] & l0;
|
||||
l0 = bn_add_words(wnum, wnum, tmp->d, (int)sdivl);
|
||||
(*wnumtop) += l0;
|
||||
assert((*wnumtop) == 0);
|
||||
|
||||
/* store part of the result */
|
||||
*--resp = quo;
|
||||
}
|
||||
/* snum holds remainder, it's as wide as divisor */
|
||||
if (r != NULL)
|
||||
copy_align_right(r, snum, norm_shift);
|
||||
/* res holds the quotient for a total of loop limbs, and is separate from q if ql < loop */
|
||||
if (q != NULL && q != res && OSSL_FN_copy_truncate(q, res) == 0)
|
||||
goto err;
|
||||
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return 1;
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return 0;
|
||||
}
|
||||
42
crypto/fn/fn_err.c
Normal file
42
crypto/fn/fn_err.c
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include "crypto/fnerr.h"
|
||||
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
|
||||
static const ERR_STRING_DATA OSSL_FN_str_reasons[] = {
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_DIV_BY_ZERO), "div by zero" },
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_INVALID_RANGE),
|
||||
"invalid range" },
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_INPUT_NOT_REDUCED),
|
||||
"input not reduced" },
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_INVALID_SHIFT),
|
||||
"invalid shift" },
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_RESULT_ARG_TOO_SMALL),
|
||||
"result arg too small" },
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_BITS_TOO_SMALL),
|
||||
"bits too small" },
|
||||
{ ERR_PACK(ERR_LIB_OSSL_FN, 0, OSSL_FN_R_TOO_MANY_ITERATIONS),
|
||||
"too many iterations" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int ossl_err_load_OSSL_FN_strings(void)
|
||||
{
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
if (ERR_reason_error_string(OSSL_FN_str_reasons[0].error) == NULL)
|
||||
ERR_load_strings_const(OSSL_FN_str_reasons);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
56
crypto/fn/fn_intern.c
Normal file
56
crypto/fn/fn_intern.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#include "crypto/fn_intern.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "fn_local.h"
|
||||
#include <openssl/err.h>
|
||||
|
||||
int ossl_fn_set_words(OSSL_FN *f, const OSSL_FN_ULONG *words, size_t limbs)
|
||||
{
|
||||
if (ossl_unlikely(f == NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((size_t)f->dsize < limbs) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(f->d, words, sizeof(OSSL_FN_ULONG) * limbs);
|
||||
memset(f->d + limbs, 0, sizeof(OSSL_FN_ULONG) * (f->dsize - limbs));
|
||||
return 1;
|
||||
}
|
||||
|
||||
const OSSL_FN_ULONG *ossl_fn_get_words(const OSSL_FN *f)
|
||||
{
|
||||
if (ossl_unlikely(f == NULL)) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f->d;
|
||||
}
|
||||
|
||||
size_t ossl_fn_get_dsize(const OSSL_FN *f)
|
||||
{
|
||||
return f->dsize;
|
||||
}
|
||||
|
||||
bool ossl_fn_is_dynamically_allocated(const OSSL_FN *f)
|
||||
{
|
||||
return f->is_dynamically_allocated;
|
||||
}
|
||||
|
||||
bool ossl_fn_is_securely_allocated(const OSSL_FN *f)
|
||||
{
|
||||
return f->is_securely_allocated;
|
||||
}
|
||||
346
crypto/fn/fn_lib.c
Normal file
346
crypto/fn/fn_lib.c
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include "internal/common.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "fn_local.h"
|
||||
#include "internal/constant_time.h"
|
||||
|
||||
static OSSL_FN *ossl_fn_new_internal(size_t limbs, bool securely)
|
||||
{
|
||||
/* Total size of the whole OSSL_FN, in bytes */
|
||||
size_t totalsize = ossl_fn_totalsize(limbs);
|
||||
if (totalsize == 0)
|
||||
return NULL;
|
||||
|
||||
OSSL_FN *ret = NULL;
|
||||
|
||||
if (securely)
|
||||
ret = OPENSSL_secure_zalloc(totalsize);
|
||||
else
|
||||
ret = OPENSSL_zalloc(totalsize);
|
||||
|
||||
if (ret != NULL) {
|
||||
ret->dsize = (int)limbs;
|
||||
ret->is_dynamically_allocated = 1;
|
||||
ret->is_securely_allocated = securely;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ossl_fn_free_internal(OSSL_FN *f, bool clear)
|
||||
{
|
||||
if (f == NULL)
|
||||
return;
|
||||
|
||||
size_t limbssize = f->dsize * sizeof(OSSL_FN_ULONG);
|
||||
size_t totalsize = limbssize + sizeof(OSSL_FN);
|
||||
|
||||
if (f->is_dynamically_allocated) {
|
||||
if (f->is_securely_allocated)
|
||||
OPENSSL_secure_clear_free(f, totalsize);
|
||||
else if (clear)
|
||||
OPENSSL_clear_free(f, totalsize);
|
||||
else
|
||||
OPENSSL_free(f);
|
||||
} else if (clear) {
|
||||
OPENSSL_cleanse(f->d, limbssize);
|
||||
}
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_new_limbs(size_t size)
|
||||
{
|
||||
return ossl_fn_new_internal(size, false);
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_secure_new_limbs(size_t size)
|
||||
{
|
||||
return ossl_fn_new_internal(size, true);
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_new_bytes(size_t size)
|
||||
{
|
||||
return OSSL_FN_new_limbs(ossl_fn_bytes_to_limbs(size));
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_secure_new_bytes(size_t size)
|
||||
{
|
||||
return OSSL_FN_secure_new_limbs(ossl_fn_bytes_to_limbs(size));
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_new_bits(size_t size)
|
||||
{
|
||||
return OSSL_FN_new_bytes(ossl_fn_bits_to_bytes(size));
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_secure_new_bits(size_t size)
|
||||
{
|
||||
return OSSL_FN_secure_new_bytes(ossl_fn_bits_to_bytes(size));
|
||||
}
|
||||
|
||||
void OSSL_FN_free(OSSL_FN *f)
|
||||
{
|
||||
ossl_fn_free_internal(f, false);
|
||||
}
|
||||
|
||||
void OSSL_FN_clear_free(OSSL_FN *f)
|
||||
{
|
||||
ossl_fn_free_internal(f, true);
|
||||
}
|
||||
|
||||
void OSSL_FN_clear(OSSL_FN *f)
|
||||
{
|
||||
size_t limbssize = f->dsize * sizeof(OSSL_FN_ULONG);
|
||||
|
||||
OPENSSL_cleanse(f->d, limbssize);
|
||||
}
|
||||
|
||||
/*-
|
||||
* Sets a->d[0] to |w| and zeroes the remaining limbs, so the full dsize
|
||||
* array reflects the value |w|. OSSL_FN is fixed-size: if a->dsize is 0
|
||||
* there is no limb to write and the call fails with
|
||||
* OSSL_FN_R_RESULT_ARG_TOO_SMALL (the same reason ossl_fn_set_words() raises
|
||||
* for an undersized destination).
|
||||
*
|
||||
* Constant-time with respect to |w|'s value: there is no value-dependent
|
||||
* control flow, since the full dsize array always holds the value. The only
|
||||
* branch is on the operand's public width (dsize).
|
||||
*/
|
||||
int OSSL_FN_set_word(OSSL_FN *a, OSSL_FN_ULONG w)
|
||||
{
|
||||
size_t dsize = (size_t)a->dsize;
|
||||
|
||||
if (ossl_unlikely(dsize < 1)) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
a->d[0] = w;
|
||||
if (dsize > 1)
|
||||
memset(&a->d[1], 0, sizeof(OSSL_FN_ULONG) * (dsize - 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Equivalent to OSSL_FN_set_word(a, 1). Kept as a named function rather
|
||||
* than a macro or static inline, consistent with the rest of
|
||||
* crypto/fn/fn_lib.c. Leak profile as for OSSL_FN_set_word().
|
||||
*/
|
||||
int OSSL_FN_one(OSSL_FN *a)
|
||||
{
|
||||
return OSSL_FN_set_word(a, OSSL_FN_ULONG_C(1));
|
||||
}
|
||||
|
||||
/*-
|
||||
* Equivalent to OSSL_FN_set_word(a, 0). This is a plain value assignment,
|
||||
* not a secure wipe: the compiler may optimise the writes away if the value
|
||||
* is not subsequently observed. Use OSSL_FN_clear() (which calls
|
||||
* OPENSSL_cleanse()) when the limbs may hold secret data and must be wiped
|
||||
* irreversibly. Leak profile as for OSSL_FN_set_word().
|
||||
*/
|
||||
int OSSL_FN_zero(OSSL_FN *a)
|
||||
{
|
||||
return OSSL_FN_set_word(a, OSSL_FN_ULONG_C(0));
|
||||
}
|
||||
|
||||
static size_t ossl_fn_num_bits_word(OSSL_FN_ULONG l)
|
||||
{
|
||||
OSSL_FN_ULONG x, mask;
|
||||
size_t bits = (size_t)constant_time_select_int(
|
||||
(unsigned int)constant_time_is_zero_bn(l), 0, 1);
|
||||
|
||||
#if OSSL_FN_BITS > 32
|
||||
x = l >> 32;
|
||||
mask = ~constant_time_is_zero_bn(x);
|
||||
bits += 32 & (size_t)mask;
|
||||
l ^= (x ^ l) & mask;
|
||||
#endif
|
||||
|
||||
x = l >> 16;
|
||||
mask = ~constant_time_is_zero_bn(x);
|
||||
bits += 16 & (size_t)mask;
|
||||
l ^= (x ^ l) & mask;
|
||||
|
||||
x = l >> 8;
|
||||
mask = ~constant_time_is_zero_bn(x);
|
||||
bits += 8 & (size_t)mask;
|
||||
l ^= (x ^ l) & mask;
|
||||
|
||||
x = l >> 4;
|
||||
mask = ~constant_time_is_zero_bn(x);
|
||||
bits += 4 & (size_t)mask;
|
||||
l ^= (x ^ l) & mask;
|
||||
|
||||
x = l >> 2;
|
||||
mask = ~constant_time_is_zero_bn(x);
|
||||
bits += 2 & (size_t)mask;
|
||||
l ^= (x ^ l) & mask;
|
||||
|
||||
x = l >> 1;
|
||||
mask = ~constant_time_is_zero_bn(x);
|
||||
bits += 1 & (size_t)mask;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
size_t OSSL_FN_num_bits(const OSSL_FN *a)
|
||||
{
|
||||
size_t i;
|
||||
size_t dsize = (size_t)a->dsize;
|
||||
size_t ret = 0;
|
||||
|
||||
for (i = 0; i < dsize; i++) {
|
||||
size_t limb_bits = ossl_fn_num_bits_word(a->d[i]);
|
||||
size_t bits = i * OSSL_FN_BITS + limb_bits;
|
||||
size_t mask = (size_t)~constant_time_is_zero_bn(a->d[i]);
|
||||
|
||||
ret = constant_time_select_s(mask, bits, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int OSSL_FN_cmp(const OSSL_FN *a, const OSSL_FN *b)
|
||||
{
|
||||
size_t i;
|
||||
size_t asize = (size_t)a->dsize;
|
||||
size_t bsize = (size_t)b->dsize;
|
||||
size_t max = asize > bsize ? asize : bsize;
|
||||
int res = 0;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
OSSL_FN_ULONG aw = i < asize ? a->d[i] : 0;
|
||||
OSSL_FN_ULONG bw = i < bsize ? b->d[i] : 0;
|
||||
|
||||
res = constant_time_select_int(
|
||||
(unsigned int)constant_time_lt_bn(aw, bw), -1, res);
|
||||
res = constant_time_select_int(
|
||||
(unsigned int)constant_time_lt_bn(bw, aw), 1, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Returns bit |n| of |a|. An out-of-range index (n < 0 or n >= the
|
||||
* operand's width in bits) reads as 0. The only control flow branches on
|
||||
* the operand's public width (dsize); the returned value is the bit itself,
|
||||
* which is the information the caller asked for.
|
||||
*/
|
||||
int OSSL_FN_is_bit_set(const OSSL_FN *a, int n)
|
||||
{
|
||||
size_t limb, off;
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
limb = (size_t)n / OSSL_FN_BITS;
|
||||
off = (size_t)n % OSSL_FN_BITS;
|
||||
if (limb >= (size_t)a->dsize)
|
||||
return 0;
|
||||
return (a->d[limb] >> off) & OSSL_FN_ULONG_C(1);
|
||||
}
|
||||
|
||||
/*-
|
||||
* Returns 1 if the unsigned value of |a| equals the single-limb word |w|.
|
||||
* Control flow branches only on the operand's public width (dsize); limb
|
||||
* values are combined with constant-time selects, so the number of limbs
|
||||
* inspected depends only on the public width, not on the operand's value.
|
||||
* The returned value is the equality test the caller asked for.
|
||||
*/
|
||||
int OSSL_FN_is_word(const OSSL_FN *a, OSSL_FN_ULONG w)
|
||||
{
|
||||
size_t i;
|
||||
size_t dsize = (size_t)a->dsize;
|
||||
int res;
|
||||
|
||||
if (dsize == 0)
|
||||
return w == 0;
|
||||
|
||||
res = constant_time_select_int(
|
||||
(unsigned int)constant_time_eq_bn(a->d[0], w), 1, 0);
|
||||
for (i = 1; i < dsize; i++)
|
||||
res = constant_time_select_int(
|
||||
(unsigned int)constant_time_is_zero_bn(a->d[i]), res, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Equivalent to OSSL_FN_is_word(a, 0), kept as a named predicate for
|
||||
* readability at call sites. Leak profile as for OSSL_FN_is_word():
|
||||
* branches only on the operand's public width (dsize).
|
||||
*/
|
||||
int OSSL_FN_is_zero(const OSSL_FN *a)
|
||||
{
|
||||
return OSSL_FN_is_word(a, 0);
|
||||
}
|
||||
|
||||
/*-
|
||||
* Equivalent to OSSL_FN_is_word(a, 1), kept as a named predicate for
|
||||
* readability at call sites. Leak profile as for OSSL_FN_is_word():
|
||||
* branches only on the operand's public width (dsize).
|
||||
*/
|
||||
int OSSL_FN_is_one(const OSSL_FN *a)
|
||||
{
|
||||
return OSSL_FN_is_word(a, 1);
|
||||
}
|
||||
|
||||
/*-
|
||||
* Returns the least significant bit of |a|, which is the information the
|
||||
* caller asked for. The only control flow branches on the operand's public
|
||||
* width (dsize), not on limb values.
|
||||
*/
|
||||
int OSSL_FN_is_odd(const OSSL_FN *a)
|
||||
{
|
||||
if (a->dsize <= 0)
|
||||
return 0;
|
||||
return (int)(a->d[0] & OSSL_FN_ULONG_C(1));
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_copy(OSSL_FN *a, const OSSL_FN *b)
|
||||
{
|
||||
if (ossl_unlikely(a == b))
|
||||
return a;
|
||||
|
||||
size_t al = a->dsize;
|
||||
size_t bl = b->dsize;
|
||||
|
||||
if (al < bl) {
|
||||
ERR_raise_data(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL,
|
||||
"Needs to be at least %zu bytes, but is only %zu bytes",
|
||||
bl * sizeof(OSSL_FN_ULONG), al * sizeof(OSSL_FN_ULONG));
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(a->d, b->d, bl * sizeof(OSSL_FN_ULONG));
|
||||
memset(a->d + bl, 0, (al - bl) * sizeof(OSSL_FN_ULONG));
|
||||
return a;
|
||||
}
|
||||
|
||||
OSSL_FN *OSSL_FN_copy_truncate(OSSL_FN *a, const OSSL_FN *b)
|
||||
{
|
||||
if (ossl_unlikely(a == b))
|
||||
return a;
|
||||
|
||||
size_t al = a->dsize;
|
||||
size_t bl = b->dsize;
|
||||
|
||||
if (ossl_unlikely(al > bl)) {
|
||||
memcpy(a->d, b->d, bl * sizeof(OSSL_FN_ULONG));
|
||||
memset(&a->d[bl], 0, sizeof(OSSL_FN_ULONG) * (al - bl));
|
||||
} else {
|
||||
memcpy(a->d, b->d, al * sizeof(OSSL_FN_ULONG));
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
182
crypto/fn/fn_local.h
Normal file
182
crypto/fn/fn_local.h
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OSSL_CRYPTO_FN_LOCAL_H
|
||||
#define OSSL_CRYPTO_FN_LOCAL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/e_os2.h>
|
||||
#include "internal/common.h"
|
||||
#include "crypto/fn.h"
|
||||
#include "crypto/fn_intern.h"
|
||||
|
||||
#if OSSL_FN_BYTES == 4
|
||||
/* 32-bit systems */
|
||||
#define OSSL_FN_ULONG_C(n) UINT32_C(n)
|
||||
#define OSSL_FN_MASK UINT32_MAX
|
||||
#elif OSSL_FN_BYTES == 8
|
||||
#define OSSL_FN_ULONG_C(n) UINT64_C(n)
|
||||
#define OSSL_FN_MASK UINT64_MAX
|
||||
#else
|
||||
#error "OpenSSL doesn't support large numbers on this platform"
|
||||
#endif
|
||||
|
||||
#define OSSL_FN_BITS (OSSL_FN_BYTES * 8)
|
||||
#define OSSL_FN_HIGH_BIT_MASK (OSSL_FN_ULONG_C(1) << (OSSL_FN_BITS - 1))
|
||||
#define OSSL_FN_LOW_HALF_MASK ((OSSL_FN_ULONG_C(1) << (OSSL_FN_BITS / 2)) - 1)
|
||||
#define OSSL_FN_HIGH_HALF_MASK (OSSL_FN_LOW_HALF_MASK << (OSSL_FN_BITS / 2))
|
||||
|
||||
struct ossl_fn_st {
|
||||
/* Flag: alloced with OSSL_FN_new() or OSSL_FN_secure_new() */
|
||||
unsigned int is_dynamically_allocated : 1;
|
||||
/* Flag: alloced with OSSL_FN_secure_new() */
|
||||
unsigned int is_securely_allocated : 1;
|
||||
|
||||
/*
|
||||
* The d array, with its size in number of OSSL_FN_ULONG.
|
||||
* This stores the number itself.
|
||||
*
|
||||
* Note: |dsize| is an int, because it turns out that some lower level
|
||||
* (possibly assembler) functions expect that type (especially, that
|
||||
* type size).
|
||||
* This deviates from the design in doc/designs/fixed-size-large-numbers.md
|
||||
*/
|
||||
int dsize;
|
||||
OSSL_FN_ULONG d[];
|
||||
};
|
||||
|
||||
static ossl_inline size_t ossl_fn_totalsize(size_t limbs)
|
||||
{
|
||||
/*
|
||||
* TODO(FIXNUM): Since the number of limbs is currently represented
|
||||
* as an 'int' in OSSL_FN, we must ensure that the desired size isn't
|
||||
* larger than can be represented.
|
||||
*/
|
||||
if (ossl_unlikely(limbs >= INT_MAX))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* sizeof(OSSL_FN) + limbs * sizeof(OSSL_FN_ULONG) > SIZE_MAX
|
||||
* => limbs * sizeof(OSSL_FN_ULONG) > SIZE_MAX - sizeof(OSSL_FN)
|
||||
* => limbs > (SIZE_MAX - sizeof(OSSL_FN)) / sizeof(OSSL_FN_ULONG)
|
||||
*/
|
||||
if (ossl_unlikely(limbs > (SIZE_MAX - sizeof(OSSL_FN)) / sizeof(OSSL_FN_ULONG)))
|
||||
return 0;
|
||||
return sizeof(OSSL_FN) + limbs * sizeof(OSSL_FN_ULONG);
|
||||
}
|
||||
|
||||
static ossl_inline size_t ossl_fn_bytes_to_limbs(size_t size)
|
||||
{
|
||||
return (size + sizeof(OSSL_FN_ULONG) - 1) / sizeof(OSSL_FN_ULONG);
|
||||
}
|
||||
|
||||
static ossl_inline size_t ossl_fn_bits_to_bytes(size_t size)
|
||||
{
|
||||
return (size + 7) / 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal functions to support BIGNUM's bn_expand_internal, BN_copy, and
|
||||
* similar.
|
||||
* The caller must ensure that src and dest are not NULL.
|
||||
* With ossl_fn_copy_internal, bn_words may be given -1 to signify that the
|
||||
* number of BN_ULONG should be found in src.
|
||||
*/
|
||||
static ossl_inline OSSL_FN *ossl_fn_copy_internal_limbs(OSSL_FN *dest,
|
||||
const OSSL_FN_ULONG *src,
|
||||
int limbs)
|
||||
{
|
||||
if (ossl_unlikely(dest->dsize < limbs))
|
||||
return NULL;
|
||||
memcpy(dest->d, src, limbs * sizeof(dest->d[0]));
|
||||
memset(dest->d + limbs, 0, (dest->dsize - limbs) * sizeof(dest->d[0]));
|
||||
return dest;
|
||||
}
|
||||
|
||||
static ossl_inline OSSL_FN *ossl_fn_copy_internal(OSSL_FN *dest,
|
||||
const OSSL_FN *src,
|
||||
int bn_words)
|
||||
{
|
||||
int words = bn_words < 0 ? src->dsize : bn_words;
|
||||
|
||||
if (ossl_fn_copy_internal_limbs(dest, src->d, words) == NULL)
|
||||
return NULL;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* OSSL_FN_CTX internals */
|
||||
|
||||
struct ossl_fn_ctx_st {
|
||||
/*
|
||||
* Pointer to the last OSSL_FN_CTX_start() location (a simple pointer into
|
||||
* the memory area). See the struct ossl_fn_ctx_frame_st definition below
|
||||
* for details.
|
||||
*/
|
||||
struct ossl_fn_ctx_frame_st *last_frame;
|
||||
|
||||
/*
|
||||
* Flags
|
||||
*/
|
||||
unsigned int is_securely_allocated : 1;
|
||||
|
||||
/*
|
||||
* Current and peak usage tracking, by allocation components.
|
||||
* The |n_*| fields hold the currently active counts; the |peak_n_*|
|
||||
* fields hold the maximum each count has ever reached simultaneously.
|
||||
* This allows callers to determine suitable arena parameters for a
|
||||
* given workload without precise up-front prediction.
|
||||
*/
|
||||
size_t n_frames;
|
||||
size_t n_numbers;
|
||||
size_t n_limbs;
|
||||
size_t peak_n_frames;
|
||||
size_t peak_n_numbers;
|
||||
size_t peak_n_limbs;
|
||||
|
||||
/*
|
||||
* The arena itself.
|
||||
*/
|
||||
size_t msize; /* Size of the arena, in bytes */
|
||||
unsigned char memory[];
|
||||
};
|
||||
|
||||
struct ossl_fn_ctx_frame_st {
|
||||
/*
|
||||
* Pointer back to the whole arena where the frame is located,
|
||||
* for |last_frame| bookkeeping.
|
||||
*/
|
||||
struct ossl_fn_ctx_st *arena;
|
||||
/*
|
||||
* Pointer to the previous frame in the arena, allowing OSSL_FN_CTX_end()
|
||||
* to do its job.
|
||||
*/
|
||||
struct ossl_fn_ctx_frame_st *previous_frame;
|
||||
/*
|
||||
* Tracking for peak usage instrumentation. These count the OSSL_FN
|
||||
* instances and total limbs allocated within this frame.
|
||||
*/
|
||||
size_t n_numbers;
|
||||
size_t n_limbs;
|
||||
/*
|
||||
* Every time OSSL_FN_CTX_get() is called, the current value of
|
||||
* |free_memory| is returned, and it's updated by incrementing it
|
||||
* by the number of bytes given by OSSL_FN_CTX_get().
|
||||
* The available number of bytes is limited by what's left in the arena.
|
||||
*/
|
||||
unsigned char *free_memory; /* Pointer to the free area of the frame */
|
||||
size_t msize; /* Size of the frame, in bytes */
|
||||
unsigned char memory[];
|
||||
};
|
||||
|
||||
/* end OSSL_FN_CTX internals */
|
||||
|
||||
#endif
|
||||
564
crypto/fn/fn_mod.c
Normal file
564
crypto/fn/fn_mod.c
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/nelem.h"
|
||||
#include "internal/safe_math.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "fn_local.h"
|
||||
|
||||
OSSL_SAFE_MATH_ADDU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
|
||||
OSSL_SAFE_MATH_MULU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
|
||||
|
||||
static size_t ctx_add_size(size_t a, size_t b)
|
||||
{
|
||||
int err = 0;
|
||||
size_t r = safe_add_size_t(a, b, &err);
|
||||
|
||||
return err == 0 ? r : 0;
|
||||
}
|
||||
|
||||
static size_t ctx_max_size(size_t a, size_t b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/*
|
||||
* The *_ctx_size helpers below use local OSSL_FN headers with only |dsize|
|
||||
* set to represent temporaries that the corresponding operation allocates
|
||||
* with OSSL_FN_CTX_get_limbs(). This is enough for nested ctx-size helpers,
|
||||
* which only inspect operand sizes.
|
||||
*/
|
||||
size_t OSSL_FN_mod_add_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b, const OSSL_FN *m)
|
||||
{
|
||||
size_t tl, own_size, nested_size;
|
||||
|
||||
if (r == NULL || a == NULL || b == NULL || m == NULL)
|
||||
return 0;
|
||||
int err = 0;
|
||||
|
||||
tl = safe_add_size_t(a->dsize > b->dsize ? a->dsize : b->dsize,
|
||||
1, &err);
|
||||
if (err != 0 || ossl_fn_totalsize(tl) == 0)
|
||||
return 0;
|
||||
|
||||
OSSL_FN t = { .dsize = (int)tl };
|
||||
|
||||
own_size = OSSL_FN_CTX_size(1, 1, tl);
|
||||
nested_size = OSSL_FN_mod_ctx_size(r, &t, m);
|
||||
if (own_size == 0 || nested_size == 0)
|
||||
return 0;
|
||||
|
||||
return ctx_add_size(own_size, nested_size);
|
||||
}
|
||||
|
||||
int OSSL_FN_mod_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m, OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
OSSL_FN *t;
|
||||
int ret = 0;
|
||||
size_t tl = (a->dsize > b->dsize ? a->dsize : b->dsize) + 1;
|
||||
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
if ((t = OSSL_FN_CTX_get_limbs(ctx, tl)) == NULL)
|
||||
goto err;
|
||||
|
||||
ret = OSSL_FN_add(t, a, b)
|
||||
&& OSSL_FN_mod(r, t, m, ctx);
|
||||
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* OSSL_FN_mod_add variant that may be used if both a and b are less than m.
|
||||
* The original formula is:
|
||||
*
|
||||
* r' = a + b
|
||||
* r = r′ − m[r′ ≥ m]
|
||||
*
|
||||
* This is replaced with addition, subtracting modulus, and conditional move
|
||||
* depending on whether or not subtraction borrowed.
|
||||
*/
|
||||
int OSSL_FN_mod_add_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m)
|
||||
{
|
||||
size_t al = a->dsize;
|
||||
size_t bl = b->dsize;
|
||||
size_t rl = r->dsize;
|
||||
size_t ml = m->dsize;
|
||||
size_t aw = al < ml ? al : ml;
|
||||
size_t bw = bl < ml ? bl : ml;
|
||||
OSSL_FN_ULONG storage[2 * 1024 / OSSL_FN_BITS];
|
||||
OSSL_FN_ULONG *tp = storage;
|
||||
OSSL_FN_ULONG *mp = storage + ml;
|
||||
OSSL_FN_ULONG carry, borrow;
|
||||
size_t i;
|
||||
|
||||
if (2 * ml > OSSL_NELEM(storage)) {
|
||||
tp = OPENSSL_malloc_array(2 * ml, sizeof(OSSL_FN_ULONG));
|
||||
if (tp == NULL)
|
||||
return 0;
|
||||
mp = tp + ml;
|
||||
}
|
||||
|
||||
/* tp = a + b mod 2^(ml*bits) */
|
||||
carry = ossl_fn_add_words(tp, ml, a->d, aw, b->d, bw);
|
||||
|
||||
/* mp = tp - m mod 2^(ml*bits) */
|
||||
borrow = ossl_fn_sub_words(mp, ml, tp, ml, m->d, ml);
|
||||
|
||||
/*
|
||||
* Because a, b < m, we have a + b < 2m. Therefore tp < m whenever
|
||||
* carry = 1, which forces borrow = 1. The mask carry − borrow thus
|
||||
* only produces 0 (select tp2) or ~0 (select tp), matching exactly
|
||||
* whether a + b ≥ m.
|
||||
*
|
||||
* Thus, we have the cases:
|
||||
*
|
||||
* a + b < m => carry == 0, borrow == 1
|
||||
* m <= a+b < 2^(ml*bits) => carry == 0, borrow == 0
|
||||
* 2^(ml*bits) <= a+b < 2m => carry == 1, borrow == 1
|
||||
*
|
||||
* If (a + b < m), select tp; otherwise select tp2. Done with the
|
||||
* help of a mask.
|
||||
*/
|
||||
OSSL_FN_ULONG mask = carry - borrow;
|
||||
size_t end = (rl < ml) ? rl : ml;
|
||||
for (i = 0; i < end; i++)
|
||||
r->d[i] = (mask & tp[i]) | (~mask & mp[i]);
|
||||
/* Make sure to pad r with zeroes when rl > ml */
|
||||
for (; i < rl; i++)
|
||||
r->d[i] = 0;
|
||||
|
||||
if (tp != storage)
|
||||
OPENSSL_clear_free(tp, 2 * ml * sizeof(OSSL_FN_ULONG));
|
||||
else
|
||||
OPENSSL_cleanse(storage, sizeof(storage));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t OSSL_FN_mod_sub_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b, const OSSL_FN *m)
|
||||
{
|
||||
size_t ml, n_numbers, own_size, mod_a_size, mod_b_size, nested_size;
|
||||
|
||||
if (r == NULL || a == NULL || b == NULL || m == NULL)
|
||||
return 0;
|
||||
|
||||
ml = m->dsize;
|
||||
n_numbers = (r == m) ? 3 : 2;
|
||||
if (ossl_fn_totalsize(ml) == 0)
|
||||
return 0;
|
||||
|
||||
OSSL_FN am = { .dsize = (int)ml };
|
||||
OSSL_FN bm = { .dsize = (int)ml };
|
||||
|
||||
own_size = OSSL_FN_CTX_size(1, n_numbers, n_numbers * ml);
|
||||
mod_a_size = OSSL_FN_mod_ctx_size(&am, a, m);
|
||||
mod_b_size = OSSL_FN_mod_ctx_size(&bm, b, m);
|
||||
nested_size = ctx_max_size(mod_a_size, mod_b_size);
|
||||
if (own_size == 0 || nested_size == 0)
|
||||
return 0;
|
||||
|
||||
return ctx_add_size(own_size, nested_size);
|
||||
}
|
||||
|
||||
int OSSL_FN_mod_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m, OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
OSSL_FN *am, *bm, *rr = r;
|
||||
int ret = 0;
|
||||
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
if ((am = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL
|
||||
|| (bm = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL)
|
||||
goto err;
|
||||
|
||||
if (r == m && (rr = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL)
|
||||
goto err;
|
||||
|
||||
ret = OSSL_FN_mod(am, a, m, ctx)
|
||||
&& OSSL_FN_mod(bm, b, m, ctx)
|
||||
&& OSSL_FN_mod_sub_quick(rr, am, bm, m)
|
||||
&& (rr == r || OSSL_FN_copy_truncate(r, rr) != NULL);
|
||||
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* OSSL_FN_mod_sub variant that may be used if a is less than m, while b is
|
||||
* of same bit width as m. It's implemented as subtraction followed by two
|
||||
* conditional additions.
|
||||
*
|
||||
* 0 <= a < m
|
||||
* 0 <= b < 2^w < 2*m
|
||||
*
|
||||
* after subtraction
|
||||
*
|
||||
* -2*m < r = a - b < m
|
||||
*
|
||||
* The original formula is:
|
||||
*
|
||||
* r' = a - b
|
||||
* r'' = r' + m[r' < 0]
|
||||
* r = r′' + m[r′' < 0]
|
||||
*
|
||||
* Because masking techniques are used, this is most efficiently
|
||||
* carried out with local loops rather than calling functions like
|
||||
* ossl_fn_add_words().
|
||||
*/
|
||||
int OSSL_FN_mod_sub_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m)
|
||||
{
|
||||
if (r == m) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t al = a->dsize;
|
||||
size_t bl = b->dsize;
|
||||
size_t rl = r->dsize;
|
||||
size_t ml = m->dsize;
|
||||
size_t aw = al < ml ? al : ml;
|
||||
size_t bw = bl < ml ? bl : ml;
|
||||
OSSL_FN_ULONG storage[1024 / OSSL_FN_BITS];
|
||||
OSSL_FN_ULONG *tp = storage;
|
||||
size_t i;
|
||||
OSSL_FN_ULONG borrow, carry, ta, mask;
|
||||
|
||||
if (ml > OSSL_NELEM(storage)) {
|
||||
tp = OPENSSL_malloc_array(ml, sizeof(OSSL_FN_ULONG));
|
||||
if (tp == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tp = a - b mod 2^(ml*bits) */
|
||||
borrow = ossl_fn_sub_words(tp, ml, a->d, aw, b->d, bw);
|
||||
|
||||
/* If borrow, add m */
|
||||
for (i = 0, mask = 0 - borrow, carry = 0; i < ml; i++) {
|
||||
ta = ((m->d[i] & mask) + carry) & OSSL_FN_MASK;
|
||||
carry = (ta < carry);
|
||||
tp[i] = (tp[i] + ta) & OSSL_FN_MASK;
|
||||
carry += (tp[i] < ta);
|
||||
}
|
||||
|
||||
/* If still borrow, add m again */
|
||||
borrow -= carry;
|
||||
for (i = 0, mask = 0 - borrow, carry = 0; i < ml; i++) {
|
||||
ta = ((m->d[i] & mask) + carry) & OSSL_FN_MASK;
|
||||
carry = (ta < carry);
|
||||
tp[i] = (tp[i] + ta) & OSSL_FN_MASK;
|
||||
carry += (tp[i] < ta);
|
||||
}
|
||||
|
||||
for (i = 0; i < rl && i < ml; i++)
|
||||
r->d[i] = tp[i];
|
||||
/* Make sure to pad r with zeroes when rl > ml */
|
||||
for (; i < rl; i++)
|
||||
r->d[i] = 0;
|
||||
|
||||
if (tp != storage)
|
||||
OPENSSL_clear_free(tp, ml * sizeof(OSSL_FN_ULONG));
|
||||
else
|
||||
OPENSSL_cleanse(storage, sizeof(storage));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t OSSL_FN_mod_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b, const OSSL_FN *m)
|
||||
{
|
||||
size_t tl, own_size, mul_size, mod_size, nested_size;
|
||||
|
||||
if (r == NULL || a == NULL || b == NULL || m == NULL)
|
||||
return 0;
|
||||
|
||||
if (a == b) {
|
||||
int err = 0;
|
||||
|
||||
tl = safe_mul_size_t(2, a->dsize, &err);
|
||||
if (err != 0 || ossl_fn_totalsize(tl) == 0)
|
||||
return 0;
|
||||
OSSL_FN t = { .dsize = (int)tl };
|
||||
|
||||
mul_size = OSSL_FN_sqr_ctx_size(&t, a);
|
||||
mod_size = OSSL_FN_mod_ctx_size(r, &t, m);
|
||||
} else {
|
||||
int err = 0;
|
||||
|
||||
tl = safe_add_size_t(a->dsize, b->dsize, &err);
|
||||
if (err != 0 || ossl_fn_totalsize(tl) == 0)
|
||||
return 0;
|
||||
OSSL_FN t = { .dsize = (int)tl };
|
||||
|
||||
mul_size = OSSL_FN_mul_ctx_size(&t, a, b);
|
||||
mod_size = OSSL_FN_mod_ctx_size(r, &t, m);
|
||||
}
|
||||
|
||||
own_size = OSSL_FN_CTX_size(1, 1, tl);
|
||||
nested_size = ctx_max_size(mul_size, mod_size);
|
||||
if (own_size == 0 || nested_size == 0)
|
||||
return 0;
|
||||
|
||||
return ctx_add_size(own_size, nested_size);
|
||||
}
|
||||
|
||||
/* slow but works */
|
||||
int OSSL_FN_mod_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m, OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
OSSL_FN *t;
|
||||
int ret = 0;
|
||||
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
|
||||
if (a == b) {
|
||||
size_t tl = 2 * a->dsize;
|
||||
|
||||
if ((t = OSSL_FN_CTX_get_limbs(ctx, tl)) == NULL
|
||||
|| !OSSL_FN_sqr(t, a, ctx))
|
||||
goto err;
|
||||
} else {
|
||||
size_t tl = a->dsize + b->dsize;
|
||||
|
||||
if ((t = OSSL_FN_CTX_get_limbs(ctx, tl)) == NULL
|
||||
|| !OSSL_FN_mul(t, a, b, ctx))
|
||||
goto err;
|
||||
}
|
||||
if (!OSSL_FN_mod(r, t, m, ctx))
|
||||
goto err;
|
||||
ret = 1;
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t OSSL_FN_mod_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *m)
|
||||
{
|
||||
size_t tl, own_size, sqr_size, mod_size, nested_size;
|
||||
|
||||
if (r == NULL || a == NULL || m == NULL)
|
||||
return 0;
|
||||
int err = 0;
|
||||
|
||||
tl = safe_mul_size_t(2, a->dsize, &err);
|
||||
if (err != 0 || ossl_fn_totalsize(tl) == 0)
|
||||
return 0;
|
||||
|
||||
OSSL_FN t = { .dsize = (int)tl };
|
||||
|
||||
own_size = OSSL_FN_CTX_size(1, 1, tl);
|
||||
sqr_size = OSSL_FN_sqr_ctx_size(&t, a);
|
||||
mod_size = OSSL_FN_mod_ctx_size(r, &t, m);
|
||||
nested_size = ctx_max_size(sqr_size, mod_size);
|
||||
if (own_size == 0 || nested_size == 0)
|
||||
return 0;
|
||||
|
||||
return ctx_add_size(own_size, nested_size);
|
||||
}
|
||||
|
||||
int OSSL_FN_mod_sqr(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
|
||||
OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
OSSL_FN *t;
|
||||
int ret = 0;
|
||||
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
if ((t = OSSL_FN_CTX_get_limbs(ctx, (size_t)(2 * a->dsize))) == NULL)
|
||||
goto err;
|
||||
|
||||
ret = OSSL_FN_sqr(t, a, ctx)
|
||||
&& OSSL_FN_mod(r, t, m, ctx);
|
||||
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t OSSL_FN_mod_lshift1_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *m)
|
||||
{
|
||||
size_t tl, own_size, nested_size;
|
||||
|
||||
if (r == NULL || a == NULL || m == NULL)
|
||||
return 0;
|
||||
int err = 0;
|
||||
|
||||
tl = safe_add_size_t(m->dsize, 1, &err);
|
||||
if (err != 0 || ossl_fn_totalsize(tl) == 0)
|
||||
return 0;
|
||||
|
||||
OSSL_FN t = { .dsize = (int)tl };
|
||||
|
||||
own_size = OSSL_FN_CTX_size(1, 1, tl);
|
||||
nested_size = OSSL_FN_mod_ctx_size(r, &t, m);
|
||||
if (own_size == 0 || nested_size == 0)
|
||||
return 0;
|
||||
|
||||
return ctx_add_size(own_size, nested_size);
|
||||
}
|
||||
|
||||
int OSSL_FN_mod_lshift1(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
|
||||
OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
OSSL_FN *t;
|
||||
int ret = 0;
|
||||
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
if ((t = OSSL_FN_CTX_get_limbs(ctx, (size_t)(m->dsize + 1))) == NULL)
|
||||
goto err;
|
||||
|
||||
ret = OSSL_FN_lshift1(t, a)
|
||||
&& OSSL_FN_mod(r, t, m, ctx);
|
||||
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* OSSL_FN_mod_lshift1 variant that may be used if a is less than m */
|
||||
int OSSL_FN_mod_lshift1_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m)
|
||||
{
|
||||
OSSL_FN *t = OSSL_FN_new_limbs((size_t)(m->dsize + 1));
|
||||
int ret = 0;
|
||||
|
||||
if (t == NULL)
|
||||
return 0;
|
||||
if (!OSSL_FN_lshift1(t, a))
|
||||
goto err;
|
||||
if (OSSL_FN_cmp(t, m) >= 0) {
|
||||
if (!OSSL_FN_sub(t, t, m))
|
||||
goto err;
|
||||
}
|
||||
OSSL_FN_copy_truncate(r, t);
|
||||
ret = 1;
|
||||
err:
|
||||
OSSL_FN_free(t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t OSSL_FN_mod_lshift_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
int n, const OSSL_FN *m)
|
||||
{
|
||||
size_t ml, own_size, nested_size;
|
||||
|
||||
if (r == NULL || a == NULL || m == NULL)
|
||||
return 0;
|
||||
(void)n;
|
||||
|
||||
ml = m->dsize;
|
||||
if (ossl_fn_totalsize(ml) == 0)
|
||||
return 0;
|
||||
|
||||
OSSL_FN ra = { .dsize = (int)ml };
|
||||
|
||||
own_size = OSSL_FN_CTX_size(1, 1, ml);
|
||||
nested_size = OSSL_FN_mod_ctx_size(&ra, a, m);
|
||||
if (own_size == 0 || nested_size == 0)
|
||||
return 0;
|
||||
|
||||
return ctx_add_size(own_size, nested_size);
|
||||
}
|
||||
|
||||
int OSSL_FN_mod_lshift(OSSL_FN *r, const OSSL_FN *a, int n, const OSSL_FN *m,
|
||||
OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
OSSL_FN *ra;
|
||||
int ret = 0;
|
||||
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
if ((ra = OSSL_FN_CTX_get_limbs(ctx, m->dsize)) == NULL)
|
||||
goto err;
|
||||
|
||||
ret = OSSL_FN_mod(ra, a, m, ctx)
|
||||
&& OSSL_FN_mod_lshift_quick(r, ra, n, m);
|
||||
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* OSSL_FN_mod_lshift variant that may be used if a is less than m */
|
||||
int OSSL_FN_mod_lshift_quick(OSSL_FN *r, const OSSL_FN *a, int n,
|
||||
const OSSL_FN *m)
|
||||
{
|
||||
OSSL_FN *t = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (n <= 0)
|
||||
return n == 0 ? (OSSL_FN_copy_truncate(r, a) != NULL) : 0;
|
||||
|
||||
t = OSSL_FN_new_limbs((size_t)(m->dsize + 1));
|
||||
if (t == NULL)
|
||||
goto err;
|
||||
|
||||
if (OSSL_FN_copy_truncate(t, a) == NULL)
|
||||
goto err;
|
||||
|
||||
while (n > 0) {
|
||||
size_t m_bits = OSSL_FN_num_bits(m);
|
||||
size_t t_bits = OSSL_FN_num_bits(t);
|
||||
size_t max_shift;
|
||||
|
||||
/* 0 <= t < m */
|
||||
if (m_bits < t_bits) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INPUT_NOT_REDUCED);
|
||||
goto err;
|
||||
}
|
||||
max_shift = m_bits - t_bits;
|
||||
|
||||
if (max_shift > (size_t)n)
|
||||
max_shift = (size_t)n;
|
||||
|
||||
if (max_shift) {
|
||||
int shift = (int)max_shift;
|
||||
|
||||
if (!OSSL_FN_lshift(t, t, shift))
|
||||
goto err;
|
||||
n -= shift;
|
||||
} else {
|
||||
if (!OSSL_FN_lshift1(t, t))
|
||||
goto err;
|
||||
n--;
|
||||
}
|
||||
|
||||
if (OSSL_FN_cmp(t, m) >= 0) {
|
||||
if (!OSSL_FN_sub(t, t, m))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (OSSL_FN_copy_truncate(r, t) == NULL)
|
||||
goto err;
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
OSSL_FN_free(t);
|
||||
return ret;
|
||||
}
|
||||
78
crypto/fn/fn_mul.c
Normal file
78
crypto/fn/fn_mul.c
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/err.h>
|
||||
#include "crypto/cryptlib.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "../bn/bn_local.h" /* For using the low level bignum functions */
|
||||
#include "fn_local.h"
|
||||
|
||||
size_t OSSL_FN_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b)
|
||||
{
|
||||
size_t limbs = 0;
|
||||
|
||||
if (r == NULL || a == NULL || b == NULL)
|
||||
return 0;
|
||||
if (r == a || r == b)
|
||||
limbs = r->dsize;
|
||||
|
||||
return OSSL_FN_CTX_size(1, limbs == 0 ? 0 : 1, limbs);
|
||||
}
|
||||
|
||||
int OSSL_FN_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b, OSSL_FN_CTX *ctx)
|
||||
{
|
||||
size_t al = (size_t)a->dsize;
|
||||
size_t bl = (size_t)b->dsize;
|
||||
size_t rl = (size_t)r->dsize;
|
||||
size_t max = (size_t)(al + bl);
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
|
||||
int ret = 0;
|
||||
#ifdef BN_MUL_COMBA
|
||||
if (al == bl) {
|
||||
if (rl >= 16 && al == 8) {
|
||||
bn_mul_comba8(r->d, a->d, b->d);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#endif /* BN_MUL_COMBA */
|
||||
|
||||
OSSL_FN *rr = r;
|
||||
if ((r == a) || (r == b))
|
||||
if ((rr = OSSL_FN_CTX_get_limbs(ctx, rl)) == NULL)
|
||||
goto err;
|
||||
|
||||
bn_mul_truncated(rr->d, (int)rl, a->d, (int)al, b->d, (int)bl);
|
||||
|
||||
if (rr != r)
|
||||
if (OSSL_FN_copy(r, rr) == NULL)
|
||||
goto err;
|
||||
|
||||
#ifdef BN_MUL_COMBA
|
||||
end:
|
||||
#endif
|
||||
|
||||
{
|
||||
size_t dif = (rl > max) ? rl - max : 0;
|
||||
OSSL_FN_ULONG *rp = &r->d[max];
|
||||
while (dif > 0) {
|
||||
*rp++ = 0;
|
||||
dif--;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
246
crypto/fn/fn_rand.c
Normal file
246
crypto/fn/fn_rand.c
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "crypto/fnerr.h"
|
||||
#include "fn_local.h"
|
||||
|
||||
/*
|
||||
* Internal flag selecting which DRBG pool the bytes are drawn from.
|
||||
* NORMAL routes through RAND_bytes_ex(), PRIVATE through
|
||||
* RAND_priv_bytes_ex() (a non-forward-linkable source). The same shaping
|
||||
* code feeds either pool; the flag selects which one, mirroring the
|
||||
* public/private split exposed by the OSSL_FN_rand() / OSSL_FN_priv_rand()
|
||||
* entry points.
|
||||
*/
|
||||
enum ossl_fn_rand_flag {
|
||||
NORMAL = 0,
|
||||
PRIVATE
|
||||
};
|
||||
|
||||
/* Set bit |pos| (0 = least significant) of |a|, by absolute position. */
|
||||
static void ossl_fn_set_bit(OSSL_FN *a, size_t pos)
|
||||
{
|
||||
a->d[pos / OSSL_FN_BITS] |= OSSL_FN_ULONG_C(1) << (pos % OSSL_FN_BITS);
|
||||
}
|
||||
|
||||
/*-
|
||||
* ossl_fn_rand() fills |rnd| with |bits| random bits, shaping the top and
|
||||
* bottom bits per the |top|/|bottom| requests. The random bytes are drawn
|
||||
* directly into rnd->d's byte image (a whole number of limbs, so the result
|
||||
* is a random value regardless of the machine's byte order), and the
|
||||
* top/bottom/mask shaping is done directly on rnd->d's limbs as value
|
||||
* operations -- set bit |bits|-1 for TOP_ONE, bits |bits|-1 and |bits|-2
|
||||
* for TOP_TWO, clear the high bits of the top limb at |bits| and above,
|
||||
* set bit 0 for BOTTOM_ODD. No intermediate byte buffer is needed, since
|
||||
* OSSL_FN's limbs are fixed-size.
|
||||
*
|
||||
* A destination too small for |bits| is an error
|
||||
* (OSSL_FN_R_RESULT_ARG_TOO_SMALL), not an implicit expansion.
|
||||
*
|
||||
* The leak profile: control flow branches on |bits|, |top|, |bottom| (all
|
||||
* caller-chosen, public) and on the byte-draw return value, never on the
|
||||
* random bytes themselves. The result value of OSSL_FN_rand() /
|
||||
* OSSL_FN_priv_rand() is, of course, the random number the caller asked for.
|
||||
*/
|
||||
static int ossl_fn_rand(enum ossl_fn_rand_flag flag, OSSL_FN *rnd, size_t bits,
|
||||
int top, int bottom, size_t strength,
|
||||
OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
size_t limbs_needed, top_limb, i;
|
||||
|
||||
if (rnd == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bits == 0) {
|
||||
if (top != OSSL_FN_RAND_TOP_ANY || bottom != OSSL_FN_RAND_BOTTOM_ANY)
|
||||
goto toosmall;
|
||||
return OSSL_FN_zero(rnd);
|
||||
}
|
||||
/* TOP_TWO forces two high bits, so it needs at least two bits. */
|
||||
if (top == OSSL_FN_RAND_TOP_TWO && bits < 2)
|
||||
goto toosmall;
|
||||
|
||||
limbs_needed = bits / OSSL_FN_BITS;
|
||||
limbs_needed += (bits % OSSL_FN_BITS != 0) ? 1 : 0;
|
||||
if (limbs_needed > (size_t)rnd->dsize) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_RESULT_ARG_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
top_limb = limbs_needed - 1;
|
||||
|
||||
/*
|
||||
* Draw random bytes directly into rnd->d's byte image. A whole number
|
||||
* of limbs is filled so the result is a random value regardless of the
|
||||
* machine's byte order; the high bits of the top limb beyond |bits| are
|
||||
* masked off below. The pool is selected by |flag|.
|
||||
*/
|
||||
{
|
||||
size_t fill_bytes = limbs_needed * OSSL_FN_BYTES;
|
||||
int b = (flag == NORMAL)
|
||||
? RAND_bytes_ex(libctx, (unsigned char *)rnd->d, fill_bytes,
|
||||
(unsigned int)strength)
|
||||
: RAND_priv_bytes_ex(libctx, (unsigned char *)rnd->d, fill_bytes,
|
||||
(unsigned int)strength);
|
||||
|
||||
if (b <= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(FIXNUM): a testing variant that mangles the byte buffer to
|
||||
* generate patterns more likely to trigger library bugs is not wired up
|
||||
* yet; if an OSSL_FN_bntest_rand() analogue is added for test coverage,
|
||||
* this is the spot for the mangle step.
|
||||
*/
|
||||
|
||||
/* Zero any limbs above those the bytes filled. */
|
||||
for (i = limbs_needed; i < (size_t)rnd->dsize; i++)
|
||||
rnd->d[i] = 0;
|
||||
|
||||
/* Clear the high bits of the top limb at |bits| and above. */
|
||||
if (bits % OSSL_FN_BITS != 0)
|
||||
rnd->d[top_limb] &= (OSSL_FN_ULONG_C(1) << (bits % OSSL_FN_BITS)) - 1;
|
||||
|
||||
/* Set the requested top bit(s); |bits| >= 2 is guaranteed for TOP_TWO. */
|
||||
if (top != OSSL_FN_RAND_TOP_ANY) {
|
||||
ossl_fn_set_bit(rnd, bits - 1);
|
||||
if (top == OSSL_FN_RAND_TOP_TWO)
|
||||
ossl_fn_set_bit(rnd, bits - 2);
|
||||
}
|
||||
|
||||
/* Set the bottom bit if requested. */
|
||||
if (bottom == OSSL_FN_RAND_BOTTOM_ODD)
|
||||
rnd->d[0] |= OSSL_FN_ULONG_C(1);
|
||||
|
||||
return 1;
|
||||
|
||||
toosmall:
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_BITS_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Draw from the public DRBG pool (NORMAL). */
|
||||
int OSSL_FN_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
|
||||
size_t strength, OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return ossl_fn_rand(NORMAL, rnd, bits, top, bottom, strength, libctx);
|
||||
}
|
||||
|
||||
/* Draw from the private DRBG pool (PRIVATE). */
|
||||
int OSSL_FN_priv_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
|
||||
size_t strength, OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return ossl_fn_rand(PRIVATE, rnd, bits, top, bottom, strength, libctx);
|
||||
}
|
||||
|
||||
/*-
|
||||
* ossl_fn_rand_range() produces 0 <= r < range by rejection sampling. The
|
||||
* libctx comes directly as an argument, as in ossl_fn_rand(); sign is never
|
||||
* considered, since OSSL_FN is unsigned.
|
||||
*
|
||||
* The leak profile: control flow branches on |range|'s top bit pattern and on
|
||||
* |r|'s width (both public), and the loop iteration count leaks the magnitude
|
||||
* of |range| (via OSSL_FN_num_bits) and the rejection probability.
|
||||
*
|
||||
* The destination |r| must be sized to hold at least |num_bits(range)| bits.
|
||||
* The "range = 100..._2" path draws n + 1 bits and is taken only when |r|
|
||||
* has room for them; an exactly-sized |r| (room for exactly n bits) uses the
|
||||
* standard n-bit rejection path instead.
|
||||
*/
|
||||
static int ossl_fn_rand_range(enum ossl_fn_rand_flag flag, OSSL_FN *r,
|
||||
const OSSL_FN *range, size_t strength,
|
||||
OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
size_t n;
|
||||
int count = 100;
|
||||
|
||||
if (r == NULL) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (OSSL_FN_is_zero(range)) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INVALID_RANGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = OSSL_FN_num_bits(range); /* n > 0 */
|
||||
|
||||
/* OSSL_FN_is_bit_set(range, n - 1) always holds */
|
||||
|
||||
if (n == 1) {
|
||||
return OSSL_FN_zero(r);
|
||||
} else if (!OSSL_FN_is_bit_set(range, (int)(n - 2))
|
||||
&& !OSSL_FN_is_bit_set(range, (int)(n - 3))
|
||||
&& n < (size_t)r->dsize * OSSL_FN_BITS) {
|
||||
/*
|
||||
* range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer
|
||||
* than range. This draws n + 1 bits, so it is taken only when |r| has
|
||||
* room for them; an exactly-sized |r| (room for exactly n bits) falls
|
||||
* through to the standard n-bit rejection path below.
|
||||
*/
|
||||
do {
|
||||
if (!ossl_fn_rand(flag, r, n + 1, OSSL_FN_RAND_TOP_ANY,
|
||||
OSSL_FN_RAND_BOTTOM_ANY, strength, libctx))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If r < 3*range, use r := r MOD range (which is either r, r -
|
||||
* range, or r - 2*range). Otherwise, iterate once more. Since
|
||||
* 3*range = 11..._2, each iteration succeeds with probability >=
|
||||
* .75.
|
||||
*/
|
||||
if (OSSL_FN_cmp(r, range) >= 0) {
|
||||
if (!OSSL_FN_sub(r, r, range))
|
||||
return 0;
|
||||
if (OSSL_FN_cmp(r, range) >= 0)
|
||||
if (!OSSL_FN_sub(r, r, range))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!--count) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_TOO_MANY_ITERATIONS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} while (OSSL_FN_cmp(r, range) >= 0);
|
||||
} else {
|
||||
do {
|
||||
/* range = 11..._2 or range = 101..._2 */
|
||||
if (!ossl_fn_rand(flag, r, n, OSSL_FN_RAND_TOP_ANY,
|
||||
OSSL_FN_RAND_BOTTOM_ANY, strength, libctx))
|
||||
return 0;
|
||||
|
||||
if (!--count) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_TOO_MANY_ITERATIONS);
|
||||
return 0;
|
||||
}
|
||||
} while (OSSL_FN_cmp(r, range) >= 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Draw from the public DRBG pool (NORMAL). */
|
||||
int OSSL_FN_rand_range(OSSL_FN *r, const OSSL_FN *range, size_t strength,
|
||||
OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return ossl_fn_rand_range(NORMAL, r, range, strength, libctx);
|
||||
}
|
||||
|
||||
/* Draw from the private DRBG pool (PRIVATE). */
|
||||
int OSSL_FN_priv_rand_range(OSSL_FN *r, const OSSL_FN *range,
|
||||
size_t strength, OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return ossl_fn_rand_range(PRIVATE, r, range, strength, libctx);
|
||||
}
|
||||
161
crypto/fn/fn_shift.c
Normal file
161
crypto/fn/fn_shift.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/err.h>
|
||||
#include "crypto/fnerr.h"
|
||||
#include "fn_local.h"
|
||||
|
||||
/*
|
||||
* In respect to shift factor the execution time is invariant of
|
||||
* |n % OSSL_FN_BITS|, but not |n / OSSL_FN_BITS|. Or in other words
|
||||
* pre-condition for constant-time-ness is |n < OSSL_FN_BITS| or
|
||||
* |n / OSSL_FN_BITS| being non-secret.
|
||||
*/
|
||||
int OSSL_FN_lshift(OSSL_FN *r, const OSSL_FN *a, int n)
|
||||
{
|
||||
size_t i, nw;
|
||||
unsigned int lb, rb;
|
||||
const OSSL_FN_ULONG *ap = a->d;
|
||||
OSSL_FN_ULONG *rp = r->d;
|
||||
size_t rl = (size_t)r->dsize;
|
||||
size_t al = (size_t)a->dsize;
|
||||
|
||||
if (n < 0) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INVALID_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nw = (size_t)n / OSSL_FN_BITS;
|
||||
if (nw >= rl) {
|
||||
memset(rp, 0, sizeof(*rp) * rl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lb = (unsigned int)n % OSSL_FN_BITS;
|
||||
rb = OSSL_FN_BITS - lb;
|
||||
|
||||
/*
|
||||
* Work from the high end to support r == a. Each result limb only
|
||||
* depends on the corresponding source limb and the limb just below it,
|
||||
* neither of which has been overwritten yet when walking downward.
|
||||
*/
|
||||
for (i = rl; i > 0; i--) {
|
||||
size_t r_idx = i - 1;
|
||||
OSSL_FN_ULONG limb = 0;
|
||||
|
||||
if (r_idx >= nw) {
|
||||
size_t src_idx = r_idx - nw;
|
||||
|
||||
if (src_idx < al)
|
||||
limb = (ap[src_idx] << lb) & OSSL_FN_MASK;
|
||||
if (lb != 0 && src_idx > 0 && src_idx - 1 < al)
|
||||
limb |= ap[src_idx - 1] >> rb;
|
||||
}
|
||||
rp[r_idx] = limb;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_FN_lshift1(OSSL_FN *r, const OSSL_FN *a)
|
||||
{
|
||||
OSSL_FN_ULONG *rp = r->d;
|
||||
const OSSL_FN_ULONG *ap = a->d;
|
||||
OSSL_FN_ULONG t, c = 0;
|
||||
size_t rl = (size_t)r->dsize;
|
||||
size_t al = (size_t)a->dsize;
|
||||
size_t l = (rl < al) ? rl : al;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
t = ap[i];
|
||||
rp[i] = ((t << 1) | c) & OSSL_FN_MASK;
|
||||
c = t >> (OSSL_FN_BITS - 1);
|
||||
}
|
||||
|
||||
if (i < rl) {
|
||||
rp[i++] = c;
|
||||
for (; i < rl; i++)
|
||||
rp[i] = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* In respect to shift factor the execution time is invariant of
|
||||
* |n % OSSL_FN_BITS|, but not |n / OSSL_FN_BITS|. Or in other words
|
||||
* pre-condition for constant-time-ness for sufficiently[!] zero-padded
|
||||
* inputs is |n < OSSL_FN_BITS| or |n / OSSL_FN_BITS| being non-secret.
|
||||
*/
|
||||
int OSSL_FN_rshift(OSSL_FN *r, const OSSL_FN *a, int n)
|
||||
{
|
||||
size_t i, nw;
|
||||
unsigned int lb, rb;
|
||||
const OSSL_FN_ULONG *ap = a->d;
|
||||
OSSL_FN_ULONG *rp = r->d;
|
||||
size_t rl = (size_t)r->dsize;
|
||||
size_t al = (size_t)a->dsize;
|
||||
|
||||
if (n < 0) {
|
||||
ERR_raise(ERR_LIB_OSSL_FN, OSSL_FN_R_INVALID_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nw = (size_t)n / OSSL_FN_BITS;
|
||||
rb = (unsigned int)n % OSSL_FN_BITS;
|
||||
lb = OSSL_FN_BITS - rb;
|
||||
|
||||
/*
|
||||
* Work from the low end to support r == a. Each result limb only
|
||||
* depends on the corresponding source limb and the limb just above it,
|
||||
* neither of which has been overwritten yet when walking upward.
|
||||
*/
|
||||
for (i = 0; i < rl; i++) {
|
||||
size_t src_idx = i + nw;
|
||||
OSSL_FN_ULONG limb = 0;
|
||||
|
||||
if (src_idx < al) {
|
||||
limb = ap[src_idx] >> rb;
|
||||
if (rb != 0 && src_idx + 1 < al)
|
||||
limb |= (ap[src_idx + 1] << lb) & OSSL_FN_MASK;
|
||||
}
|
||||
rp[i] = limb;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OSSL_FN_rshift1(OSSL_FN *r, const OSSL_FN *a)
|
||||
{
|
||||
OSSL_FN_ULONG *rp = r->d;
|
||||
const OSSL_FN_ULONG *ap = a->d;
|
||||
size_t rl = (size_t)r->dsize;
|
||||
size_t al = (size_t)a->dsize;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Work from the low end to support r == a. Each result limb only
|
||||
* depends on the corresponding source limb and the limb just above it,
|
||||
* neither of which has been overwritten yet when walking upward.
|
||||
*/
|
||||
for (i = 0; i < rl; i++) {
|
||||
OSSL_FN_ULONG limb = 0;
|
||||
|
||||
if (i < al) {
|
||||
limb = ap[i] >> 1;
|
||||
if (i + 1 < al)
|
||||
limb |= (ap[i + 1] << (OSSL_FN_BITS - 1)) & OSSL_FN_MASK;
|
||||
}
|
||||
rp[i] = limb;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
95
crypto/fn/fn_sqr.c
Normal file
95
crypto/fn/fn_sqr.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/err.h>
|
||||
#include "internal/safe_math.h"
|
||||
#include "crypto/cryptlib.h"
|
||||
#include "crypto/fnerr.h"
|
||||
#include "../bn/bn_local.h" /* For using the low level bignum functions */
|
||||
#include "fn_local.h"
|
||||
|
||||
OSSL_SAFE_MATH_MULU(size_t, size_t, OSSL_SAFE_MATH_MAXU(size_t))
|
||||
|
||||
size_t OSSL_FN_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a)
|
||||
{
|
||||
size_t max, limbs, n_numbers = 1;
|
||||
|
||||
if (r == NULL || a == NULL)
|
||||
return 0;
|
||||
int err = 0;
|
||||
|
||||
max = safe_mul_size_t(2, a->dsize, &err);
|
||||
if ((size_t)r->dsize < max)
|
||||
n_numbers++;
|
||||
limbs = safe_mul_size_t(n_numbers, max, &err);
|
||||
|
||||
return err == 0 ? OSSL_FN_CTX_size(1, n_numbers, limbs) : 0;
|
||||
}
|
||||
|
||||
int OSSL_FN_sqr(OSSL_FN *r, const OSSL_FN *a, OSSL_FN_CTX *ctx)
|
||||
{
|
||||
const void *token = OSSL_FN_CTX_start(ctx);
|
||||
if (token == NULL)
|
||||
return 0;
|
||||
|
||||
size_t al = (size_t)a->dsize;
|
||||
size_t rl = (size_t)r->dsize;
|
||||
size_t max = (size_t)(2 * al);
|
||||
|
||||
int ret = 0;
|
||||
#ifdef BN_SQR_COMBA
|
||||
if (al == 4 && rl >= 8) {
|
||||
bn_sqr_comba4(r->d, a->d);
|
||||
goto end;
|
||||
} else if (al == 8 && rl >= 16) {
|
||||
bn_sqr_comba8(r->d, a->d);
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* rl < max is always true when r == a, so covers that case too */
|
||||
OSSL_FN *rr = r;
|
||||
if (rl < max)
|
||||
if ((rr = OSSL_FN_CTX_get_limbs(ctx, max)) == NULL)
|
||||
goto err;
|
||||
|
||||
OSSL_FN *tmp = NULL;
|
||||
if ((tmp = OSSL_FN_CTX_get_limbs(ctx, max)) == NULL)
|
||||
goto err;
|
||||
|
||||
if (al != 0)
|
||||
bn_sqr_normal(rr->d, a->d, (int)al, tmp->d);
|
||||
|
||||
if (rr != r) {
|
||||
/*
|
||||
* We use OSSL_FN_copy_truncate() here, because OSSL_FN_copy() expects
|
||||
* to make a full copy, but r may be smaller than rr
|
||||
*/
|
||||
OSSL_FN_copy_truncate(r, rr);
|
||||
}
|
||||
|
||||
#ifdef BN_SQR_COMBA
|
||||
end:
|
||||
#endif
|
||||
|
||||
ret = 1;
|
||||
|
||||
/* Zeroise everything above the result, if the r is that large */
|
||||
size_t dif = (rl > max) ? rl - max : 0;
|
||||
OSSL_FN_ULONG *rp = &r->d[max];
|
||||
while (dif > 0) {
|
||||
*rp++ = 0;
|
||||
dif--;
|
||||
}
|
||||
|
||||
err:
|
||||
OSSL_FN_CTX_end(ctx, token);
|
||||
return ret;
|
||||
}
|
||||
29
crypto/int.c
Normal file
29
crypto/int.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "crypto/cryptlib.h"
|
||||
|
||||
size_t ossl_num_bits(size_t value)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long ret = 0;
|
||||
|
||||
/*
|
||||
* It is argued that *on average* constant counter loop performs
|
||||
* not worse [if not better] than one with conditional break or
|
||||
* mask-n-table-lookup-style, because of branch misprediction
|
||||
* penalties.
|
||||
*/
|
||||
for (i = 0; i < sizeof(value) * 8; i++) {
|
||||
ret += (value != 0);
|
||||
value >>= 1;
|
||||
}
|
||||
|
||||
return (int)ret;
|
||||
}
|
||||
623
doc/designs/fixed-size-large-numbers.md
Normal file
623
doc/designs/fixed-size-large-numbers.md
Normal file
|
|
@ -0,0 +1,623 @@
|
|||
Fixed size large numbers
|
||||
========================
|
||||
|
||||
*`BIGNUM` redesign for better constant time calculations*
|
||||
---------------------------------------------------------
|
||||
|
||||
<center>
|
||||
<p><h3>Abstract</h3></p>
|
||||
|
||||
<p>
|
||||
In this design, we explore and define how OpenSSL's `BIGNUM` library can
|
||||
be remodelled for constant-size calculations. Furthermore, we explore and
|
||||
define a fixed size large number library, which never changes the in-memory
|
||||
size of a number once it has been allocated.
|
||||
</p>
|
||||
|
||||
</center>
|
||||
|
||||
### Table of contents:
|
||||
|
||||
- [Background][]
|
||||
- [Goals][]
|
||||
- [Challenges][]
|
||||
- [Design][]
|
||||
- [The `OSSL_FN` type][]
|
||||
- [The `OSSL_FN_CTX` type][]
|
||||
- [The `OSSL_FN_CTX` type, with frames][]
|
||||
- [The `OSSL_FN_CTX` type, without frames][]
|
||||
- [The `BIGNUM` type][]
|
||||
- [Mutability][]
|
||||
- [Memory functionality for `OSSL_FN`][]
|
||||
- [Memory functionality for `OSSL_FN_CTX`][]
|
||||
- [Failures][]
|
||||
- [Repurposing existing code][]
|
||||
- [How to apply `OSSL_FN`][]
|
||||
- [Where to apply `OSSL_FN`][]
|
||||
- [How to apply `OSSL_FN_CTX`][]
|
||||
- [The variant with frames][]
|
||||
- [The variant without frames][]
|
||||
- [Testing][]
|
||||
- [Appendix][]
|
||||
- [Using the C99 flexible array member feature][]
|
||||
|
||||
Background
|
||||
==========
|
||||
|
||||
[Background]: #background
|
||||
|
||||
The current internal definition of OpenSSL's `BIGNUM` looks like this:
|
||||
|
||||
```c
|
||||
struct bignum_st {
|
||||
BN_ULONG *d; /*
|
||||
* Pointer to an array of 'BN_BITS2' bit
|
||||
* chunks. These chunks are organised in
|
||||
* a least significant chunk first order.
|
||||
*/
|
||||
int top; /* Index of last used d +1. */
|
||||
/* The next are internal book keeping for bn_expand. */
|
||||
int dmax; /* Size of the d array. */
|
||||
int neg; /* one if the number is negative */
|
||||
int flags;
|
||||
};
|
||||
```
|
||||
|
||||
The fields `d`, `top` and `dmax` allow the numbers to be quite dynamic in
|
||||
terms of its memory footprint, as it can both increase in size[^1] and
|
||||
decrease in size.[^2]
|
||||
|
||||
Furthermore, the result of any `BIGNUM` operation may be the same `BIGNUM`
|
||||
instance as any of the operands, which means that any `BIGNUM` may have its
|
||||
memory footprint adjusted at any time.
|
||||
|
||||
While this is very flexible, it leaves uncertainties about the time any
|
||||
calculation may take, following any earlier calculation, which is a security
|
||||
vulnerability.
|
||||
|
||||
[^1]: the array `d` is reallocated to a larger size and `dmax` as well as top
|
||||
are updated
|
||||
[^2]: `top` is diminished
|
||||
|
||||
Goals
|
||||
=====
|
||||
|
||||
[Goals]: #goals
|
||||
|
||||
Overall goal: Introduce a new type and API that are inherently constant size
|
||||
to replace the existing `BIGNUM` usage.
|
||||
|
||||
The intention is to enhance this one aspect of constant time calculations.
|
||||
Other aspects are considered out of scope for this design.
|
||||
|
||||
The included sub-goals are:
|
||||
|
||||
* To define a new large number type and accompanying API, that doesn't allow
|
||||
size adjustments of the large numbers once their individual size has been
|
||||
established
|
||||
* To define that large number type and API in such a way it's compatible
|
||||
with the `BIGNUM` type, so that a `BIGNUM` may use an `OSSL_FN` as its
|
||||
backing storage and selected call sites may acquire an `OSSL_FN` view of
|
||||
a `BIGNUM`.
|
||||
* To ensure that the new large number API is constant-size
|
||||
* To repurpose as much as possible of our current `BIGNUM` code for the new
|
||||
large number API, especially our assembler code (with the assumption that
|
||||
everything that doesn't change the `BIGNUM` sizes can be repurposed as is)
|
||||
* To replace all security critical large number calculations so that they
|
||||
are not just constant-size in themselves, but that the whole set of
|
||||
calculations remains constant-size, within OpenSSL code
|
||||
|
||||
Challenges
|
||||
==========
|
||||
|
||||
[Challenges]: #challenges
|
||||
|
||||
The challenges we have are:
|
||||
|
||||
- **`BIGNUM` usage**
|
||||
|
||||
Because `BIGNUM` is a public facing API, it's likely to be used by OpenSSL
|
||||
users. This existing API needs to be backward compatible, but performance
|
||||
isn't necessarily critical.
|
||||
|
||||
- **constant-time through constant-size**
|
||||
|
||||
To make calculation time predictable on a broader scale than on a
|
||||
per-operation basis, there's a need to ensure that each large number being
|
||||
used in the calculations involved has a fixed size, i.e. to avoid the sort
|
||||
of dynamic sizing that the `BIGNUM` functionality does.
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
[Design]: #design
|
||||
|
||||
The overall design defines a new type, `OSSL_FN` (where FN is short for
|
||||
"FIXNUM"), which can somehow be made compatible with `BIGNUM`, but yet be
|
||||
distinct. Early thoughts on this was to make them essentially the same type
|
||||
internally, and cast between them, but unfortunately, a compliant C compiler
|
||||
is very likely to auto-cast between them, making it difficult to keep them
|
||||
separate yet castable back and forth.
|
||||
|
||||
To allow a stricter or more explicit way to remedy the flexibility of the C
|
||||
language, this design therefore defines a `OSSL_FN` which is separate from
|
||||
the `BIGNUM`, yet compatible with BIGNUM insofar that the `BIGNUM` type
|
||||
wraps around the `OSSL_FN` type.
|
||||
|
||||
The compatibility is primarily at the storage and acquisition boundary. A
|
||||
`BIGNUM` may use an `OSSL_FN` as its backing storage, and selected internal
|
||||
crypto call sites that already receive `BIGNUM` values may acquire the
|
||||
embedded `OSSL_FN` and perform security-critical calculations with `OSSL_FN`
|
||||
functions.
|
||||
|
||||
This does not mean that ordinary `BIGNUM` (`BN_`) operation functions are
|
||||
wrappers around corresponding `OSSL_FN` operation functions. `BN_`
|
||||
functions retain their dynamic `BIGNUM` semantics. Conversely, once
|
||||
execution has entered an `OSSL_FN` operation, that operation must remain
|
||||
inside the "`OSSL_FN` only" bubble and must not call functions that take
|
||||
`BIGNUM` arguments.
|
||||
|
||||
This restriction does not apply to low-level helpers that operate only on
|
||||
`BN_ULONG` arrays or primitive limb values, such as existing `bn_` word
|
||||
functions. `BN_ULONG` and `OSSL_FN_ULONG` are compatible, so such helpers
|
||||
may be reused by `OSSL_FN` code as long as they do not allocate, resize, or
|
||||
otherwise operate on `BIGNUM` objects.
|
||||
|
||||
The overall design also defines new associated types to replace their
|
||||
`BIGNUM` counterparts: `OSSL_FN_CTX`, `OSSL_FN_BLINDING`, `OSSL_FN_MONT_CTX`,
|
||||
and `OSSL_FN_RECP_CTX`. Notably, however, the callback type `BN_GENCB`
|
||||
isn't replaced, as it contains nothing `BIGNUM`, and can therefore be reused
|
||||
unchanged with an `OSSL_FN` API.
|
||||
|
||||
The `OSSL_FN` type and API will be designed in such a way to enable it to
|
||||
become public at some point in the future. *The initial version will not be
|
||||
public and will only be used internally within OpenSSL.*
|
||||
|
||||
Let's go over the details
|
||||
|
||||
The `OSSL_FN` type
|
||||
------------------
|
||||
|
||||
[The `OSSL_FN` type]: #the-ossl_fn-type
|
||||
|
||||
The `OSSL_FN` type would be a structure derived from the existing `BIGNUM`
|
||||
type, retaining a minimum amount of data. Just as was previously with
|
||||
`BIGNUM`, the absolute value of the number is stored in a `BN_ULONG` array.
|
||||
`OSSL_FN` itself is unsigned; sign handling remains with `BIGNUM` when
|
||||
`BIGNUM` values are used as carriers.
|
||||
|
||||
```c
|
||||
typedef struct ossl_fn_st OSSL_FN;
|
||||
|
||||
struct ossl_fn_st {
|
||||
/* Flag: alloced with OSSL_FN_new() or OSSL_FN_secure_new() */
|
||||
unsigned int is_dynamically_allocated : 1;
|
||||
/* Flag: alloced with OSSL_FN_secure_new() */
|
||||
unsigned int is_securely_allocated : 1;
|
||||
|
||||
/*
|
||||
* The d array, with its size in number of BN_ULONG.
|
||||
* This stores the number itself
|
||||
*/
|
||||
size_t dsize;
|
||||
BN_ULONG d[];
|
||||
};
|
||||
```
|
||||
|
||||
The `OSSL_FN_CTX` type
|
||||
----------------------
|
||||
|
||||
[The `OSSL_FN_CTX` type]: #the-ossl_fn_ctx-type
|
||||
|
||||
The `OSSL_FN_CTX` type is made to replace the `BN_CTX` type where `OSSL_FN`
|
||||
type is used instead of `BIGNUM`.
|
||||
|
||||
The `OSSL_FN_CTX` type is to be implemented as an arena (a large enough chunk
|
||||
of memory) in which `OSSL_FN` instances are allocated. More in detail, there
|
||||
are two possibilities.
|
||||
|
||||
### The `OSSL_FN_CTX` type, with frames
|
||||
|
||||
[The `OSSL_FN_CTX` type, with frames]: #the-ossl_fn_ctx-type-with-frames
|
||||
|
||||
This variant is intended to mimic all `BN_CTX` functionality. The idea is to
|
||||
create a large `OSSL_FN_CTX` at the top function of a complex calculation, and
|
||||
pass it around to all sub-function calls.
|
||||
|
||||
Each sub-function would begin with starting a frame (using `OSSL_FN_CTX_begin()`,
|
||||
similar in spirit to `BN_CTX_start()`) in the passed `OSSL_FN_CTX` arena,
|
||||
obtain what temporary `OSSL_FN`s it needs from it (using `OSSL_FN_CTX_get()`,
|
||||
similar in spirit to `BN_CTX_get()`), perform what calculations it needs, and
|
||||
finish with ending the frame (using `OSSL_FN_CTX_end()`, similar in spirit to
|
||||
`BN_CTX_end()`), which relinquishing that frame's space in the `OSSL_FN_CTX`
|
||||
arena, and thereby making that same space available for the next sub-function.
|
||||
|
||||
```c
|
||||
typedef struct ossl_fn_ctx_st OSSL_FN_CTX;
|
||||
|
||||
struct ossl_fn_ctx_frame_st; /* forwarding, see below */
|
||||
struct ossl_fn_ctx_st {
|
||||
/*
|
||||
* Pointer to the last OSSL_FN_CTX_start() location (a simple pointer into
|
||||
* the memory area). See the struct ossl_fn_ctx_frame_st definition below
|
||||
* for details.
|
||||
*/
|
||||
struct ossl_fn_ctx_frame_st *last_frame;
|
||||
/*
|
||||
* The arena itself.
|
||||
*/
|
||||
size_t msize; /* bytes */
|
||||
unsigned char memory[];
|
||||
};
|
||||
|
||||
struct ossl_fn_ctx_frame_st {
|
||||
/*
|
||||
* Pointer back to the whole arena where the frame is located, to access
|
||||
* |msize| and |memory| from it.
|
||||
*/
|
||||
struct ossl_fn_ctx_st *arena;
|
||||
/*
|
||||
* Pointer to the previous frame in the arena, allowing OSSL_FN_CTX_end()
|
||||
* to do its job.
|
||||
*/
|
||||
struct ossl_fn_ctx_frame_st *previous_frame;
|
||||
/*
|
||||
* Pointer to the free area of the frame. Every time OSSL_FN_CTX_get() is
|
||||
* called, the current value of this pointer is returned, and it's updated
|
||||
* by incrementing it by the number of bytes given by OSSL_FN_CTX_get().
|
||||
* The available number of bytes is limited by what's left in the arena.
|
||||
*/
|
||||
unsigned char *free_memory;
|
||||
unsigned char memory[];
|
||||
};
|
||||
```
|
||||
|
||||
The arena design requires that the total use of the arena can be predicted
|
||||
at the point of allocating the arena. There is an inherent uncertainty how
|
||||
large an arena should be to accommodate the needs of a large tree of
|
||||
function calls using it. A possible solution is to allocate a very large
|
||||
arena (could 32kB be considered enough?), but it may require some
|
||||
investigation to find out what's reasonable.
|
||||
|
||||
Looking at the current use of `BN_CTX_new`, it can be noted that they are
|
||||
allocated all over current OpenSSL code, so it's easy to assume that each is
|
||||
used in a fairly limited fashion. Furthermore, the `BN_CTX` internals allow
|
||||
for a maximum of 16 `BIGNUM`s. A corresponding arena could the reasonably
|
||||
have the size 16 \* *size of largest fixed number* plus a little extra for
|
||||
bookkeeping purposes.
|
||||
|
||||
### The `OSSL_FN_CTX` type, without frames
|
||||
|
||||
[The `OSSL_FN_CTX` type, without frames]: #the-ossl_fn_ctx-type-without-frames
|
||||
|
||||
Compared to the variant with frames, this `OSSL_FN_CTX` variant is much
|
||||
simpler, but also more heap allocation intense.
|
||||
|
||||
The idea with this one is that each function that needs to obtain temporary
|
||||
`OSSL_FN`s would also create their own `OSSL_FN_CTX`, independently from any
|
||||
other function.
|
||||
|
||||
```c
|
||||
typedef struct ossl_fn_ctx_st OSSL_FN_CTX;
|
||||
|
||||
struct ossl_fn_ctx_st {
|
||||
/*
|
||||
* Pointer to the free area of the arena. Every time OSSL_FN_CTX_get() is
|
||||
* called, the current value of this pointer is returned, and it's updated
|
||||
* by incrementing it by the number of bytes given by OSSL_FN_CTX_get().
|
||||
* The available number of bytes is limited by what's left in the arena.
|
||||
*/
|
||||
unsigned char *free_memory;
|
||||
/*
|
||||
* The arena itself.
|
||||
*/
|
||||
size_t msize; /* bytes */
|
||||
unsigned char memory[];
|
||||
};
|
||||
```
|
||||
|
||||
Other associated types
|
||||
----------------------
|
||||
|
||||
[Other associated types]: #other-associated-types
|
||||
|
||||
There are a few types that, like `BN_CTX` / `OSSL_FN_CTX`, are used to hold
|
||||
a context around some more complicated calculations. Just like `OSSL_FN_CTX`,
|
||||
The `OSSL_FN` variants of these types are made into strictly separate types,
|
||||
not compatible with their `BIGNUM` counterparts.
|
||||
|
||||
| `BIGNUM` types | `OSSL_FN` types |
|
||||
|----------------|--------------------|
|
||||
| `BN_BLINDING` | `OSSL_FN_BLINDING` |
|
||||
| `BN_MONT_CTX` | `OSSL_FN_MONT_CTX` |
|
||||
| `BN_RECP_CTX` | `OSSL_FN_RECP_CTX` |
|
||||
|
||||
Their `OSSL_FN` APIs for these types should be possible to create by
|
||||
repurposing the corresponding `BIGNUM` APIs, with adjustments for the
|
||||
constant-size requirements of all `OSSL_FN` functions.
|
||||
|
||||
The `BIGNUM` type
|
||||
-----------------
|
||||
|
||||
[The `BIGNUM` type]: #the-bignum-type
|
||||
|
||||
The `BIGNUM` type is changed to include a `OSSL_FN` for its data, while
|
||||
retaining the fields that support the dynamic `BIGNUM` semantics:
|
||||
|
||||
```c
|
||||
struct bignum_st {
|
||||
OSSL_FN *data;
|
||||
/* Some of these flags are replicated in OSSL_FN, some are not */
|
||||
int flags;
|
||||
|
||||
BN_ULONG *d; /* Pointer to |data->d| */
|
||||
int top; /* Index of last used d +1. */
|
||||
int dmax; /* Copy of |data->dsize| */
|
||||
int neg; /* One if the number is negative */
|
||||
};
|
||||
```
|
||||
|
||||
In normal public use, `data` is non-NULL and `d` points at `data->d`.
|
||||
Certain internal or otherwise special `BIGNUM`s may still have `data` set to
|
||||
NULL, in which case `d` points directly at a `BN_ULONG` array. Such cases
|
||||
must not be forced to grow an `OSSL_FN` backing object solely to fit this
|
||||
structure. How `OSSL_FN` code should use the `BN_ULONG` data from such
|
||||
`BIGNUM`s remains an implementation detail.
|
||||
|
||||
When structured this way, it's easy to get an `OSSL_FN` out of a `BIGNUM`:
|
||||
|
||||
```c
|
||||
/*
|
||||
* BN_acquire_fn() and BN_release_fn() function together. It is done this
|
||||
* way as a safety measure, to make sure that a BIGNUM doesn't expand an OSSL_FN
|
||||
* that the caller currently has a handle on. However, it's possible to
|
||||
* adjust the size of the OSSL_FN while acquiring it.
|
||||
*/
|
||||
OSSL_FN *BN_acquire_fn(BIGNUM *a, size_t bits)
|
||||
{
|
||||
if ((bn_expand(a, bits)) <= 0)
|
||||
return NULL;
|
||||
/* Implementation may do further acquisition bookkeeping here. */
|
||||
return a->data;
|
||||
}
|
||||
void BN_release_fn(BIGNUM *a)
|
||||
{
|
||||
/* Implementation may do further release bookkeeping here. */
|
||||
}
|
||||
```
|
||||
|
||||
Note that these functions are not designed to be thread-safe. By design,
|
||||
holding pointers to a `BIGNUM` and its wrapped `OSSL_FN` at the same time
|
||||
should only happen in a very short term.
|
||||
|
||||
Mutability
|
||||
----------
|
||||
|
||||
[Mutability]: #mutability
|
||||
|
||||
The understanding is that within a `OSSL_FN` API, `dsize` is immutable as
|
||||
soon as a `OSSL_FN` has been allocated to its target size, except for when
|
||||
the `OSSL_FN` instance is freed.
|
||||
|
||||
When accessed through the `BIGNUM` type (i.e. by the `BIGNUM` API), the
|
||||
`OSSL_FN` size may be reallocated to allow a larger size than initially
|
||||
allocated, and `dsize` may be modified accordingly. The exception is an
|
||||
acquired `OSSL_FN` view. Once a caller has acquired the backing `OSSL_FN`
|
||||
from a `BIGNUM`, that backing size must be treated as immutable until
|
||||
release. The owning `BIGNUM` must not simultaneously be used through `BN_`
|
||||
operations that could resize or otherwise reinterpret the same storage.
|
||||
|
||||
The `OSSL_FN_CTX` API is much more strict. The size of an `OSSL_FN_CTX`
|
||||
instance is immutable after it has been allocated, except when it is freed.
|
||||
|
||||
Memory functionality for `OSSL_FN`
|
||||
----------------------------------
|
||||
|
||||
[Memory functionality for `OSSL_FN`]: #memory-functionality-for-ossl_fn
|
||||
|
||||
We anticipate that we will need the following functions to allocate and
|
||||
deallocate `OSSL_FN`s:
|
||||
|
||||
```c
|
||||
OSSL_FN *OSSL_FN_new(size_t size);
|
||||
void OSSL_FN_free(OSSL_FN *f);
|
||||
```
|
||||
|
||||
Memory functionality for `OSSL_FN_CTX`
|
||||
--------------------------------------
|
||||
|
||||
[Memory functionality for `OSSL_FN_CTX`]: #memory-functionality-for-ossl_fn_ctx
|
||||
|
||||
We anticipate that the `OSSL_FN_CTX` API will look very much like the
|
||||
`BN_CTX` API, except for the allocation functionality:
|
||||
|
||||
```c
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_new(OSSL_LIB_CTX *libctx, size_t arena_size);
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_secure_new(OSSL_LIB_CTX *libctx, size_t arena_size);
|
||||
void OSSL_FN_CTX_free(OSSL_FN_CTX *ctx);
|
||||
|
||||
OSSL_FN *OSSL_FN_CTX_get(OSSL_FN_CTX *ctx, size_t size);
|
||||
```
|
||||
|
||||
*Something to be noted is that `OSSL_FN_CTX_secure_new()` allocates the
|
||||
whole arena in secure memory. The impact compared to allocating individual
|
||||
`OSSL_FN` instances in secure memory is considered minimal.*
|
||||
|
||||
If the variant of `OSSL_FN_CTX` *with frames* is chosen, the following
|
||||
functions will also have to be defined:
|
||||
|
||||
```c
|
||||
int OSSL_FN_CTX_start(OSSL_FN_CTX *ctx);
|
||||
int OSSL_FN_CTX_end(OSSL_FN_CTX *ctx);
|
||||
```
|
||||
|
||||
Failures
|
||||
--------
|
||||
|
||||
[Failures]: #failures
|
||||
|
||||
A fixed size large number introduces new problems, which introduces new ways
|
||||
that the `OSSL_FN` API can fail:
|
||||
|
||||
* Overflow: this will happen when the caller has allocated an improperly
|
||||
sized `OSSL_FN` to store future calculation results in. *This is akin to
|
||||
memory allocation failures in so far that there isn't enough memory space*
|
||||
|
||||
Repurposing existing code
|
||||
=========================
|
||||
|
||||
[Repurposing existing code]: #repurposing-existing-code
|
||||
|
||||
A majority of existing internal `BIGNUM` code operates directly on the `d`
|
||||
array of the existing `BIGNUM` structure, with the size of that array given
|
||||
separately, and are already essentially operating on fixed size numbers.
|
||||
This design assumes that such functions can be repurposed for `OSSL_FN`
|
||||
functionality with zero change, apart from function name changes.
|
||||
|
||||
Furthermore, the remaining functions, which do manipulate the size of the
|
||||
`BIGNUM`, or are public facing `BIGNUM` functions, retain their current
|
||||
`BIGNUM` functionality, including size manipulation within the `BIGNUM`
|
||||
"bubble". They are not wrapped around `OSSL_FN` functions; conversion
|
||||
between `BIGNUM` and `OSSL_FN` happens at top-level crypto call sites,
|
||||
where the embedded `OSSL_FN` is acquired and passed to `OSSL_FN`
|
||||
functions, during whose execution the `OSSL_FN` size is immutable (see
|
||||
[Mutability][]).
|
||||
|
||||
How to apply `OSSL_FN`
|
||||
======================
|
||||
|
||||
[How to apply `OSSL_FN`]: #how-to-apply-ossl_fn
|
||||
|
||||
The purpose of `OSSL_FN` is to make the number constant size (implying
|
||||
enhanced constant time) for a crypto system. To guarantee this with high
|
||||
confidence, any function that performs some sort of numeric operation on a
|
||||
set of input `OSSL_FN`s must only use other functions that only affect the
|
||||
contents of their `d` array, but not its size. Those are typically other
|
||||
`OSSL_FN` functions, or reused bignum functions that receive the `d` array
|
||||
and its size directly.
|
||||
|
||||
Where to apply `OSSL_FN`
|
||||
========================
|
||||
|
||||
[Where to apply `OSSL_FN`]: #where-to-apply-ossl_fn
|
||||
|
||||
`OSSL_FN` should primarily be used instead of `BIGNUM` in internal
|
||||
calculations throughout OpenSSLs libraries. Exceptions can be made where
|
||||
calculations aren't security critical.
|
||||
|
||||
In this, "calculations" is meant in a mathematical sense, i.e. whatever what
|
||||
would be expressed as a mathematical formula is considered a "calculation".
|
||||
|
||||
However, `BIGNUM` has other uses than mere calculations. For example,
|
||||
`BIGNUM` is used as storage of numbers that were originally ASN.1 INTEGERs,
|
||||
and while individual ASN.1 INTEGERs always have a known size, they are
|
||||
usually just one number in a set, and it's often only known at a later time
|
||||
what are the size requirements of the cryptosystem that use them.
|
||||
For example, the size of an RSA key can only be determined when a known
|
||||
number in that key - usually *n* - has been seen by code, and this affects
|
||||
what size all numbers in an RSA key should be adjusted to before doing
|
||||
calculations on them.
|
||||
|
||||
How to apply `OSSL_FN_CTX`
|
||||
==========================
|
||||
|
||||
[How to apply `OSSL_FN_CTX`]: #how-to-apply-ossl_fn_ctx
|
||||
|
||||
The variant with frames
|
||||
-----------------------
|
||||
|
||||
[The variant with frames]: #the-variant-with-frames
|
||||
|
||||
All internal uses of `BN_CTX_new()` and `BN_CTX_new_ex()` are to be replaced
|
||||
with calls of `OSSL_FN_CTX_new()`.
|
||||
|
||||
All internal uses of `BN_CTX_secure_new()` and `BN_CTX_secure_new_ex()` are to
|
||||
be replaced with calls of `OSSL_FN_CTX_secure_new()`.
|
||||
|
||||
All internal uses of `BN_CTX_free()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_free()`.
|
||||
|
||||
All internal uses of `BN_CTX_start()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_start()`.
|
||||
|
||||
All internal uses of `BN_CTX_get()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_get()`.
|
||||
|
||||
All internal uses of `BN_CTX_end()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_end()`.
|
||||
|
||||
The variant without frames
|
||||
--------------------------
|
||||
|
||||
[The variant without frames]: #the-variant-without-frames
|
||||
|
||||
All internal uses of `BN_CTX_new()`, `BN_CTX_new_ex()`, `BN_CTX_secure_new()`,
|
||||
`BN_CTX_secure_new_ex()`, and `BN_CTX_free()` are to be dropped.
|
||||
|
||||
All internal uses of `BN_CTX_start()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_new()`.
|
||||
|
||||
All internal uses of `BN_CTX_get()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_get()`.
|
||||
|
||||
All internal uses of `BN_CTX_end()` are to be replaced with calls of
|
||||
`OSSL_FN_CTX_free()`.
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
[Testing]: #testing
|
||||
|
||||
Functional tests similar to `test/recipes/10-test_bn.t` must be added.
|
||||
|
||||
Timing tests to compare operations on a variety of inputs of different sizes
|
||||
must also be added. These tests should perform operations based on a given
|
||||
fixed number size.
|
||||
|
||||
It should also prove interesting to collect timing statistics for a set of
|
||||
operations using `BIGNUM` in previous OpenSSL versions and compare them with
|
||||
similar timing statistics using `BIGNUM` when reimplemented according to this
|
||||
design.
|
||||
|
||||
Appendix
|
||||
========
|
||||
|
||||
[Appendix]: #appendix
|
||||
|
||||
Using the C99 flexible array member feature
|
||||
-------------------------------------------
|
||||
|
||||
[Using the C99 flexible array member feature]: #using-the-c99-flexible-array-member-feature
|
||||
|
||||
In this design, the C99 feature that's dubbed "flexible array member" is used
|
||||
extensively. This a `struct` member that's an array, that must come last in
|
||||
the struct, and that is incomplete in so far that no array size is given. It
|
||||
can look like this:
|
||||
|
||||
``` C
|
||||
struct t {
|
||||
size_t a;
|
||||
char b;
|
||||
char c[]; /**< flexible array member */
|
||||
};
|
||||
```
|
||||
|
||||
Some attention must be paid to how it's arranged in memory. It's debated
|
||||
whether the offset of a flexible array member's offset from the start of the
|
||||
`struct` is set to be before or after the `struct`'s end padding, i.e. whether
|
||||
`sizeof(struct t) == offsetof(struct t, c)` is true or not in all circumstances.
|
||||
|
||||
Here's how that would differ on a 64-bit system:
|
||||
|
||||
| location of `c` | `offsetof(struct t, a)` | `offsetof(struct t, b)` | `offsetof(struct t, c)` | `sizeof(struct t)` |
|
||||
|-----------------|:-----------------------:|:-----------------------:|:-----------------------:|:------------------:|
|
||||
| before padding | 0 | 8 | 9 | 16 |
|
||||
| after padding | 0 | 8 | 16 | 16 |
|
||||
|
||||
To be noted, `gcc` and `clang` favor "before padding".
|
||||
|
||||
For consistent placement of the flexible array member, one therefore needs to
|
||||
pay attention to possible `struct` padding. Among other methods, one chosen
|
||||
here is to precede the flexible array member with a member whose type is
|
||||
assumed to be large enough that no padding is needed after it, such as
|
||||
`size_t` or a pointer.
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
bn_mul_words, bn_mul_add_words, bn_sqr_words, bn_div_words,
|
||||
bn_add_words, bn_sub_words, bn_mul_comba4, bn_mul_comba8,
|
||||
bn_sqr_comba4, bn_sqr_comba8, bn_cmp_words, bn_mul_normal,
|
||||
bn_sqr_comba4, bn_sqr_comba8, bn_cmp_words, bn_mul_truncated, bn_mul_normal,
|
||||
bn_mul_low_normal, bn_mul_recursive, bn_mul_part_recursive,
|
||||
bn_mul_low_recursive, bn_sqr_normal, bn_sqr_recursive,
|
||||
bn_expand, bn_wexpand, bn_expand2, bn_fix_top, bn_check_top,
|
||||
|
|
@ -32,6 +32,8 @@ library internal functions
|
|||
|
||||
int bn_cmp_words(BN_ULONG *a, BN_ULONG *b, int n);
|
||||
|
||||
void bn_mul_truncated(BN_ULONG *r, int rn, BN_ULONG *a, int na,
|
||||
BN_ULONG *b, int nb);
|
||||
void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b,
|
||||
int nb);
|
||||
void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n);
|
||||
|
|
@ -151,6 +153,11 @@ bn_cmp_words(B<a>, B<b>, B<n>) operates on the B<n> word arrays B<a>
|
|||
and B<b>. It returns 1, 0 and -1 if B<a> is greater than, equal and
|
||||
less than B<b>.
|
||||
|
||||
bn_mul_truncated(B<r>, B<nr>, B<a>, B<na>, B<b>, B<nb>) operates on the
|
||||
B<na> word array B<a>, the B<nb> word array B<b> and the B<nr> word array
|
||||
B<r>. It computes B<a>*B<b> and places the result in B<r>, truncated to
|
||||
B<nr> words.
|
||||
|
||||
bn_mul_normal(B<r>, B<a>, B<na>, B<b>, B<nb>) operates on the B<na>
|
||||
word array B<a>, the B<nb> word array B<b> and the B<na>+B<nb> word
|
||||
array B<r>. It computes B<a>*B<b> and places the result in B<r>.
|
||||
|
|
|
|||
|
|
@ -13,12 +13,58 @@
|
|||
|
||||
#include <openssl/bn.h>
|
||||
#include <limits.h>
|
||||
#include "types.h"
|
||||
|
||||
BIGNUM *bn_wexpand(BIGNUM *a, int words);
|
||||
BIGNUM *bn_expand2(BIGNUM *a, int words);
|
||||
|
||||
void bn_correct_top(BIGNUM *a);
|
||||
|
||||
/*
|
||||
* bn_acquire_ossl_fn() and bn_release() work in tandem, and are
|
||||
* most useful at call sites that temporarily operate on a BIGNUM's
|
||||
* fixed-width OSSL_FN representation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Acquire the OSSL_FN from a BIGNUM. The BIGNUM should no longer be
|
||||
* used until bn_release() is called.
|
||||
*
|
||||
* @param[in] b The BIGNUM instance to get an OSSL_FN from
|
||||
* @param[in] limbs The minimum number of limbs 'b' should be expanded to.
|
||||
* Note that this doesn't set 'top', that's done by
|
||||
* bn_release().
|
||||
* @returns the OSSL_FN instance of the BIGNUM, if there is one
|
||||
* @pre b must not be NULL
|
||||
*/
|
||||
OSSL_FN *bn_acquire_ossl_fn(BIGNUM *b, int limbs);
|
||||
|
||||
/**
|
||||
* Release the BIGNUM from which the OSSL_FN was acquired. This will
|
||||
* adjust the BIGNUM to what was done with its OSSL_FN, and the BIGNUM
|
||||
* can again be used with BN_ functions.
|
||||
*
|
||||
* @param[in] b The BIGNUM instance to release
|
||||
* @param[in] limbs The maximum number of significant limbs. This sets
|
||||
* 'top'.
|
||||
* @pre b and b->data must not be NULL
|
||||
*/
|
||||
void bn_release(BIGNUM *b, int limbs);
|
||||
|
||||
/**
|
||||
* Get the OSSL_FN from a BIGNUM for read-only access. Unlike
|
||||
* bn_acquire_ossl_fn(), this does not acquire or resize the BIGNUM:
|
||||
* the BIGNUM remains fully usable with BN_ functions, no bn_release()
|
||||
* call is needed, and the returned OSSL_FN keeps the BIGNUM's current
|
||||
* allocated width without any expansion. Use this for read-only
|
||||
* operands; use bn_acquire_ossl_fn() for writable results.
|
||||
*
|
||||
* @param[in] bn The BIGNUM instance to get an OSSL_FN from
|
||||
* @returns the OSSL_FN instance of the BIGNUM, or NULL if it has none
|
||||
* @pre bn must not be NULL
|
||||
*/
|
||||
OSSL_FN *bn_get_ossl_fn(const BIGNUM *bn);
|
||||
|
||||
/*
|
||||
* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'.
|
||||
* This is an array r[] of values that are either zero or odd with an
|
||||
|
|
|
|||
|
|
@ -36,4 +36,6 @@ void ossl_malloc_setup_failures(void);
|
|||
int ossl_crypto_alloc_ex_data_intern(int class_index, void *obj,
|
||||
CRYPTO_EX_DATA *ad, int idx);
|
||||
|
||||
size_t ossl_num_bits(size_t value);
|
||||
|
||||
#endif /* OSSL_CRYPTO_CRYPTLIB_H */
|
||||
|
|
|
|||
992
include/crypto/fn.h
Normal file
992
include/crypto/fn.h
Normal file
|
|
@ -0,0 +1,992 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_FN_H
|
||||
#define OPENSSL_FN_H
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/bn_limbs.h>
|
||||
#include <openssl/types.h>
|
||||
#include "crypto/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @type OSSL_FN_ULONG is the type for the OSSL_FN limb. It's made to be
|
||||
* compatible with BN_ULONG (quite literally).
|
||||
*
|
||||
* @def OSSL_FN_BYTES is defined with the size of OSSL_FN_ULONG, measured in
|
||||
* bytes. This is mainly useful where 'sizeof(OSSL_FN_ULONG)' isn't suitable,
|
||||
* such as the C pre-processor.
|
||||
*/
|
||||
|
||||
#ifdef BN_BYTES
|
||||
typedef BN_ULONG OSSL_FN_ULONG;
|
||||
#define OSSL_FN_BYTES BN_BYTES
|
||||
#endif
|
||||
|
||||
#ifndef OSSL_FN_BYTES
|
||||
#error "OpenSSL doesn't support large numbers on this platform"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For practical reasons, we allow allocating OSSL_FNs in terms of limbs (what
|
||||
* the BIGNUM library calls "words"), bytes and bits. The number of bytes and
|
||||
* bits are rounded up to the number of limbs that can fit them.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocate an OSSL_FN in memory.
|
||||
*
|
||||
* @param[in] size The number of limbs for the number itself.
|
||||
* There's an additional few bytes allocated for bookkeeping.
|
||||
* @returns an OSSL_FN instance.
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_new_limbs(size_t size);
|
||||
|
||||
/**
|
||||
* Allocate an OSSL_FN in secure memory.
|
||||
*
|
||||
* @param[in] size The number of limbs for the number itself.
|
||||
* There's an additional few bytes allocated for bookkeeping.
|
||||
* @returns an OSSL_FN instance.
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_secure_new_limbs(size_t size);
|
||||
|
||||
/**
|
||||
* Allocate an OSSL_FN in memory.
|
||||
*
|
||||
* @param[in] size The number of bytes for the number itself.
|
||||
* There's an additional few bytes allocated for bookkeeping.
|
||||
* @returns an OSSL_FN instance.
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_new_bytes(size_t size);
|
||||
|
||||
/**
|
||||
* Allocate an OSSL_FN in secure memory.
|
||||
*
|
||||
* @param[in] size The number of bytes for the number itself.
|
||||
* There's an additional few bytes allocated for bookkeeping.
|
||||
* @returns an OSSL_FN instance.
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_secure_new_bytes(size_t size);
|
||||
|
||||
/**
|
||||
* Allocate an OSSL_FN in memory.
|
||||
*
|
||||
* @param[in] size The number of bits for the number itself.
|
||||
* There's an additional few bytes allocated for bookkeeping.
|
||||
* @returns an OSSL_FN instance.
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_new_bits(size_t size);
|
||||
|
||||
/**
|
||||
* Allocate an OSSL_FN in secure memory.
|
||||
*
|
||||
* @param[in] size The number of bits for the number itself.
|
||||
* There's an additional few bytes allocated for bookkeeping.
|
||||
* @returns an OSSL_FN instance.
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_secure_new_bits(size_t size);
|
||||
|
||||
/**
|
||||
* Free an OSSL_FN instance if it was dynamically allocated.
|
||||
* Free it securely if it was allocated securely.
|
||||
*
|
||||
* @param[in] f The OSSL_FN instance to be freed.
|
||||
*/
|
||||
void OSSL_FN_free(OSSL_FN *f);
|
||||
|
||||
/**
|
||||
* Cleanse and free an OSSL_FN instance if it was dynamically allocated.
|
||||
* Cleanse and free it securely if it was allocated securely.
|
||||
* Merely cleanse it if it was not dynamically allocated.
|
||||
*
|
||||
* @param[in] f The OSSL_FN instance to be freed.
|
||||
*/
|
||||
void OSSL_FN_clear_free(OSSL_FN *f);
|
||||
|
||||
/**
|
||||
* Cleanse the data of an OSSL_FN instance, effectively making it zero.
|
||||
*
|
||||
* @param[in] f The OSSL_FN instance to be cleared.
|
||||
*/
|
||||
void OSSL_FN_clear(OSSL_FN *f);
|
||||
|
||||
/**
|
||||
* Set an OSSL_FN to a single-limb word value.
|
||||
*
|
||||
* @param[out] a The destination OSSL_FN
|
||||
* @param[in] w The OSSL_FN_ULONG word
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note Sets a->d[0] to @p w and zeroes the remaining limbs, so the full
|
||||
* dsize array reflects the value @p w. If a->dsize is 0 there is no
|
||||
* limb to write and the call fails with
|
||||
* OSSL_FN_R_RESULT_ARG_TOO_SMALL (OSSL_FN is fixed-size, so the
|
||||
* destination cannot be grown). The operation is constant-time with
|
||||
* respect to @p w's value; the only branch is on the operand's public
|
||||
* width (dsize).
|
||||
*/
|
||||
int OSSL_FN_set_word(OSSL_FN *a, OSSL_FN_ULONG w);
|
||||
|
||||
/**
|
||||
* Set an OSSL_FN to one.
|
||||
*
|
||||
* @param[out] a The destination OSSL_FN
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note Equivalent to OSSL_FN_set_word(a, 1), provided as a named function
|
||||
* for readability at call sites. Leak profile as for
|
||||
* OSSL_FN_set_word().
|
||||
*/
|
||||
int OSSL_FN_one(OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Set an OSSL_FN to zero.
|
||||
*
|
||||
* @param[out] a The destination OSSL_FN
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This is a plain value assignment, not a secure wipe; use
|
||||
* OSSL_FN_clear() when the limbs may hold secret data and must be wiped
|
||||
* irreversibly. Equivalent to OSSL_FN_set_word(a, 0). Leak profile as
|
||||
* for OSSL_FN_set_word().
|
||||
*/
|
||||
int OSSL_FN_zero(OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Copy the contents of one OSSL_FN instance to another.
|
||||
*
|
||||
* @param[out] a The destination OSSL_FN
|
||||
* @param[in] b The source OSSL_FN
|
||||
* @returns The destination on success, NULL on error.
|
||||
*
|
||||
* @note The destination must be at least as large as the source.
|
||||
* Any limbs beyond the source size are zeroed.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_copy(OSSL_FN *a, const OSSL_FN *b);
|
||||
|
||||
/**
|
||||
* Copy the contents of one OSSL_FN instance to another,
|
||||
* normally the shorter one, truncating the high bytes.
|
||||
*
|
||||
* @param[out] a The destination OSSL_FN
|
||||
* @param[in] b The source OSSL_FN
|
||||
* @returns the destination.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_copy_truncate(OSSL_FN *a, const OSSL_FN *b);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size for an OSSL_FN_CTX.
|
||||
*
|
||||
* @param[in] max_n_frames Maximum number of simultaneously active frames.
|
||||
* This indicates the expected depth of call stack
|
||||
* that the resulting OSSL_FN_CTX will be used in.
|
||||
* Must be at least 1.
|
||||
* @param[in] max_n_numbers Maximum number of simultaneously active OSSL_FN.
|
||||
* Must be 0 if and only if @p max_n_limbs is 0.
|
||||
* @param[in] max_n_limbs Maximum number of simultaneously active OSSL_FN
|
||||
* limbs. Must be 0 if and only if
|
||||
* @p max_n_numbers is 0.
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid argument.
|
||||
*
|
||||
* The returned size is the value to pass to OSSL_FN_CTX_new_size() or
|
||||
* OSSL_FN_CTX_secure_new_size(). It does not include sizeof(OSSL_FN_CTX).
|
||||
*/
|
||||
size_t OSSL_FN_CTX_size(size_t max_n_frames, size_t max_n_numbers,
|
||||
size_t max_n_limbs);
|
||||
|
||||
/**
|
||||
* Allocate a new OSSL_FN_CTX, given a set of input numbers.
|
||||
*
|
||||
* @param[in] libctx OpenSSL library context (currently unused)
|
||||
* @param[in] max_n_frames Maximum number of simultaneously active frames.
|
||||
* This indicates the expected depth of call stack
|
||||
* that the resulting OSSL_FN_CTX will be used in.
|
||||
* @param[in] max_n_numbers Maximum number of simultaneously active OSSL_FN.
|
||||
* @param[in] max_n_limbs Maximum number of simultaneously active OSSL_FN
|
||||
* limbs.
|
||||
* @returns An allocated OSSL_FN_CTX, or NULL on error.
|
||||
*/
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
|
||||
size_t max_n_numbers, size_t max_n_limbs);
|
||||
|
||||
/**
|
||||
* Allocate a new OSSL_FN_CTX with a given arena payload size.
|
||||
*
|
||||
* @param[in] libctx OpenSSL library context (currently unused)
|
||||
* @param[in] size Arena payload size in bytes, typically from
|
||||
* OSSL_FN_CTX_size(). A size of 0 is the error
|
||||
* return of OSSL_FN_CTX_size() and is treated as
|
||||
* an error here too.
|
||||
* @returns An allocated OSSL_FN_CTX, or NULL on error.
|
||||
*/
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_new_size(OSSL_LIB_CTX *libctx, size_t size);
|
||||
|
||||
/**
|
||||
* Allocate a new OSSL_FN_CTX in secure memory, given a set of input numbers.
|
||||
* Other than allocating in secure memory, this function does exactly the same
|
||||
* thing as OSSL_FN_CTX_new().
|
||||
*/
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_secure_new(OSSL_LIB_CTX *libctx, size_t max_n_frames,
|
||||
size_t max_n_numbers, size_t max_n_limbs);
|
||||
|
||||
/**
|
||||
* Allocate a new OSSL_FN_CTX in secure memory with a given arena payload size.
|
||||
*
|
||||
* @param[in] libctx OpenSSL library context (currently unused)
|
||||
* @param[in] size Arena payload size in bytes, typically from
|
||||
* OSSL_FN_CTX_size(). A size of 0 is treated as
|
||||
* an error, as in OSSL_FN_CTX_new_size().
|
||||
* @returns An allocated OSSL_FN_CTX, or NULL on error.
|
||||
*/
|
||||
OSSL_FN_CTX *OSSL_FN_CTX_secure_new_size(OSSL_LIB_CTX *libctx, size_t size);
|
||||
|
||||
/**
|
||||
* Report the peak number of frames, numbers, and limbs that were
|
||||
* simultaneously active during the lifetime of the OSSL_FN_CTX.
|
||||
* This can be used to determine suitable arena parameters for a
|
||||
* given workload.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX to query. This may be NULL.
|
||||
* @param[out] peak_n_frames Peak number of simultaneously active frames
|
||||
* @param[out] peak_n_numbers Peak number of simultaneously active OSSL_FNs
|
||||
* @param[out] peak_n_limbs Peak total limbs across all active OSSL_FNs
|
||||
*
|
||||
* Any of the out parameters may be NULL. If ctx is NULL, all out
|
||||
* parameters that are non-NULL are set to 0.
|
||||
*/
|
||||
void OSSL_FN_CTX_peak_usage(const OSSL_FN_CTX *ctx, size_t *peak_n_frames,
|
||||
size_t *peak_n_numbers, size_t *peak_n_limbs);
|
||||
|
||||
/**
|
||||
* Free an OSSL_FN_CTX.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX to be freed. This may be NULL.
|
||||
*/
|
||||
void OSSL_FN_CTX_free(OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Start a new OSSL_FN_CTX frame. This *must* be called by any function
|
||||
* that wants to get a temporary OSSL_FN from the OSSL_FN_CTX. The function
|
||||
* call this must also clean up with a OSSL_FN_CTX_end() call.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX to start the frame in.
|
||||
* @returns Ownership token of the started frame, NULL on error.
|
||||
* This token must be passed to OSSL_FN_CTX_end().
|
||||
*/
|
||||
const void *OSSL_FN_CTX_start(OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* End the last OSSL_FN_CTX frame, resetting back to the previous
|
||||
* frame. If a function called OSSL_FN_CTX_start(), it *must* call
|
||||
* this function before returning.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX to start the frame in.
|
||||
* @param[in] token Ownership token returned by OSSL_FN_CTX_start().
|
||||
* @returns 1 on success, 0 on error.
|
||||
*
|
||||
* @note The token parameter is validated but not used for choosing a
|
||||
* frame; only the most recent frame can be ended. Passing an incorrect
|
||||
* token indicates a programming error and the function will fail.
|
||||
* If NULL is passed, nothing will be done but the function will return 1.
|
||||
*/
|
||||
int OSSL_FN_CTX_end(OSSL_FN_CTX *ctx, const void *token);
|
||||
|
||||
/**
|
||||
* Get a suitably sized OSSL_FN from an OSSL_FN_CTX.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX
|
||||
* @param[in] limbs The desired size of the resulting OSSL_FN,
|
||||
* in number of limbs.
|
||||
* @returns an OSSL_FN pointer on success, NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_CTX_get_limbs(OSSL_FN_CTX *ctx, size_t limbs);
|
||||
|
||||
/**
|
||||
* Get a suitably sized OSSL_FN from an OSSL_FN_CTX.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX
|
||||
* @param[in] limbs The desired size of the resulting OSSL_FN,
|
||||
* in number of bytes.
|
||||
* @returns an OSSL_FN pointer on success, NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_CTX_get_bytes(OSSL_FN_CTX *ctx, size_t bytes);
|
||||
|
||||
/**
|
||||
* Get a suitably sized OSSL_FN from an OSSL_FN_CTX.
|
||||
*
|
||||
* @param[in] ctx The OSSL_FN_CTX
|
||||
* @param[in] limbs The desired size of the resulting OSSL_FN,
|
||||
* in number of bits.
|
||||
* @returns an OSSL_FN pointer on success, NULL on error.
|
||||
*/
|
||||
OSSL_FN *OSSL_FN_CTX_get_bits(OSSL_FN_CTX *ctx, size_t bits);
|
||||
|
||||
/*
|
||||
* Arithmetic functions treat the OSSL_FN 'd' array as a large 2's complement
|
||||
* unsigned integer, least significant limb first. All carrys or borrows are
|
||||
* extended in the result and otherwise ignored. This makes OSSL_FN functions
|
||||
* act just like operations on C unsigned integer types, but at a larger scale.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return the number of significant bits in an OSSL_FN number.
|
||||
*
|
||||
* @param[in] a The operand
|
||||
* @returns The number of significant bits, or zero if a is zero
|
||||
*/
|
||||
size_t OSSL_FN_num_bits(const OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Compare two OSSL_FN numbers as unsigned integers.
|
||||
*
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @returns 1 if a > b, -1 if a < b, 0 if a == b
|
||||
*/
|
||||
int OSSL_FN_cmp(const OSSL_FN *a, const OSSL_FN *b);
|
||||
|
||||
/**
|
||||
* Test whether bit @p n is set in @p a.
|
||||
*
|
||||
* @param[in] a The operand
|
||||
* @param[in] n The bit index (0 = least significant)
|
||||
* @returns 1 if bit @p n of @p a is set, 0 otherwise.
|
||||
*
|
||||
* @note An out-of-range index (n < 0 or n >= the operand's width in bits)
|
||||
* reads as 0. The only control flow branches on the operand's public
|
||||
* width (its dsize), not on limb values; the returned value is the bit
|
||||
* itself, which is the information the caller asked for.
|
||||
*/
|
||||
int OSSL_FN_is_bit_set(const OSSL_FN *a, int n);
|
||||
|
||||
/**
|
||||
* Test whether the unsigned value of @p a equals the single-limb word @p w.
|
||||
*
|
||||
* @param[in] a The operand
|
||||
* @param[in] w The OSSL_FN_ULONG word to compare against
|
||||
* @returns 1 if the unsigned value of @p a equals @p w, 0 otherwise
|
||||
*
|
||||
* @note Control flow branches only on the operand's public width (its dsize),
|
||||
* not on limb values; the returned value is the equality test the caller
|
||||
* asked for.
|
||||
*/
|
||||
int OSSL_FN_is_word(const OSSL_FN *a, OSSL_FN_ULONG w);
|
||||
|
||||
/**
|
||||
* Test whether @p a is zero.
|
||||
*
|
||||
* @param[in] a The operand
|
||||
* @returns 1 if @p a is zero, 0 otherwise
|
||||
*
|
||||
* @note Equivalent to OSSL_FN_is_word(a, 0), provided as a named predicate for
|
||||
* readability at call sites. Leak profile as for OSSL_FN_is_word():
|
||||
* branches only on the operand's public width (its dsize).
|
||||
*/
|
||||
int OSSL_FN_is_zero(const OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Test whether @p a is one.
|
||||
*
|
||||
* @param[in] a The operand
|
||||
* @returns 1 if @p a is one, 0 otherwise
|
||||
*
|
||||
* @note Equivalent to OSSL_FN_is_word(a, 1), provided as a named predicate for
|
||||
* readability at call sites. Leak profile as for OSSL_FN_is_word():
|
||||
* branches only on the operand's public width (its dsize).
|
||||
*/
|
||||
int OSSL_FN_is_one(const OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Test whether @p a is odd.
|
||||
*
|
||||
* @param[in] a The operand
|
||||
* @returns the least significant bit of @p a (1 if odd, 0 if even)
|
||||
*
|
||||
* @note The only control flow branches on the operand's public width (its
|
||||
* dsize), not on limb values; the returned value is the bit itself,
|
||||
* which is the information the caller asked for.
|
||||
*/
|
||||
int OSSL_FN_is_odd(const OSSL_FN *a);
|
||||
|
||||
/*-
|
||||
* Top/bottom selectors for OSSL_FN_rand() / OSSL_FN_priv_rand(). These are
|
||||
* caller-chosen public parameters (not secrets); OSSL_FN_rand() branches on
|
||||
* them to shape the top and bottom bits of the result. Each TOP_* value is
|
||||
* the number of high bits to force to 1 (0 = unconstrained, 1, 2), matching
|
||||
* the BOTTOM_* numbering (0 = unconstrained, 1 = force the low bit).
|
||||
*/
|
||||
#define OSSL_FN_RAND_TOP_ANY 0
|
||||
#define OSSL_FN_RAND_TOP_ONE 1
|
||||
#define OSSL_FN_RAND_TOP_TWO 2
|
||||
#define OSSL_FN_RAND_BOTTOM_ANY 0
|
||||
#define OSSL_FN_RAND_BOTTOM_ODD 1
|
||||
|
||||
/**
|
||||
* Fill @p rnd with @p bits random bits.
|
||||
*
|
||||
* @param[out] rnd The OSSL_FN for the result
|
||||
* @param[in] bits The number of random bits to generate
|
||||
* @param[in] top Top-bit selector (OSSL_FN_RAND_TOP_*)
|
||||
* @param[in] bottom Bottom-bit selector (OSSL_FN_RAND_BOTTOM_*)
|
||||
* @param[in] strength The private strength of the generated bytes
|
||||
* @param[in] libctx The OpenSSL library context (for the DRBG)
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* Draws from the public DRBG pool via RAND_bytes_ex(). The library context
|
||||
* is taken directly as @p libctx. The random bytes are drawn straight into
|
||||
* rnd->d (no intermediate buffer) and the top/bottom/mask constraints are
|
||||
* applied as limb value operations; a @p rnd too small for @p bits is
|
||||
* reported as OSSL_FN_R_RESULT_ARG_TOO_SMALL rather than grown. Leak
|
||||
* profile as for OSSL_FN_priv_rand().
|
||||
*/
|
||||
int OSSL_FN_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
|
||||
size_t strength, OSSL_LIB_CTX *libctx);
|
||||
|
||||
/**
|
||||
* Fill @p rnd with @p bits random bits from the private DRBG pool.
|
||||
*
|
||||
* @param[out] rnd The OSSL_FN for the result
|
||||
* @param[in] bits The number of random bits to generate
|
||||
* @param[in] top Top-bit selector (OSSL_FN_RAND_TOP_*)
|
||||
* @param[in] bottom Bottom-bit selector (OSSL_FN_RAND_BOTTOM_*)
|
||||
* @param[in] strength The private strength of the generated bytes
|
||||
* @param[in] libctx The OpenSSL library context (for the DRBG)
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* Draws from the private (non-forward-linkable) DRBG pool via
|
||||
* RAND_priv_bytes_ex(). This is the private counterpart of OSSL_FN_rand();
|
||||
* the public/private pool selection is exposed as separate functions rather
|
||||
* than a flag argument. Control flow branches only on @p bits, @p top,
|
||||
* @p bottom (all caller-chosen, public) and on the byte-draw return value,
|
||||
* never on the random bytes themselves; the returned value is the random
|
||||
* number the caller asked for.
|
||||
*
|
||||
* @note See ossl_fn_rand() in crypto/fn/fn_rand.c for the byte-to-limb
|
||||
* shaping mechanics.
|
||||
*/
|
||||
int OSSL_FN_priv_rand(OSSL_FN *rnd, size_t bits, int top, int bottom,
|
||||
size_t strength, OSSL_LIB_CTX *libctx);
|
||||
|
||||
/**
|
||||
* Generate 0 <= r < range.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] range The exclusive upper bound (must be non-zero)
|
||||
* @param[in] strength The private strength of the generated bytes
|
||||
* @param[in] libctx The OpenSSL library context (for the DRBG)
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* Draws from the public DRBG pool. OSSL_FN is unsigned, so no sign
|
||||
* rejection is performed. The loop iteration count leaks the magnitude of
|
||||
* @p range via OSSL_FN_num_bits() and the rejection probability.
|
||||
*
|
||||
* The destination @p r must be sized to hold at least
|
||||
* OSSL_FN_num_bits(@p range) bits. Sizing @p r to hold one extra bit
|
||||
* (OSSL_FN_num_bits(@p range) + 1) additionally enables the optimized
|
||||
* "range = 100..._2" path, which draws n + 1 bits; an exactly-sized @p r
|
||||
* (room for exactly OSSL_FN_num_bits(@p range) bits) uses standard n-bit
|
||||
* rejection sampling instead. An @p r too small for
|
||||
* OSSL_FN_num_bits(@p range) bits fails with OSSL_FN_R_RESULT_ARG_TOO_SMALL.
|
||||
*/
|
||||
int OSSL_FN_rand_range(OSSL_FN *r, const OSSL_FN *range, size_t strength,
|
||||
OSSL_LIB_CTX *libctx);
|
||||
|
||||
/**
|
||||
* Generate 0 <= r < range from the private DRBG pool.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] range The exclusive upper bound (must be non-zero)
|
||||
* @param[in] strength The private strength of the generated bytes
|
||||
* @param[in] libctx The OpenSSL library context (for the DRBG)
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* Draws from the private DRBG pool. Leak profile and destination sizing
|
||||
* as for OSSL_FN_rand_range().
|
||||
*/
|
||||
int OSSL_FN_priv_rand_range(OSSL_FN *r, const OSSL_FN *range,
|
||||
size_t strength, OSSL_LIB_CTX *libctx);
|
||||
|
||||
/**
|
||||
* Shift an OSSL_FN number left by n bits. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] n The number of bits to shift
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_lshift(OSSL_FN *r, const OSSL_FN *a, int n);
|
||||
|
||||
/**
|
||||
* Shift an OSSL_FN number left by one bit. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_lshift1(OSSL_FN *r, const OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Shift an OSSL_FN number right by n bits. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] n The number of bits to shift
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_rshift(OSSL_FN *r, const OSSL_FN *a, int n);
|
||||
|
||||
/**
|
||||
* Shift an OSSL_FN number right by one bit. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_rshift1(OSSL_FN *r, const OSSL_FN *a);
|
||||
|
||||
/**
|
||||
* Add two OSSL_FN numbers.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b);
|
||||
|
||||
/**
|
||||
* Add an OSSL_FN_ULONG word to an OSSL_FN numbers.
|
||||
*
|
||||
* @param[in,out] a The OSSL_FN to add the word to
|
||||
* @param[in] w The OSSL_FN_ULONG word
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_add_word(OSSL_FN *a, OSSL_FN_ULONG w);
|
||||
|
||||
/**
|
||||
* Subtract two OSSL_FN numbers.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b);
|
||||
|
||||
/**
|
||||
* Subtract an OSSL_FN_ULONG word from an OSSL_FN numbers.
|
||||
*
|
||||
* @param[in,out] a The OSSL_FN to subtract the word from
|
||||
* @param[in] w The OSSL_FN_ULONG word
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_sub_word(OSSL_FN *a, OSSL_FN_ULONG w);
|
||||
|
||||
/**
|
||||
* Multiply two OSSL_FN numbers. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for one temporary OSSL_FN with res->dsize limbs, plus one frame
|
||||
* (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mul() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mul().
|
||||
*/
|
||||
size_t OSSL_FN_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b);
|
||||
|
||||
/**
|
||||
* Divide two OSSL_FN numbers. Truncates the result to fit in q and r.
|
||||
*
|
||||
* @param[out] q The OSSL_FN for the quotient
|
||||
* @param[out] r The OSSL_FN for the remainder
|
||||
* @param[in] n The first operand (numerator)
|
||||
* @param[in] d The second operand (denominator)
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for 1 frame, 4 numbers, and 4 * max(n->dsize, d->dsize) + 2 limbs.
|
||||
* Note that this provides an upper bound. Actual use of the arena may be
|
||||
* smaller - see OSSL_FN_div_ctx_size() for an exact, conditional value.
|
||||
*/
|
||||
int OSSL_FN_div(OSSL_FN *q, OSSL_FN *r, const OSSL_FN *n, const OSSL_FN *d,
|
||||
OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_div() needs.
|
||||
*
|
||||
* @param[in] q The OSSL_FN for the quotient, or NULL when
|
||||
* only the remainder is of interest.
|
||||
* @param[in] r The OSSL_FN for the remainder
|
||||
* @param[in] n The first operand (numerator)
|
||||
* @param[in] d The second operand (denominator)
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_div().
|
||||
* When q is NULL, the size is computed for the modulo case, i.e. as if
|
||||
* only the remainder is produced.
|
||||
*/
|
||||
size_t OSSL_FN_div_ctx_size(const OSSL_FN *q, const OSSL_FN *r,
|
||||
const OSSL_FN *n, const OSSL_FN *d);
|
||||
|
||||
/**
|
||||
* Add two OSSL_FN numbers modulo m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for one temporary OSSL_FN with max(a->dsize, b->dsize) + 1
|
||||
* limbs, plus the requirements of OSSL_FN_mod(), plus one frame
|
||||
* (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mod_add(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m, OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod_add() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mod_add().
|
||||
*/
|
||||
size_t OSSL_FN_mod_add_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b, const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Add two OSSL_FN numbers modulo m. This is a quick variant that may be
|
||||
* used if both a and b are less than m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_mod_add_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Subtract two OSSL_FN numbers modulo m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for two temporary OSSL_FNs with m->dsize limbs each, plus an
|
||||
* additional temporary OSSL_FN with m->dsize limbs if r == m, plus the
|
||||
* requirements of OSSL_FN_mod(), plus one frame (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mod_sub(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m, OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod_sub() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mod_sub().
|
||||
*/
|
||||
size_t OSSL_FN_mod_sub_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b, const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Subtract two OSSL_FN numbers modulo m. This is a quick variant that may
|
||||
* be used if a is less than m and b is of the same bit width as m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_mod_sub_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Multiply two OSSL_FN numbers modulo m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for one temporary OSSL_FN with a->dsize + b->dsize limbs
|
||||
* (or 2 * a->dsize limbs if a == b), plus the largest of the
|
||||
* requirements of OSSL_FN_mul(), OSSL_FN_sqr(), and OSSL_FN_mod(),
|
||||
* plus one frame (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mod_mul(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *b,
|
||||
const OSSL_FN *m, OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod_mul() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The first operand
|
||||
* @param[in] b The second operand
|
||||
* @param[in] m The modulus
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mod_mul().
|
||||
*/
|
||||
size_t OSSL_FN_mod_mul_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *b, const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Square an OSSL_FN number modulo m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] m The modulus
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for one temporary OSSL_FN with 2 * a->dsize limbs, plus the
|
||||
* larger of the requirements of OSSL_FN_sqr() and OSSL_FN_mod(),
|
||||
* plus one frame (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mod_sqr(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
|
||||
OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod_sqr() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] m The modulus
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mod_sqr().
|
||||
*/
|
||||
size_t OSSL_FN_mod_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Left shift an OSSL_FN number by 1 bit, modulo m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] m The modulus
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for one temporary OSSL_FN with m->dsize + 1 limbs, plus the
|
||||
* requirements of OSSL_FN_mod(), plus one frame (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mod_lshift1(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m,
|
||||
OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod_lshift1() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] m The modulus
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by
|
||||
* OSSL_FN_mod_lshift1().
|
||||
*/
|
||||
size_t OSSL_FN_mod_lshift1_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Left shift an OSSL_FN number by 1 bit, modulo m. This is a quick
|
||||
* variant that may be used if a is less than m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] m The modulus
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_mod_lshift1_quick(OSSL_FN *r, const OSSL_FN *a, const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Left shift an OSSL_FN number by n bits, modulo m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] n The number of bits to shift
|
||||
* @param[in] m The modulus
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for one temporary OSSL_FN with m->dsize limbs, plus the
|
||||
* requirements of OSSL_FN_mod(), plus one frame (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_mod_lshift(OSSL_FN *r, const OSSL_FN *a, int n, const OSSL_FN *m,
|
||||
OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod_lshift() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] n The number of bits to shift
|
||||
* @param[in] m The modulus
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mod_lshift().
|
||||
*/
|
||||
size_t OSSL_FN_mod_lshift_ctx_size(const OSSL_FN *r, const OSSL_FN *a,
|
||||
int n, const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Left shift an OSSL_FN number by n bits, modulo m. This is a quick
|
||||
* variant that may be used if a is less than m.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] n The number of bits to shift
|
||||
* @param[in] m The modulus
|
||||
* @returns 1 on success, 0 on error
|
||||
*/
|
||||
int OSSL_FN_mod_lshift_quick(OSSL_FN *r, const OSSL_FN *a, int n,
|
||||
const OSSL_FN *m);
|
||||
|
||||
/**
|
||||
* Calculate modulo of two OSSL_FN numbers. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the remainder
|
||||
* @param[in] n The first operand (numerator)
|
||||
* @param[in] d The second operand (denominator)
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function has the same requirements on ctx as OSSL_FN_div().
|
||||
* It is equivalent to OSSL_FN_div(NULL, r, n, d, ctx).
|
||||
*/
|
||||
static inline int OSSL_FN_mod(OSSL_FN *r, const OSSL_FN *n, const OSSL_FN *d,
|
||||
OSSL_FN_CTX *ctx)
|
||||
{
|
||||
return OSSL_FN_div(NULL, r, n, d, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_mod() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the remainder
|
||||
* @param[in] n The numerator
|
||||
* @param[in] d The denominator
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_mod().
|
||||
* This is a thin wrapper around OSSL_FN_div_ctx_size() with a NULL
|
||||
* quotient, since OSSL_FN_mod() is itself a wrapper around OSSL_FN_div().
|
||||
*/
|
||||
static inline size_t OSSL_FN_mod_ctx_size(const OSSL_FN *r,
|
||||
const OSSL_FN *n, const OSSL_FN *d)
|
||||
{
|
||||
return OSSL_FN_div_ctx_size(NULL, r, n, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the square of one OSSL_FN number. Truncates the result to fit in r.
|
||||
*
|
||||
* @param[out] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @param[in] ctx A context to get temporary OSSL_FN
|
||||
* instances from.
|
||||
* @returns 1 on success, 0 on error
|
||||
*
|
||||
* @note This function currently requires that the OSSL_FN_CTX has free
|
||||
* space for two temporary OSSL_FNs, a->dsize * 2 limbs each, plus one
|
||||
* frame (currently 32 bytes).
|
||||
*/
|
||||
int OSSL_FN_sqr(OSSL_FN *r, const OSSL_FN *a, OSSL_FN_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Calculate the arena payload size that OSSL_FN_sqr() needs.
|
||||
*
|
||||
* @param[in] r The OSSL_FN for the result
|
||||
* @param[in] a The operand
|
||||
* @returns The arena payload size, in bytes.
|
||||
* @retval 0 on arithmetic overflow or invalid input.
|
||||
*
|
||||
* The returned size includes any frame budget needed by OSSL_FN_sqr().
|
||||
*/
|
||||
size_t OSSL_FN_sqr_ctx_size(const OSSL_FN *r, const OSSL_FN *a);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
60
include/crypto/fn_intern.h
Normal file
60
include/crypto/fn_intern.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file A set of internal functions to manipulate the OSSL_FN d array, and
|
||||
* for introspection.
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_FN_INTERN_H
|
||||
#define OPENSSL_FN_INTERN_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "crypto/fn.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if OSSL_FN_BYTES == 4
|
||||
/* 32-bit systems */
|
||||
#define OSSL_FN_ULONG_C(n) UINT32_C(n)
|
||||
#define OSSL_FN_ULONG64_C(hi32, lo32) OSSL_FN_ULONG_C(lo32), OSSL_FN_ULONG_C(hi32)
|
||||
#elif OSSL_FN_BYTES == 8
|
||||
/* 64-bit systems */
|
||||
#define OSSL_FN_ULONG_C(n) UINT64_C(n)
|
||||
#define OSSL_FN_ULONG64_C(hi32, lo32) (OSSL_FN_ULONG_C(hi32) << 32 | OSSL_FN_ULONG_C(lo32))
|
||||
#else
|
||||
#error "OpenSSL doesn't support large numbers on this platform"
|
||||
#endif
|
||||
|
||||
int ossl_fn_set_words(OSSL_FN *f, const OSSL_FN_ULONG *words, size_t limbs);
|
||||
const OSSL_FN_ULONG *ossl_fn_get_words(const OSSL_FN *f);
|
||||
|
||||
size_t ossl_fn_get_dsize(const OSSL_FN *f);
|
||||
|
||||
void ossl_fn_set_negative(OSSL_FN *f, bool neg);
|
||||
|
||||
bool ossl_fn_is_negative(const OSSL_FN *f);
|
||||
bool ossl_fn_is_dynamically_allocated(const OSSL_FN *f);
|
||||
bool ossl_fn_is_securely_allocated(const OSSL_FN *f);
|
||||
|
||||
OSSL_FN_ULONG ossl_fn_add_words(OSSL_FN_ULONG *r, size_t rl,
|
||||
const OSSL_FN_ULONG *a, size_t al,
|
||||
const OSSL_FN_ULONG *b, size_t bl);
|
||||
OSSL_FN_ULONG ossl_fn_sub_words(OSSL_FN_ULONG *r, size_t rl,
|
||||
const OSSL_FN_ULONG *a, size_t al,
|
||||
const OSSL_FN_ULONG *b, size_t bl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
38
include/crypto/fnerr.h
Normal file
38
include/crypto/fnerr.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OSSL_CRYPTO_FNERR_H
|
||||
#define OSSL_CRYPTO_FNERR_H
|
||||
#pragma once
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/symhacks.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ossl_err_load_OSSL_FN_strings(void);
|
||||
|
||||
/*
|
||||
* OSSL_FN reason codes.
|
||||
*/
|
||||
#define OSSL_FN_R_DIV_BY_ZERO 101
|
||||
#define OSSL_FN_R_INPUT_NOT_REDUCED 103
|
||||
#define OSSL_FN_R_BITS_TOO_SMALL 105
|
||||
#define OSSL_FN_R_INVALID_RANGE 106
|
||||
#define OSSL_FN_R_INVALID_SHIFT 102
|
||||
#define OSSL_FN_R_RESULT_ARG_TOO_SMALL 100
|
||||
#define OSSL_FN_R_TOO_MANY_ITERATIONS 107
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -13,6 +13,10 @@
|
|||
#define OSSL_CRYPTO_TYPES_H
|
||||
#pragma once
|
||||
|
||||
/* At some point in the future, this may move to include/openssl/types.h */
|
||||
typedef struct ossl_fn_st OSSL_FN;
|
||||
typedef struct ossl_fn_ctx_st OSSL_FN_CTX;
|
||||
|
||||
#ifdef OPENSSL_NO_DEPRECATED_3_0
|
||||
typedef struct rsa_st RSA;
|
||||
typedef struct rsa_meth_st RSA_METHOD;
|
||||
|
|
|
|||
|
|
@ -21,36 +21,15 @@
|
|||
#ifndef OPENSSL_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/types.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/bnerr.h>
|
||||
#include <openssl/bn_limbs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 64-bit processor with LP64 ABI
|
||||
*/
|
||||
#ifdef SIXTY_FOUR_BIT_LONG
|
||||
typedef unsigned long BN_ULONG;
|
||||
#define BN_BYTES 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 64-bit processor other than LP64 ABI
|
||||
*/
|
||||
#ifdef SIXTY_FOUR_BIT
|
||||
typedef unsigned long long BN_ULONG;
|
||||
#define BN_BYTES 8
|
||||
#endif
|
||||
|
||||
#ifdef THIRTY_TWO_BIT
|
||||
typedef unsigned int BN_ULONG;
|
||||
#define BN_BYTES 4
|
||||
#endif
|
||||
|
||||
#define BN_BITS2 (BN_BYTES * 8)
|
||||
#define BN_BITS (BN_BITS2 * 2)
|
||||
#define BN_TBIT ((BN_ULONG)1 << (BN_BITS2 - 1))
|
||||
|
|
|
|||
48
include/openssl/bn_limbs.h
Normal file
48
include/openssl/bn_limbs.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Defines the type of large integer limbs.
|
||||
*
|
||||
* The large number is composed of words, the size of which is assumed to
|
||||
* be optimal for the platform it's built for. In many large number texts,
|
||||
* these words are called "limb". The BIGNUM library also calls this "word".
|
||||
*
|
||||
* In OpenSSL code, the BIGNUM "limb" is represented with the type macro
|
||||
* BN_ULONG.
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_BN_LIMBS_H
|
||||
#define OPENSSL_BN_LIMBS_H
|
||||
#pragma once
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
/*
|
||||
* 64-bit processor with LP64 ABI
|
||||
*/
|
||||
#ifdef SIXTY_FOUR_BIT_LONG
|
||||
typedef unsigned long BN_ULONG;
|
||||
#define BN_BYTES 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 64-bit processor other than LP64 ABI
|
||||
*/
|
||||
#ifdef SIXTY_FOUR_BIT
|
||||
typedef unsigned long long BN_ULONG;
|
||||
#define BN_BYTES 8
|
||||
#endif
|
||||
|
||||
#ifdef THIRTY_TWO_BIT
|
||||
typedef unsigned int BN_ULONG;
|
||||
#define BN_BYTES 4
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -105,6 +105,7 @@ extern "C" {
|
|||
#define ERR_LIB_OSSL_ENCODER 59
|
||||
#define ERR_LIB_OSSL_DECODER 60
|
||||
#define ERR_LIB_HTTP 61
|
||||
#define ERR_LIB_OSSL_FN 62
|
||||
|
||||
#define ERR_LIB_USER 128
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ The number `{nn}` is (somewhat loosely) grouped as follows:
|
|||
|
||||
00-04 sanity, internal and essential API tests
|
||||
05-09 individual symmetric cipher algorithms
|
||||
10-14 math (bignum)
|
||||
10-14 math (bignum and ossl_fn)
|
||||
15-19 individual asymmetric cipher algorithms
|
||||
20-24 openssl commands (some otherwise not tested)
|
||||
25-29 certificate forms, generation and verification
|
||||
|
|
|
|||
|
|
@ -1830,6 +1830,49 @@ err:
|
|||
return st;
|
||||
}
|
||||
|
||||
static int file_modinv(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *m = NULL, *ainv_check = NULL, *ainv = NULL;
|
||||
int st = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(m = getBN(s, "M"))
|
||||
|| !TEST_ptr(ainv_check = getBN(s, "ModInv")))
|
||||
goto err;
|
||||
|
||||
if (BN_is_negative(ainv_check)) {
|
||||
/* a negative testcase */
|
||||
ERR_set_mark();
|
||||
if (!TEST_ptr_null(BN_mod_inverse(NULL, a, m, ctx))
|
||||
|| !TEST_int_eq(ERR_GET_LIB(ERR_peek_last_error()), ERR_LIB_BN)
|
||||
|| !TEST_int_eq(ERR_GET_REASON(ERR_peek_last_error()),
|
||||
BN_R_NO_INVERSE))
|
||||
goto err;
|
||||
ERR_pop_to_mark();
|
||||
|
||||
st = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* the inverse is unique in [1,M) */
|
||||
if (!TEST_ptr(ainv = BN_mod_inverse(NULL, a, m, ctx))
|
||||
|| !equalBN("inv(A) (mod M)", ainv_check, ainv))
|
||||
goto err;
|
||||
|
||||
/* verify A * ainv == 1 (mod M) */
|
||||
if (!TEST_true(BN_mod_mul(ainv, a, ainv, m, ctx))
|
||||
|| !TEST_true(BN_is_one(ainv)))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
BN_free(a);
|
||||
BN_free(m);
|
||||
BN_free(ainv_check);
|
||||
BN_free(ainv);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_gcd(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *b = NULL, *gcd = NULL, *ret = NULL;
|
||||
|
|
@ -3324,6 +3367,7 @@ static int file_test_run(STANZA *s)
|
|||
{ "ModExp", file_modexp },
|
||||
{ "Exp", file_exp },
|
||||
{ "ModSqrt", file_modsqrt },
|
||||
{ "ModInv", file_modinv },
|
||||
{ "GCD", file_gcd },
|
||||
};
|
||||
int numtests = OSSL_NELEM(filetests);
|
||||
|
|
|
|||
|
|
@ -1127,6 +1127,21 @@ IF[{- !$disabled{tests} -}]
|
|||
DEPEND[rsa_x931_test]=../libcrypto.a libtestutil.a
|
||||
ENDIF
|
||||
|
||||
PROGRAMS{noinst}=fn_internal_test
|
||||
SOURCE[fn_internal_test]=fn_internal_test.c
|
||||
INCLUDE[fn_internal_test]=.. ../include ../crypto/fn ../apps/include
|
||||
DEPEND[fn_internal_test]=../libcrypto.a libtestutil.a
|
||||
|
||||
PROGRAMS{noinst}=fn_api_test
|
||||
SOURCE[fn_api_test]=fn_api_test.c
|
||||
INCLUDE[fn_api_test]=.. ../include ../crypto/fn ../apps/include
|
||||
DEPEND[fn_api_test]=../libcrypto.a libtestutil.a
|
||||
|
||||
PROGRAMS{noinst}=fntest
|
||||
SOURCE[fntest]=fntest.c
|
||||
INCLUDE[fntest]=.. ../include ../crypto/fn ../apps/include
|
||||
DEPEND[fntest]=../libcrypto.a libtestutil.a
|
||||
|
||||
SOURCE[bn_internal_test]=bn_internal_test.c
|
||||
INCLUDE[bn_internal_test]=.. ../include ../crypto/bn ../apps/include
|
||||
DEPEND[bn_internal_test]=../libcrypto.a libtestutil.a
|
||||
|
|
|
|||
3598
test/fn_api_test.c
Normal file
3598
test/fn_api_test.c
Normal file
File diff suppressed because it is too large
Load diff
457
test/fn_internal_test.c
Normal file
457
test/fn_internal_test.c
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Internal tests of OSSL_FN
|
||||
*
|
||||
* This tests OSSL_FN internals only, i.e. anything that requires including
|
||||
* ../crypto/fn/fn_local.h, such as introspection.
|
||||
*/
|
||||
|
||||
#include "crypto/fn.h"
|
||||
#include "crypto/fn_intern.h"
|
||||
#include "fn_local.h"
|
||||
#include "testutil.h"
|
||||
|
||||
static int test_struct(void)
|
||||
{
|
||||
TEST_note("OSSL_FN struct is %zu bytes\n", sizeof(OSSL_FN));
|
||||
TEST_note("OSSL_FN 'd' array starts at offset %zu\n", offsetof(OSSL_FN, d));
|
||||
|
||||
/*
|
||||
* Note: The working theory for the moment is that the 'd' array *must*
|
||||
* align with the end of the OSSL_FN struct.
|
||||
* If it turns out that this isn't the case, we can choose to run
|
||||
* TEST_size_t_eq() for display purposes, but ignore its result and
|
||||
* return 1.
|
||||
*/
|
||||
return TEST_size_t_eq(sizeof(OSSL_FN), offsetof(OSSL_FN, d));
|
||||
}
|
||||
|
||||
static int test_alloc(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN *f = NULL;
|
||||
const OSSL_FN_ULONG *u = NULL;
|
||||
|
||||
/*
|
||||
* OSSL_FN_new_bits() calls OSSL_FN_new_bytes(), which calls
|
||||
* OSSL_FN_new_limbs(), so we're exercising all three in one go.
|
||||
*
|
||||
* The curious size formula is there to check that the number of bits that
|
||||
* is passed in gets properly rounded up to the number of limbs they fit
|
||||
* into.
|
||||
* This formula aims for two limbs (each of which is at least 32 bits),
|
||||
* shaving off 17 bits for demonstration purposes.
|
||||
*/
|
||||
if (!TEST_ptr(f = OSSL_FN_new_bits(sizeof(OSSL_FN_ULONG) * 16 - 17))
|
||||
|| !TEST_true(ossl_fn_is_dynamically_allocated(f))
|
||||
|| !TEST_false(ossl_fn_is_securely_allocated(f))
|
||||
|| !TEST_size_t_eq(ossl_fn_get_dsize(f), 2)
|
||||
|| !TEST_ptr(u = ossl_fn_get_words(f))
|
||||
|| !TEST_size_t_eq(u[0], 0)
|
||||
|| !TEST_size_t_eq(u[1], 0))
|
||||
ret = 0;
|
||||
OSSL_FN_free(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_secure_alloc(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN *f = NULL;
|
||||
const OSSL_FN_ULONG *u = NULL;
|
||||
|
||||
/*
|
||||
* OSSL_FN_secure_new_bits() calls OSSL_FN_secure_new_bytes(), which calls
|
||||
* OSSL_FN_secure_new_limbs(), so we're exercising all three in one go.
|
||||
*
|
||||
* The curious size formula is there to check that the number of bits that
|
||||
* is passed in gets properly rounded up to the number of limbs they fit
|
||||
* into.
|
||||
* This formula aims for two limbs (each of which is at least 32 bits),
|
||||
* shaving off 17 bits for demonstration purposes.
|
||||
*/
|
||||
if (!TEST_ptr(f = OSSL_FN_secure_new_bits(sizeof(OSSL_FN_ULONG) * 16 - 17))
|
||||
|| !TEST_true(ossl_fn_is_dynamically_allocated(f))
|
||||
|| !TEST_true(ossl_fn_is_securely_allocated(f))
|
||||
|| !TEST_size_t_eq(ossl_fn_get_dsize(f), 2)
|
||||
|| !TEST_ptr(u = ossl_fn_get_words(f))
|
||||
|| !TEST_size_t_eq(u[0], 0)
|
||||
|| !TEST_size_t_eq(u[1], 0))
|
||||
ret = 0;
|
||||
OSSL_FN_free(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_ctx(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
OSSL_FN *f = NULL;
|
||||
const void *token = NULL;
|
||||
|
||||
/*
|
||||
* Make a CTX that is likely to contain two 2048-bit or one 4096-bit OSSL_FN
|
||||
* and one frame (let's overestimate its size to 128 bytes).
|
||||
* Note that OSSL_FN_CTX_new() takes a maximum number of limbs in the last
|
||||
* parameter, so we must ensure that we get that number right.
|
||||
*/
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new(NULL, 1, 2, 4096 / OSSL_FN_BITS))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check that we can get 1 2048-bit OSSL_FN instance, and check its metadata */
|
||||
if (!TEST_ptr(token = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_false(ossl_fn_is_dynamically_allocated(f))
|
||||
|| !TEST_false(ossl_fn_is_securely_allocated(f)))
|
||||
ret = 0;
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check that we can get 2 2048-bit OSSL_FN instances, but not 3 */
|
||||
if (!TEST_ptr(token = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_ptr_null(f = OSSL_FN_CTX_get_bits(ctx, 2048)))
|
||||
ret = 0;
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check that we can get 1 4096-bit OSSL_FN instance, but not 2 */
|
||||
if (!TEST_ptr(token = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 4096))
|
||||
|| !TEST_ptr_null(f = OSSL_FN_CTX_get_bits(ctx, 2048)))
|
||||
ret = 0;
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_ctx_size(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
OSSL_FN *f = NULL;
|
||||
const void *token = NULL;
|
||||
size_t size = OSSL_FN_CTX_size(1, 2, 4096 / OSSL_FN_BITS);
|
||||
|
||||
if (!TEST_size_t_ne(size, 0)
|
||||
|| !TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL, size))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!TEST_ptr(token = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_false(ossl_fn_is_dynamically_allocated(f))
|
||||
|| !TEST_false(ossl_fn_is_securely_allocated(f))
|
||||
|| !TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_ptr_null(f = OSSL_FN_CTX_get_bits(ctx, 2048)))
|
||||
ret = 0;
|
||||
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token)))
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
|
||||
/*
|
||||
* Force each term of OSSL_FN_CTX_size() to overflow in turn,
|
||||
* keeping the others at a minimal valid context (1 frame, 1
|
||||
* number, 1 limb) so only the overflowing term is unrealistic.
|
||||
*/
|
||||
if (!TEST_size_t_eq(OSSL_FN_CTX_size(SIZE_MAX, 1, 1), 0))
|
||||
ret = 0;
|
||||
if (!TEST_size_t_eq(OSSL_FN_CTX_size(1, SIZE_MAX, 1), 0))
|
||||
ret = 0;
|
||||
if (!TEST_size_t_eq(OSSL_FN_CTX_size(1, 1, SIZE_MAX), 0))
|
||||
ret = 0;
|
||||
/* A context must have at least one frame. */
|
||||
if (!TEST_size_t_eq(OSSL_FN_CTX_size(0, 1, 1), 0))
|
||||
ret = 0;
|
||||
/*
|
||||
* Numbers and limbs must both be present or both absent: a context
|
||||
* with one budget but not the other can never allocate a usable
|
||||
* number, since OSSL_FN_CTX_get_limbs() allocates the OSSL_FN header
|
||||
* and its limbs together.
|
||||
*/
|
||||
if (!TEST_size_t_eq(OSSL_FN_CTX_size(1, 0, 1), 0))
|
||||
ret = 0;
|
||||
if (!TEST_size_t_eq(OSSL_FN_CTX_size(1, 1, 0), 0))
|
||||
ret = 0;
|
||||
if (!TEST_ptr_null(OSSL_FN_CTX_new_size(NULL, SIZE_MAX)))
|
||||
ret = 0;
|
||||
/* A size of 0 is the error return of OSSL_FN_CTX_size(). */
|
||||
if (!TEST_ptr_null(OSSL_FN_CTX_new_size(NULL, 0)))
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_secure_ctx(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
OSSL_FN *f = NULL;
|
||||
const void *token = NULL;
|
||||
|
||||
/*
|
||||
* Make a CTX that is likely to contain two 2048-bit OSSL_FN and one frame
|
||||
* (let's overestimate its size to 128 bytes).
|
||||
* Note that OSSL_FN_CTX_new() takes a maximum number of limbs in the last
|
||||
* parameter, so we must ensure that we get that number right.
|
||||
*/
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_secure_new(NULL, 1, 2, 2048 / OSSL_FN_BITS))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check that we can get 1 2048-bit OSSL_FN instance, and check its metadata */
|
||||
if (!TEST_ptr(token = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_false(ossl_fn_is_dynamically_allocated(f))
|
||||
|| !TEST_true(ossl_fn_is_securely_allocated(f)))
|
||||
ret = 0;
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token))) {
|
||||
ret = 0;
|
||||
/* It's pointless to try more tests after this failure */
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_secure_ctx_size(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
OSSL_FN *f = NULL;
|
||||
const void *token = NULL;
|
||||
size_t size = OSSL_FN_CTX_size(1, 1, 2048 / OSSL_FN_BITS);
|
||||
|
||||
if (!TEST_size_t_ne(size, 0)
|
||||
|| !TEST_ptr(ctx = OSSL_FN_CTX_secure_new_size(NULL, size))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!TEST_ptr(token = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048))
|
||||
|| !TEST_false(ossl_fn_is_dynamically_allocated(f))
|
||||
|| !TEST_true(ossl_fn_is_securely_allocated(f))
|
||||
|| !TEST_ptr_null(f = OSSL_FN_CTX_get_bits(ctx, 2048)))
|
||||
ret = 0;
|
||||
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token)))
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
|
||||
if (!TEST_ptr_null(OSSL_FN_CTX_secure_new_size(NULL, SIZE_MAX)))
|
||||
ret = 0;
|
||||
/* A size of 0 is the error return of OSSL_FN_CTX_size(). */
|
||||
if (!TEST_ptr_null(OSSL_FN_CTX_secure_new_size(NULL, 0)))
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_ctx_peak_used(void)
|
||||
{
|
||||
int ret = 1;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
OSSL_FN *f = NULL;
|
||||
const void *token1 = NULL;
|
||||
const void *token2 = NULL;
|
||||
size_t frames, numbers, limbs;
|
||||
size_t limbs_2048 = 2048 / 8 / OSSL_FN_BYTES;
|
||||
size_t limbs_4096 = 4096 / 8 / OSSL_FN_BYTES;
|
||||
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new(NULL, 2, 4, 256))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fresh context.
|
||||
*/
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 0)
|
||||
|| !TEST_size_t_eq(numbers, 0)
|
||||
|| !TEST_size_t_eq(limbs, 0))
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* NULL context: all out parameters set to 0.
|
||||
*/
|
||||
OSSL_FN_CTX_peak_usage(NULL, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 0)
|
||||
|| !TEST_size_t_eq(numbers, 0)
|
||||
|| !TEST_size_t_eq(limbs, 0))
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* NULL out parameters are tolerated.
|
||||
*/
|
||||
OSSL_FN_CTX_peak_usage(ctx, NULL, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Start frame 1.
|
||||
*/
|
||||
if (!TEST_ptr(token1 = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 1)
|
||||
|| !TEST_size_t_eq(numbers, 0)
|
||||
|| !TEST_size_t_eq(limbs, 0))
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* Allocate one number in frame 1.
|
||||
*/
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048)))
|
||||
ret = 0;
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 1)
|
||||
|| !TEST_size_t_eq(numbers, 1)
|
||||
|| !TEST_size_t_eq(limbs, limbs_2048))
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* Start frame 2 (nested inside frame 1).
|
||||
*/
|
||||
if (!TEST_ptr(token2 = OSSL_FN_CTX_start(ctx))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 2)
|
||||
|| !TEST_size_t_eq(numbers, 1)
|
||||
|| !TEST_size_t_eq(limbs, limbs_2048))
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* Allocate one number in frame 2.
|
||||
*/
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 4096)))
|
||||
ret = 0;
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 2)
|
||||
|| !TEST_size_t_eq(numbers, 2)
|
||||
|| !TEST_size_t_eq(limbs, limbs_2048 + limbs_4096))
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* Allocate a second number in frame 2.
|
||||
*/
|
||||
if (!TEST_ptr(f = OSSL_FN_CTX_get_bits(ctx, 2048)))
|
||||
ret = 0;
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 2)
|
||||
|| !TEST_size_t_eq(numbers, 3)
|
||||
|| !TEST_size_t_eq(limbs, limbs_2048 + limbs_4096 + limbs_2048))
|
||||
ret = 0;
|
||||
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token2))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* After ending frame 2: peaks must not decrease.
|
||||
*/
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 2)
|
||||
|| !TEST_size_t_eq(numbers, 3)
|
||||
|| !TEST_size_t_eq(limbs, limbs_2048 + limbs_4096 + limbs_2048))
|
||||
ret = 0;
|
||||
|
||||
if (!TEST_true(OSSL_FN_CTX_end(ctx, token1))) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* After ending frame 1: peaks still preserved.
|
||||
*/
|
||||
OSSL_FN_CTX_peak_usage(ctx, &frames, &numbers, &limbs);
|
||||
if (!TEST_size_t_eq(frames, 2)
|
||||
|| !TEST_size_t_eq(numbers, 3)
|
||||
|| !TEST_size_t_eq(limbs, limbs_2048 + limbs_4096 + limbs_2048))
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
ADD_TEST(test_struct);
|
||||
ADD_TEST(test_alloc);
|
||||
ADD_TEST(test_secure_alloc);
|
||||
ADD_TEST(test_ctx);
|
||||
ADD_TEST(test_ctx_size);
|
||||
ADD_TEST(test_secure_ctx);
|
||||
ADD_TEST(test_secure_ctx_size);
|
||||
ADD_TEST(test_ctx_peak_used);
|
||||
|
||||
return 1;
|
||||
}
|
||||
766
test/fntest.c
Normal file
766
test/fntest.c
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
/*
|
||||
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "crypto/fn.h"
|
||||
#include "crypto/bn.h"
|
||||
#include "crypto/fn_intern.h"
|
||||
#include "internal/nelem.h"
|
||||
#include "testutil.h"
|
||||
|
||||
/*
|
||||
* This is a stanza-driven arithmetic test for OSSL_FN. Non-stanza API tests
|
||||
* belong in fn_api_test.
|
||||
*/
|
||||
|
||||
typedef struct filetest_st {
|
||||
const char *name;
|
||||
int (*func)(STANZA *s);
|
||||
int skipped;
|
||||
} FILETEST;
|
||||
|
||||
static const char *findattr(STANZA *s, const char *key)
|
||||
{
|
||||
int i = s->numpairs;
|
||||
PAIR *pp = s->pairs;
|
||||
|
||||
for (; --i >= 0; pp++)
|
||||
if (OPENSSL_strcasecmp(pp->key, key) == 0)
|
||||
return pp->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int parseBN(BIGNUM **out, const char *in)
|
||||
{
|
||||
*out = NULL;
|
||||
return BN_hex2bn(out, in);
|
||||
}
|
||||
|
||||
static BIGNUM *getBN(STANZA *s, const char *attribute)
|
||||
{
|
||||
const char *hex;
|
||||
BIGNUM *ret = NULL;
|
||||
|
||||
if ((hex = findattr(s, attribute)) == NULL) {
|
||||
TEST_error("%s:%d: Can't find %s", s->test_file, s->start, attribute);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (parseBN(&ret, hex) != (int)strlen(hex)) {
|
||||
TEST_error("Could not decode '%s'", hex);
|
||||
BN_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int getint(STANZA *s, int *out, const char *attribute)
|
||||
{
|
||||
BIGNUM *ret;
|
||||
BN_ULONG word;
|
||||
int st = 0;
|
||||
|
||||
if (!TEST_ptr(ret = getBN(s, attribute))
|
||||
|| !TEST_uint64_t_le(word = BN_get_word(ret), INT_MAX))
|
||||
goto err;
|
||||
|
||||
*out = (int)word;
|
||||
st = 1;
|
||||
err:
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int equalBN(const char *op, const BIGNUM *expected, const BIGNUM *actual)
|
||||
{
|
||||
if (!TEST_BN_eq(expected, actual)) {
|
||||
TEST_error("unexpected %s value", op);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Number of limbs needed to hold bn's value, equivalent to the (properly
|
||||
* adjusted) BIGNUM 'top' field, which is not directly accessible here.
|
||||
*/
|
||||
static int limbs(const BIGNUM *bn)
|
||||
{
|
||||
int ret = (BN_num_bits(bn) + BN_BITS2 - 1) / BN_BITS2;
|
||||
|
||||
return ret > 0 ? ret : 1;
|
||||
}
|
||||
|
||||
static int set_result_addsub(OSSL_FN *r, OSSL_FN *a, int a_neg,
|
||||
OSSL_FN *b, int b_neg, int *neg)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
*neg = 0;
|
||||
if (a_neg == b_neg) {
|
||||
*neg = a_neg;
|
||||
return OSSL_FN_add(r, a, b);
|
||||
}
|
||||
|
||||
cmp = OSSL_FN_cmp(a, b);
|
||||
if (cmp >= 0) {
|
||||
*neg = a_neg;
|
||||
return OSSL_FN_sub(r, a, b);
|
||||
}
|
||||
|
||||
*neg = b_neg;
|
||||
return OSSL_FN_sub(r, b, a);
|
||||
}
|
||||
|
||||
static int file_sum(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *b = NULL, *sum = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *bf = NULL, *rf = NULL;
|
||||
int a_neg = 0, b_neg = 0, r_neg = 0, st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(b = getBN(s, "B"))
|
||||
|| !TEST_ptr(sum = getBN(s, "Sum"))
|
||||
|| !TEST_ptr(ret = BN_new()))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
b_neg = BN_is_negative(b);
|
||||
nlimbs = limbs(sum);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(bf = bn_get_ossl_fn(b))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
|
||||
if (!TEST_true(set_result_addsub(rf, af, a_neg, bf, b_neg, &r_neg)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, r_neg);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A + B", sum, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
BN_free(a);
|
||||
BN_free(b);
|
||||
BN_free(sum);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_product(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *b = NULL, *product = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *bf = NULL, *rf = NULL;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
int a_neg = 0, b_neg = 0, r_neg = 0, st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(b = getBN(s, "B"))
|
||||
|| !TEST_ptr(product = getBN(s, "Product"))
|
||||
|| !TEST_ptr(ret = BN_new()))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
b_neg = BN_is_negative(b);
|
||||
r_neg = a_neg ^ b_neg;
|
||||
nlimbs = limbs(product);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(bf = bn_get_ossl_fn(b))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_mul_ctx_size(rf, af, bf))))
|
||||
goto err;
|
||||
|
||||
if (!TEST_true(OSSL_FN_mul(rf, af, bf, ctx)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, r_neg);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A * B", product, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
BN_free(a);
|
||||
BN_free(b);
|
||||
BN_free(product);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_square(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *square = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *rf = NULL;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
int st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(square = getBN(s, "Square"))
|
||||
|| !TEST_ptr(ret = BN_new()))
|
||||
goto err;
|
||||
|
||||
nlimbs = limbs(square);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_sqr_ctx_size(rf, af))))
|
||||
goto err;
|
||||
|
||||
if (!TEST_true(OSSL_FN_sqr(rf, af, ctx)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, 0);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A^2", square, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
BN_free(a);
|
||||
BN_free(square);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_quotient(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *b = NULL, *quotient = NULL, *remainder = NULL;
|
||||
BIGNUM *qret = NULL, *rret = NULL, *mret = NULL;
|
||||
OSSL_FN *af = NULL, *bf = NULL, *qf = NULL, *rf = NULL, *mf = NULL;
|
||||
OSSL_FN_CTX *ctx = NULL, *mod_ctx = NULL;
|
||||
int a_neg = 0, b_neg = 0, q_neg = 0, r_neg = 0, st = 0;
|
||||
int q_acq = 0, r_acq = 0, m_acq = 0;
|
||||
int q_limbs = 0, r_limbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(b = getBN(s, "B"))
|
||||
|| !TEST_ptr(quotient = getBN(s, "Quotient"))
|
||||
|| !TEST_ptr(remainder = getBN(s, "Remainder"))
|
||||
|| !TEST_ptr(qret = BN_new())
|
||||
|| !TEST_ptr(rret = BN_new())
|
||||
|| !TEST_ptr(mret = BN_new()))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
b_neg = BN_is_negative(b);
|
||||
q_neg = a_neg ^ b_neg;
|
||||
r_neg = a_neg;
|
||||
q_limbs = limbs(quotient);
|
||||
r_limbs = limbs(remainder);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(bf = bn_get_ossl_fn(b))
|
||||
|| !TEST_ptr(qf = bn_acquire_ossl_fn(qret, q_limbs)))
|
||||
goto err;
|
||||
q_acq = 1;
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(rret, r_limbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_ptr(mf = bn_acquire_ossl_fn(mret, r_limbs)))
|
||||
goto err;
|
||||
m_acq = 1;
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_div_ctx_size(qf, rf, af, bf)))
|
||||
|| !TEST_ptr(mod_ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_mod_ctx_size(mf, af, bf))))
|
||||
goto err;
|
||||
|
||||
if (!TEST_true(OSSL_FN_div(qf, rf, af, bf, ctx)))
|
||||
goto err;
|
||||
bn_release(qret, q_limbs);
|
||||
if (!BN_is_zero(qret))
|
||||
BN_set_negative(qret, q_neg);
|
||||
q_acq = 0;
|
||||
bn_release(rret, r_limbs);
|
||||
if (!BN_is_zero(rret))
|
||||
BN_set_negative(rret, r_neg);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A / B", quotient, qret)
|
||||
|| !equalBN("A % B", remainder, rret))
|
||||
goto err;
|
||||
|
||||
if (!TEST_true(OSSL_FN_mod(mf, af, bf, mod_ctx)))
|
||||
goto err;
|
||||
bn_release(mret, r_limbs);
|
||||
if (!BN_is_zero(mret))
|
||||
BN_set_negative(mret, r_neg);
|
||||
m_acq = 0;
|
||||
if (!equalBN("A % B (mod)", remainder, mret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (m_acq)
|
||||
bn_release(mret, r_limbs);
|
||||
if (r_acq)
|
||||
bn_release(rret, r_limbs);
|
||||
if (q_acq)
|
||||
bn_release(qret, q_limbs);
|
||||
OSSL_FN_CTX_free(mod_ctx);
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
BN_free(a);
|
||||
BN_free(b);
|
||||
BN_free(quotient);
|
||||
BN_free(remainder);
|
||||
BN_free(qret);
|
||||
BN_free(rret);
|
||||
BN_free(mret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_lshift1(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *lshift1 = NULL, *two = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *lf = NULL, *tf = NULL, *rf = NULL;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
int a_neg = 0, st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(lshift1 = getBN(s, "LShift1"))
|
||||
|| !TEST_ptr(two = BN_new())
|
||||
|| !TEST_ptr(ret = BN_new()))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
nlimbs = limbs(lshift1);
|
||||
BN_set_word(two, 2);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(lf = bn_get_ossl_fn(lshift1))
|
||||
|| !TEST_ptr(tf = bn_get_ossl_fn(two))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_mul_ctx_size(rf, af, tf))))
|
||||
goto err;
|
||||
|
||||
/* A + A == LShift1 */
|
||||
if (!TEST_true(OSSL_FN_add(rf, af, af)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("A + A", lshift1, ret))
|
||||
goto err;
|
||||
|
||||
/* A * 2 == LShift1 */
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_true(OSSL_FN_mul(rf, af, tf, ctx)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("A * 2", lshift1, ret))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* TODO(FIXNUM): bntest.c also checks the division/modulus identities
|
||||
* LShift1 / 2 == A ("LShift1 / 2")
|
||||
* LShift1 % 2 == 0 ("LShift1 % 2")
|
||||
* using BN_div(). These cannot be ported yet: there is no OSSL_FN_div().
|
||||
*/
|
||||
|
||||
/* A << 1 == LShift1 */
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_true(OSSL_FN_lshift1(rf, af)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A << 1", lshift1, ret))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Round-trip: LShift1 >> 1 == A, done twice to match bntest.c's
|
||||
* double-check structure.
|
||||
*
|
||||
* TODO(FIXNUM): bntest.c's second iteration forces the LSB of LShift1
|
||||
* to 1 (BN_set_bit(lshift1, 0)) and then checks
|
||||
* (LShift1 | 1) / 2 == A ("(LShift1 | 1) / 2")
|
||||
* (LShift | 1) >> 1 == A ("(LShift | 1) >> 1")
|
||||
* to exercise rshift1's flooring of an odd operand. This cannot be
|
||||
* ported yet: there is no OSSL_FN_set_bit(), and the division variant
|
||||
* also needs OSSL_FN_div(). For now we just repeat the even case to
|
||||
* preserve the two-iteration shape.
|
||||
*/
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_true(OSSL_FN_rshift1(rf, lf)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("LShift >> 1", a, ret))
|
||||
goto err;
|
||||
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_true(OSSL_FN_rshift1(rf, lf)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("LShift >> 1", a, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
BN_free(a);
|
||||
BN_free(lshift1);
|
||||
BN_free(two);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_lshift(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *lshift = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *lf = NULL, *rf = NULL;
|
||||
int a_neg = 0, n = 0, st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(lshift = getBN(s, "LShift"))
|
||||
|| !TEST_ptr(ret = BN_new())
|
||||
|| !getint(s, &n, "N"))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
nlimbs = limbs(lshift);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(lf = bn_get_ossl_fn(lshift))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
|
||||
if (!TEST_true(OSSL_FN_lshift(rf, af, n)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A << N", lshift, ret))
|
||||
goto err;
|
||||
|
||||
/* Round-trip: shift the result back and recover A */
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_true(OSSL_FN_rshift(rf, lf, n)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("A >> N", a, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
BN_free(a);
|
||||
BN_free(lshift);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_rshift(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *rshift = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *rf = NULL;
|
||||
int a_neg = 0, n = 0, st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(rshift = getBN(s, "RShift"))
|
||||
|| !TEST_ptr(ret = BN_new())
|
||||
|| !getint(s, &n, "N"))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
nlimbs = limbs(rshift);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
|
||||
if (!TEST_true(OSSL_FN_rshift(rf, af, n)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("A >> N", rshift, ret))
|
||||
goto err;
|
||||
|
||||
/* If N == 1, try with rshift1 as well */
|
||||
if (n == 1) {
|
||||
if (!TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
if (!TEST_true(OSSL_FN_rshift1(rf, af)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
BN_set_negative(ret, a_neg && !BN_is_zero(ret));
|
||||
r_acq = 0;
|
||||
if (!equalBN("A >> 1 (rshift1)", rshift, ret))
|
||||
goto err;
|
||||
}
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
BN_free(a);
|
||||
BN_free(rshift);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_modmul(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *b = NULL, *m = NULL, *mod_mul = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *bf = NULL, *rf = NULL, *mf = NULL;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
int a_neg = 0, b_neg = 0, st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(b = getBN(s, "B"))
|
||||
|| !TEST_ptr(m = getBN(s, "M"))
|
||||
|| !TEST_ptr(mod_mul = getBN(s, "ModMul"))
|
||||
|| !TEST_ptr(ret = BN_new()))
|
||||
goto err;
|
||||
|
||||
a_neg = BN_is_negative(a);
|
||||
b_neg = BN_is_negative(b);
|
||||
nlimbs = limbs(m);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(bf = bn_get_ossl_fn(b))
|
||||
|| !TEST_ptr(mf = bn_get_ossl_fn(m))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_mod_mul_ctx_size(rf, af, bf, mf))))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* OSSL_FN is unsigned, so the multiplication is on absolute values.
|
||||
* If the operands have different signs, the non-negative modular
|
||||
* residue of A * B is M - ((|A| * |B|) mod M), unless that is zero.
|
||||
*/
|
||||
if (!TEST_true(OSSL_FN_mod_mul(rf, af, bf, mf, ctx)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
r_acq = 0;
|
||||
if ((a_neg ^ b_neg) && !BN_is_zero(ret)) {
|
||||
if (!TEST_true(BN_sub(ret, m, ret)))
|
||||
goto err;
|
||||
}
|
||||
if (!equalBN("A * B (mod M)", mod_mul, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
BN_free(a);
|
||||
BN_free(b);
|
||||
BN_free(m);
|
||||
BN_free(mod_mul);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
|
||||
static int file_modsqr(STANZA *s)
|
||||
{
|
||||
BIGNUM *a = NULL, *m = NULL, *mod_sqr = NULL, *ret = NULL;
|
||||
OSSL_FN *af = NULL, *rf = NULL, *mf = NULL;
|
||||
OSSL_FN_CTX *ctx = NULL;
|
||||
int st = 0;
|
||||
int r_acq = 0;
|
||||
int nlimbs = 0;
|
||||
|
||||
if (!TEST_ptr(a = getBN(s, "A"))
|
||||
|| !TEST_ptr(m = getBN(s, "M"))
|
||||
|| !TEST_ptr(mod_sqr = getBN(s, "ModSqr"))
|
||||
|| !TEST_ptr(ret = BN_new()))
|
||||
goto err;
|
||||
|
||||
nlimbs = limbs(m);
|
||||
|
||||
if (!TEST_ptr(af = bn_get_ossl_fn(a))
|
||||
|| !TEST_ptr(mf = bn_get_ossl_fn(m))
|
||||
|| !TEST_ptr(rf = bn_acquire_ossl_fn(ret, nlimbs)))
|
||||
goto err;
|
||||
r_acq = 1;
|
||||
|
||||
if (!TEST_ptr(ctx = OSSL_FN_CTX_new_size(NULL,
|
||||
OSSL_FN_mod_sqr_ctx_size(rf, af, mf))))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Squaring is always non-negative, so no sign fixup is needed.
|
||||
*/
|
||||
if (!TEST_true(OSSL_FN_mod_sqr(rf, af, mf, ctx)))
|
||||
goto err;
|
||||
bn_release(ret, nlimbs);
|
||||
r_acq = 0;
|
||||
if (!equalBN("A^2 (mod M)", mod_sqr, ret))
|
||||
goto err;
|
||||
|
||||
st = 1;
|
||||
err:
|
||||
if (r_acq)
|
||||
bn_release(ret, nlimbs);
|
||||
OSSL_FN_CTX_free(ctx);
|
||||
BN_free(a);
|
||||
BN_free(m);
|
||||
BN_free(mod_sqr);
|
||||
BN_free(ret);
|
||||
return st;
|
||||
}
|
||||
static FILETEST filetests[] = {
|
||||
{ "Sum", file_sum, 0 },
|
||||
{ "LShift1", file_lshift1, 0 },
|
||||
{ "LShift", file_lshift, 0 },
|
||||
{ "RShift", file_rshift, 0 },
|
||||
{ "Square", file_square, 0 },
|
||||
{ "Product", file_product, 0 },
|
||||
{ "Quotient", file_quotient, 0 },
|
||||
{ "ModMul", file_modmul, 0 },
|
||||
{ "ModSqr", file_modsqr, 0 },
|
||||
{ "ModExp", NULL, 0 },
|
||||
{ "Exp", NULL, 0 },
|
||||
{ "ModSqrt", NULL, 0 },
|
||||
{ "GCD", NULL, 0 },
|
||||
};
|
||||
|
||||
static int file_test_run(STANZA *s)
|
||||
{
|
||||
const FILETEST *tp = filetests;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(filetests); i++, tp++) {
|
||||
if (findattr(s, tp->name) != NULL) {
|
||||
if (tp->func == NULL) {
|
||||
filetests[i].skipped++;
|
||||
return 1;
|
||||
}
|
||||
if (!tp->func(s)) {
|
||||
TEST_info("%s:%d: Failed %s test",
|
||||
s->test_file, s->start, tp->name);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_info("%s:%d: Unknown test, skipped", s->test_file, s->start);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int run_file_tests(int i)
|
||||
{
|
||||
STANZA *s = NULL;
|
||||
char *testfile = test_get_argument(i);
|
||||
int c;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < OSSL_NELEM(filetests); j++)
|
||||
filetests[j].skipped = 0;
|
||||
|
||||
if (!TEST_ptr(s = OPENSSL_zalloc(sizeof(*s))))
|
||||
return 0;
|
||||
if (!test_start_file(s, testfile)) {
|
||||
OPENSSL_free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!BIO_eof(s->fp) && test_readstanza(s)) {
|
||||
if (s->numpairs == 0)
|
||||
continue;
|
||||
if (!file_test_run(s))
|
||||
s->errors++;
|
||||
s->numtests++;
|
||||
test_clearstanza(s);
|
||||
}
|
||||
test_end_file(s);
|
||||
|
||||
for (j = 0; j < OSSL_NELEM(filetests); j++)
|
||||
if (filetests[j].skipped > 0)
|
||||
TEST_info("%s: skipped %d unsupported %s stanzas",
|
||||
testfile, filetests[j].skipped, filetests[j].name);
|
||||
|
||||
c = s->errors;
|
||||
OPENSSL_free(s);
|
||||
|
||||
return c == 0;
|
||||
}
|
||||
|
||||
OPT_TEST_DECLARE_USAGE("file...\n")
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
size_t n = test_get_argument_count();
|
||||
|
||||
if (!TEST_size_t_gt(n, 0))
|
||||
return 0;
|
||||
|
||||
ADD_ALL_TESTS(run_file_tests, (int)n);
|
||||
return 1;
|
||||
}
|
||||
19
test/recipes/03-test_internal_fn.t
Normal file
19
test/recipes/03-test_internal_fn.t
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#! /usr/bin/env perl
|
||||
# Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
use strict;
|
||||
use OpenSSL::Test; # get 'plan'
|
||||
use OpenSSL::Test::Simple;
|
||||
use OpenSSL::Test::Utils;
|
||||
|
||||
setup("test_internal_fn");
|
||||
|
||||
plan skip_all => "This test is unsupported in a shared library build on Windows"
|
||||
if $^O eq 'MSWin32' && !disabled("shared");
|
||||
|
||||
simple_test("test_internal_fn", "fn_internal_test");
|
||||
|
|
@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT data_file/;
|
|||
|
||||
setup("test_bn");
|
||||
|
||||
my @files = qw( bnexp.txt bnmod.txt bnmul.txt bnshift.txt bnsum.txt bngcd.txt );
|
||||
my @files = qw( bnexp.txt bnmod.txt bnmodinv.txt bnmul.txt bnshift.txt bnsum.txt bngcd.txt );
|
||||
|
||||
plan tests => 1 + scalar(@files);
|
||||
|
||||
|
|
|
|||
69180
test/recipes/10-test_bn_data/bnmodinv.txt
Normal file
69180
test/recipes/10-test_bn_data/bnmodinv.txt
Normal file
File diff suppressed because it is too large
Load diff
22
test/recipes/11-test_fn.t
Normal file
22
test/recipes/11-test_fn.t
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#! /usr/bin/env perl
|
||||
# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use OpenSSL::Test qw/:DEFAULT srctop_file/;
|
||||
setup("test_fn");
|
||||
|
||||
my @files = qw( bnmul.txt bnshift.txt bnsum.txt bnmod.txt );
|
||||
|
||||
plan tests => scalar(@files);
|
||||
|
||||
foreach my $f (@files) {
|
||||
ok(run(test(["fntest", srctop_file("test", "recipes", "10-test_bn_data", $f)])),
|
||||
"running fntest $f");
|
||||
}
|
||||
14
test/recipes/11-test_fn_api.t
Normal file
14
test/recipes/11-test_fn_api.t
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#! /usr/bin/env perl
|
||||
# Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
use strict;
|
||||
use OpenSSL::Test; # get 'plan'
|
||||
use OpenSSL::Test::Simple;
|
||||
setup("test_fn_api");
|
||||
|
||||
simple_test("test_fn_api", "fn_api_test");
|
||||
Loading…
Add table
Add a link
Reference in a new issue