#include "../include/sc25519.h"
#include "../include/montgomery_reduction.h"
#define BARRET_REDUCTION 1
#define MONTGOMERY_REDUCTION 2
#define REDUCTION_TYPE BARRET_REDUCTION
#if (REDUCTION_TYPE == BARRET_REDUCTION)
static const UN_288bitValue sc25519_scalar =
{{
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10
}};
#define uint32_scalar sc25519_scalar.as_uint32_t
#else
static const UNMontgomeryConstants256 sc25519_scalarMontgomeryPrecalc = {{
0x01, 0x0f, 0x9c, 0x44, 0xe3, 0x11, 0x06, 0xa4,
0x47, 0x93, 0x85, 0x68, 0xa7, 0x1b, 0x0e, 0xd0,
0x65, 0xbe, 0xf5, 0x17, 0xd2, 0x73, 0xec, 0xce,
0x3d, 0x9a, 0x30, 0x7c, 0x1b, 0x41, 0x99, 0x03,
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x1b, 0x7e, 0x54, 0x12
}};
#define uint32_scalar sc25519_scalarMontgomeryPrecalc.constants.prime.as_uint32_t
#endif
static int32_t
bigint_sub(
uint32_t* dest,
const uint32_t* sub,
uint32_t numberOfWords
)
{
unsigned ctr;
int64_t accu = 0;
for (ctr = 0; ctr < numberOfWords; ctr ++)
{
accu += dest[ctr];
accu -= sub[ctr];
dest[ctr] = (uint32_t)accu;
accu >>= 32;
}
return (int32_t)accu;
}
static int32_t
bigint_add(
uint32_t* dest,
const uint32_t* addend,
uint32_t numberOfWords
)
{
unsigned ctr;
int64_t accu = 0;
for (ctr = 0; ctr < numberOfWords; ctr ++)
{
accu += dest[ctr];
accu += addend[ctr];
dest[ctr] = (uint32_t)accu;
accu >>= 32;
}
return (int32_t)accu;
}
#if 1
static void
sc25519_reduceAddSub(
sc25519* valueToReduce,
sc25519* tempBufferSuppliedByCaller
)
{
int32_t didUnderflowHappen;
cpy_256bitvalue(tempBufferSuppliedByCaller, valueToReduce);
didUnderflowHappen = bigint_sub(tempBufferSuppliedByCaller->as_uint32_t,
uint32_scalar,
8);
conditionalMove_256bitValue(valueToReduce, tempBufferSuppliedByCaller,
(uint8_t) (~didUnderflowHappen) & 1);
}
#else#endif
void
sc25519_from32bytes(
sc25519* r,
const uint8_t x[32]
)
{
UN_512bitValue temp;
uint8_t ctr;
for (ctr = 0; ctr < 32; ctr++)
{
temp.as_uint8_t[ctr] = x[ctr];
}
for (ctr = 8; ctr < 16; ctr++)
{
temp.as_uint32_t[ctr] = 0;
}
sc25519_reduce(&temp);
for (ctr = 0; ctr < 8; ctr++)
{
r->as_uint32_t[ctr] = temp.as_uint32_t[ctr];
}
}
void
sc25519_from64bytes(
sc25519* r,
const uint8_t x[64]
)
{
UN_512bitValue temp;
uint8_t ctr;
for (ctr = 0; ctr < 64; ctr++)
{
temp.as_uint8_t[ctr] = x[ctr];
}
sc25519_reduce(&temp);
for (ctr = 0; ctr < 8; ctr++)
{
r->as_uint32_t[ctr] = temp.as_uint32_t[ctr];
}
}
void
sc25519_to32bytes(
uint8_t r[32],
const sc25519* x
)
{
uint8_t ctr;
for (ctr = 0; ctr < 32; ctr++)
{
r[ctr] = x->as_uint8_t[ctr];
}
}
void
sc25519_add(
sc25519* result,
const sc25519* addend1,
const sc25519* addend2
)
{
UN_256bitValue tmp;
cpy_256bitvalue(result, addend1);
bigint_add(result->as_uint32_t, addend2->as_uint32_t, 8);
sc25519_reduceAddSub(result, &tmp);
}
void
sc25519_sub(
sc25519* result,
const sc25519* addend,
const sc25519* valueToSubstract
)
{
UN_256bitValue tmp;
int didUnderflowHappen;
cpy_256bitvalue(result, addend);
didUnderflowHappen = bigint_sub( result->as_uint32_t,
valueToSubstract->as_uint32_t,
8);
{
int i;
for (i = 0; i < 8; i ++)
{
tmp.as_uint32_t[i] = uint32_scalar[i];
}
}
bigint_add (tmp.as_uint32_t, result->as_uint32_t,8);
conditionalMove_256bitValue((UN_256bitValue *) result, &tmp,
(uint8_t) (didUnderflowHappen & 1));
}
#if (REDUCTION_TYPE == BARRET_REDUCTION)
void
sc25519_reduce(
UN_512bitValue* valueToReduce
)
{
static const uint32_t u32_mu[9] =
{
0x0a2c131bUL, 0xed9ce5a3UL, 0x086329a7UL, 0x2106215dUL,
0xffffffebUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL,
0xfUL
};
UN_288bitValue* valueForBarretMpy =
(UN_288bitValue*)&valueToReduce->as_uint32_t[7];
UN_288bitValue* u288_mu = (UN_288bitValue*)u32_mu;
const UN_288bitValue* u288_pr252 = &sc25519_scalar;
UN_576bitValue intermResultBarret;
multiply288x288(&intermResultBarret, u288_mu, valueForBarretMpy);
{
UN_288bitValue* approximateResultOfDivision =
(UN_288bitValue*)&intermResultBarret.as_uint32_t[9];
UN_576bitValue valueToSubstract;
multiply288x288(&valueToSubstract,
approximateResultOfDivision,
u288_pr252);
bigint_sub(valueToReduce->as_uint32_t, valueToSubstract.as_uint32_t,
16);
}
sc25519_reduceAddSub(&valueToReduce->as_256_bitValue[0],
&valueToReduce->as_256_bitValue[1]);
sc25519_reduceAddSub(&valueToReduce->as_256_bitValue[0],
&valueToReduce->as_256_bitValue[1]);
}
#else
void
sc25519_reduce(
UN_512bitValue* valueToReduce
)
{
UN_256bitValue tmp;
montgomery_reduce (&tmp,
valueToReduce, &sc25519_scalarMontgomeryPrecalc.constants);
multiply256x256 (valueToReduce, &tmp,
&sc25519_scalarMontgomeryPrecalc.constants.kSquare);
montgomery_reduce (&valueToReduce->as_256_bitValue [0],
valueToReduce, &sc25519_scalarMontgomeryPrecalc.constants);
}
#endif
#if (REDUCTION_TYPE == BARRET_REDUCTION)
void
sc25519_mul(
sc25519* r,
const sc25519* x,
const sc25519* y
)
{
UN_512bitValue temp;
multiply256x256(&temp, x, y);
sc25519_reduce(&temp);
cpy_256bitvalue(r, &temp.as_256_bitValue[0]);
}
void
sc25519_sqr(
sc25519* r,
const sc25519* x
)
{
UN_512bitValue temp;
square256(&temp, x);
sc25519_reduce(&temp);
cpy_256bitvalue(r, &temp.as_256_bitValue[0]);
}
#else
void
sc25519_mul(
sc25519* r,
const sc25519* x,
const sc25519* y
)
{
UN_512bitValue tmp;
multiply256x256 (&tmp, x,y);
montgomery_reduce (r,&tmp, &sc25519_scalarMontgomeryPrecalc.constants);
multiply256x256 (&tmp, r, &sc25519_scalarMontgomeryPrecalc.constants.kSquare);
montgomery_reduce (r,&tmp, &sc25519_scalarMontgomeryPrecalc.constants);
}
void
sc25519_sqr(
sc25519* r,
const sc25519* x
)
{
UN_512bitValue tmp;
square256(&tmp, x);
montgomery_reduce(r, &tmp, &sc25519_scalarMontgomeryPrecalc.constants);
multiply256x256(&tmp, r, &sc25519_scalarMontgomeryPrecalc.constants.kSquare);
montgomery_reduce(r, &tmp, &sc25519_scalarMontgomeryPrecalc.constants);
}
#endif
void
sc25519_window4(
signed char r[SC25519_WINDOW4_SIZE],
const sc25519* s
)
{
char carry;
uint8_t i;
for (i = 0; i < 32; i++)
{
r[2 * i] = s->as_uint8_t[i] & 15;
r[2 * i + 1] = s->as_uint8_t[i] >> 4;
}
carry = 0;
for (i = 0; i < (SC25519_WINDOW4_SIZE - 1); i++)
{
r[i] += carry;
r[i + 1] += r[i] >> 4;
r[i] &= 15;
carry = r[i] >> 3;
r[i] -= carry << 4;
}
r[SC25519_WINDOW4_SIZE - 1] += carry;
}
int greaterThan(const UN_256bitValue* x, const UN_256bitValue* y) {
UN_256bitValue tmp;
cpy_256bitvalue(&tmp, x);
bigint_sub(tmp.as_uint32_t, y->as_uint32_t, 8);
return tmp.as_uint32_t[7] >> 31;
}
void sc25519_binary_extended_gcd(UN_256bitValue *R, const UN_256bitValue *X, const UN_256bitValue *Y) {
UN_256bitValue B, D, v, u, g, x, y, zero;
cpy_256bitvalue(&x, X);
cpy_256bitvalue(&y, Y);
setone_256bitvalue(&g);
while(((x.as_uint8_t[0] & 1) == 0) && ((y.as_uint8_t[0] & 1) == 0)) {
shiftRightOne(&x);
shiftRightOne(&y);
shiftLeftOne(&g);
}
cpy_256bitvalue(&u, &x);
cpy_256bitvalue(&v, &y);
setzero_256bitvalue(&B);
setone_256bitvalue(&D);
setzero_256bitvalue(&zero);
while(isEqual_256bitvalue(&u, &zero) > 0) {
while((u.as_uint8_t[0] & 1) == 0) {
shiftRightOne(&u);
if((B.as_uint8_t[0] & 1) == 0) {
shiftRightOne(&B);
} else {
bigint_sub(B.as_uint32_t, x.as_uint32_t, 8);
shiftRightOne(&B);
}
}
while((v.as_uint8_t[0] & 1) == 0) {
shiftRightOne(&v);
if((D.as_uint8_t[0] & 1) == 0) {
shiftRightOne(&D);
} else {
bigint_sub(D.as_uint32_t, x.as_uint32_t, 8);
shiftRightOne(&D);
}
}
if(!greaterThan(&u, &v) || (isEqual_256bitvalue(&u, &v) == 0)) {
bigint_sub(u.as_uint32_t, v.as_uint32_t, 8);
bigint_sub(B.as_uint32_t, D.as_uint32_t, 8);
} else {
bigint_sub(v.as_uint32_t, u.as_uint32_t, 8);
bigint_sub(D.as_uint32_t, B.as_uint32_t, 8);
}
}
cpy_256bitvalue(R, &D);
}
void sc25519_inverse(UN_256bitValue *R, const UN_256bitValue *X) {
UN_256bitValue order = {{
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
}};
sc25519_binary_extended_gcd(R, &order, X);
while((R->as_uint32_t[7] & 0x80000000) != 0)
bigint_add(R->as_uint32_t, order.as_uint32_t, 8);
}