Files
MeshCore/lib/ed25519/sc_compact.h
T

89 lines
3.0 KiB
C

/*
* Loop form of the ref10 scalar arithmetic in sc.c. The 21-bit limbs,
* folding coefficients, and carry order are unchanged. Small STM32
* Companion images cannot afford the unrolled reduction and multiply-add.
* All loop bounds and memory addresses depend only on public limb indices;
* scalar values never select a branch or an array index.
*/
static void sc_unpack(int64_t *limbs, const unsigned char *bytes, int count) {
const int size = count == 24 ? 64 : 32;
int i;
for (i = 0; i < count; ++i) {
const int start = (i * 21) >> 3;
const int shift = (i * 21) & 7;
uint32_t word = 0;
int j;
for (j = 0; j < 4 && start + j < size; ++j)
word |= (uint32_t)bytes[start + j] << (j * 8);
word >>= shift;
/* The last limb retains every remaining input bit, as in ref10. */
limbs[i] = (int64_t)(i == count - 1 ? word : word & 2097151);
}
}
static void sc_carry(int64_t *limbs, int first, int last, int step, int rounded) {
int i;
for (i = first; i <= last; i += step) {
const int64_t value = (limbs[i] + (rounded ? 1048576 : 0)) >> 21;
limbs[i + 1] += value;
/* A carry can be negative; multiplication avoids a signed left shift. */
limbs[i] -= value * 2097152;
}
}
static void sc_fold(int64_t *limbs, int first, int last) {
static const int32_t coefficients[6] = {666643, 470296, 654183, -997805, 136657, -683901};
int i;
for (i = first; i >= last; --i) {
int j;
for (j = 0; j < 6; ++j)
limbs[i - 12 + j] += limbs[i] * coefficients[j];
limbs[i] = 0;
}
}
static void sc_reduce_limbs(unsigned char *out, int64_t limbs[24]) {
int i;
sc_fold(limbs, 23, 18);
sc_carry(limbs, 6, 16, 2, 1);
sc_carry(limbs, 7, 15, 2, 1);
sc_fold(limbs, 17, 12);
sc_carry(limbs, 0, 10, 2, 1);
sc_carry(limbs, 1, 11, 2, 1);
sc_fold(limbs, 12, 12);
sc_carry(limbs, 0, 11, 1, 0);
sc_fold(limbs, 12, 12);
sc_carry(limbs, 0, 10, 1, 0);
/* Encode the same 256 low bits as ref10's byte assignments. */
for (i = 0; i < 32; ++i) {
const int index = (i * 8) / 21;
const int shift = (i * 8) % 21;
uint64_t word = (uint64_t)limbs[index] >> shift;
if (shift > 13 && index < 11)
word |= (uint64_t)limbs[index + 1] << (21 - shift);
out[i] = (unsigned char)word;
}
}
void sc_reduce(unsigned char *s) {
int64_t limbs[24];
sc_unpack(limbs, s, 24);
sc_reduce_limbs(s, limbs);
}
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
int64_t aa[12], bb[12], limbs[24] = {0};
int i, j;
/* Read all inputs before writing the result; s may alias a, b, or c. */
sc_unpack(aa, a, 12);
sc_unpack(bb, b, 12);
sc_unpack(limbs, c, 12);
for (i = 0; i < 12; ++i)
for (j = 0; j < 12; ++j)
limbs[i + j] += aa[i] * bb[j];
sc_carry(limbs, 0, 22, 2, 1);
sc_carry(limbs, 1, 21, 2, 1);
sc_reduce_limbs(s, limbs);
}