crypto/bn: bignum supports negative number operations

1.Add sign to indicate negative and positive
2.Fix case where there are negative numbers in the operation
3.expand to 512 bytes to support rsa2048

Signed-off-by: makejian <makejian@xiaomi.com>
This commit is contained in:
makejian 2023-06-16 16:51:29 +08:00 committed by Xiang Xiao
parent fbb2e5f781
commit 21514e266a
2 changed files with 120 additions and 9 deletions

View File

@ -159,6 +159,38 @@ static void rshift_one_bit(FAR struct bn *a)
a->array[BN_ARRAY_SIZE - 1] >>= 1; a->array[BN_ARRAY_SIZE - 1] >>= 1;
} }
static
void bignum_add_sub(struct bn *a, struct bn *b, struct bn *c, int flip)
{
int cmp;
int s;
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
s = a->s;
if (a->s * b->s * flip < 0)
{
cmp = bignum_cmp_abs(a, b);
if (cmp >= 0)
{
bignum_sub_abs(a, b, c);
c->s = cmp == 0 ? 1 : s;
}
else
{
bignum_sub_abs(b, a, c);
c->s = -s;
}
}
else
{
bignum_add_abs(a, b, c);
c->s = s;
}
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -175,6 +207,8 @@ void bignum_init(FAR struct bn *n)
{ {
n->array[i] = 0; n->array[i] = 0;
} }
n->s = 1;
} }
void bignum_from_int(FAR struct bn *n, DTYPE_TMP i) void bignum_from_int(FAR struct bn *n, DTYPE_TMP i)
@ -345,6 +379,11 @@ void bignum_inc(FAR struct bn *n)
} }
void bignum_add(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c) void bignum_add(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
{
bignum_add_sub(a, b, c, 1);
}
void bignum_add_abs(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
{ {
DTYPE_TMP tmp; DTYPE_TMP tmp;
int carry = 0; int carry = 0;
@ -363,6 +402,11 @@ void bignum_add(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
} }
void bignum_sub(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c) void bignum_sub(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
{
bignum_add_sub(a, b, c, -1);
}
void bignum_sub_abs(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
{ {
DTYPE_TMP res; DTYPE_TMP res;
DTYPE_TMP tmp1; DTYPE_TMP tmp1;
@ -415,11 +459,20 @@ void bignum_mul(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
((DTYPE_TMP)a->array[i] * (DTYPE_TMP)b->array[j]); ((DTYPE_TMP)a->array[i] * (DTYPE_TMP)b->array[j]);
bignum_from_int(&tmp, intermediate); bignum_from_int(&tmp, intermediate);
lshift_word(&tmp, i + j); lshift_word(&tmp, i + j);
bignum_add(&tmp, &row, &row); bignum_add_abs(&tmp, &row, &row);
} }
} }
bignum_add(c, &row, c); bignum_add_abs(c, &row, c);
}
if (bignum_is_zero(c) != 0)
{
c->s = 1;
}
else
{
c->s = a->s * b->s;
} }
} }
@ -439,7 +492,7 @@ void bignum_div(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
bignum_assign(&denom, b); /* denom = b */ bignum_assign(&denom, b); /* denom = b */
bignum_assign(&tmp, a); /* tmp = a */ bignum_assign(&tmp, a); /* tmp = a */
while (bignum_cmp(&denom, a) != LARGER) /* while (denom <= a) { */ while (bignum_cmp_abs(&denom, &tmp) != LARGER) /* while (denom <= a) { */
{ {
if (denom.array[BN_ARRAY_SIZE - 1] >= half_max) if (denom.array[BN_ARRAY_SIZE - 1] >= half_max)
{ {
@ -461,9 +514,9 @@ void bignum_div(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
while (!bignum_is_zero(&current)) /* while (current != 0) */ while (!bignum_is_zero(&current)) /* while (current != 0) */
{ {
if (bignum_cmp(&tmp, &denom) != SMALLER) /* if (dividend >= denom) */ if (bignum_cmp_abs(&tmp, &denom) != SMALLER) /* if (dividend >= denom) */
{ {
bignum_sub(&tmp, &denom, &tmp); /* dividend -= denom; */ bignum_sub_abs(&tmp, &denom, &tmp); /* dividend -= denom; */
bignum_or(c, &current, c); /* answer |= current; */ bignum_or(c, &current, c); /* answer |= current; */
} }
@ -471,6 +524,8 @@ void bignum_div(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
rshift_one_bit(&denom); /* denom >>= 1; */ rshift_one_bit(&denom); /* denom >>= 1; */
} }
c->s = a->s * b->s;
/* return answer; */ /* return answer; */
} }
@ -580,6 +635,11 @@ void bignum_divmod(FAR struct bn *a, FAR struct bn *b,
/* c = a - tmp */ /* c = a - tmp */
bignum_sub(a, &tmp, d); bignum_sub(a, &tmp, d);
while (d->s < 0)
{
bignum_add(d, b, d);
}
} }
void bignum_and(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c) void bignum_and(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c)
@ -631,6 +691,40 @@ int bignum_cmp(FAR struct bn *a, FAR struct bn *b)
require(a, "a is null"); require(a, "a is null");
require(b, "b is null"); require(b, "b is null");
if (a->s > 0 && b->s < 0)
{
return LARGER;
}
if (b->s > 0 && a->s < 0)
{
return SMALLER;
}
do
{
i -= 1; /* Decrement first, to start with last array element */
if (a->array[i] > b->array[i])
{
return a->s;
}
else if (a->array[i] < b->array[i])
{
return -a->s;
}
}
while (i != 0);
return EQUAL;
}
int bignum_cmp_abs(FAR struct bn *a, FAR struct bn *b)
{
int i = BN_ARRAY_SIZE;
require(a, "a is null");
require(b, "b is null");
do do
{ {
i -= 1; /* Decrement first, to start with last array element */ i -= 1; /* Decrement first, to start with last array element */
@ -741,9 +835,9 @@ void bignum_isqrt(FAR struct bn *a, FAR struct bn *b)
bignum_assign(&low, &mid); bignum_assign(&low, &mid);
} }
bignum_sub(&high, &low, &mid); bignum_sub_abs(&high, &low, &mid);
rshift_one_bit(&mid); rshift_one_bit(&mid);
bignum_add(&low, &mid, &mid); bignum_add_abs(&low, &mid, &mid);
bignum_inc(&mid); bignum_inc(&mid);
} }
@ -761,6 +855,8 @@ void bignum_assign(FAR struct bn *dst, FAR struct bn *src)
{ {
dst->array[i] = src->array[i]; dst->array[i] = src->array[i];
} }
dst->s = src->s;
} }
void pow_mod_faster(FAR struct bn *a, FAR struct bn *b, void pow_mod_faster(FAR struct bn *a, FAR struct bn *b,

View File

@ -68,7 +68,7 @@
/* Size of big-numbers in bytes */ /* Size of big-numbers in bytes */
#define BN_ARRAY_SIZE (256 / WORD_SIZE) #define BN_ARRAY_SIZE (512 / WORD_SIZE)
/* Data type of array in structure */ /* Data type of array in structure */
@ -101,6 +101,9 @@
struct bn struct bn
{ {
/* Sign: -1 if the bignum is negative, 1 otherwise. */
int s;
DTYPE array[BN_ARRAY_SIZE]; DTYPE array[BN_ARRAY_SIZE];
}; };
@ -131,10 +134,18 @@ void bignum_to_string(FAR struct bn *n, FAR char *str, int maxsize);
void bignum_add(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c); void bignum_add(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);
/* c = |a| + |b| */
void bignum_add_abs(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);
/* c = a - b */ /* c = a - b */
void bignum_sub(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c); void bignum_sub(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);
/* c = |a| - |b| */
void bignum_sub_abs(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);
/* c = a * b */ /* c = a * b */
void bignum_mul(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c); void bignum_mul(FAR struct bn *a, FAR struct bn *b, FAR struct bn *c);
@ -180,6 +191,10 @@ void bignum_rshift(FAR struct bn *a, FAR struct bn *b, int nbits);
int bignum_cmp(FAR struct bn *a, FAR struct bn *b); int bignum_cmp(FAR struct bn *a, FAR struct bn *b);
/* Compare |A| and |B| */
int bignum_cmp_abs(FAR struct bn *a, FAR struct bn *b);
/* For comparison with zero */ /* For comparison with zero */
int bignum_is_zero(FAR struct bn *n); int bignum_is_zero(FAR struct bn *n);