Fix firmware size limits and refresh CI compatibility checks

Compact the existing STM32 field arithmetic and ESP-NOW tail-frame storage without removing features or lowering memory reserves. Refresh power-saving fixtures and pin official-app tests to a published archive.
This commit is contained in:
mikecarper committed 2026-10-23 19:04:43 -07:00
1 parent cf98125c65
commit c563c40c66
15 files changed
+494 -66

No files matched your search

+10 -1
View File
@@ -9,6 +9,7 @@
/*
helper functions
*/
#if !defined(ED25519_COMPACT_FIELD) || !ED25519_COMPACT_FIELD
static uint64_t load_3(const unsigned char *in) {
uint64_t result;
@@ -29,6 +30,7 @@ static uint64_t load_4(const unsigned char *in) {
return result;
}
#endif
@@ -301,6 +303,7 @@ void fe_copy(fe h, const fe f) {
#endif
#if !defined(ED25519_COMPACT_FIELD) || !ED25519_COMPACT_FIELD
void fe_frombytes(fe h, const unsigned char *s) {
int64_t h0 = load_4(s);
int64_t h1 = load_3(s + 4) << 6;
@@ -368,6 +371,8 @@ void fe_frombytes(fe h, const unsigned char *s) {
#endif
void fe_invert(fe out, const fe z) {
fe t0;
fe t1;
@@ -482,6 +487,7 @@ int fe_isnegative(const fe f) {
|f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*/
#if !defined(ED25519_COMPACT_FIELD) || !ED25519_COMPACT_FIELD
int fe_isnonzero(const fe f) {
unsigned char s[32];
unsigned char r;
@@ -525,6 +531,7 @@ int fe_isnonzero(const fe f) {
return r != 0;
}
#endif
@@ -785,6 +792,7 @@ Postconditions:
|h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
*/
#if !defined(ED25519_COMPACT_FIELD) || !ED25519_COMPACT_FIELD
void fe_mul121666(fe h, fe f) {
int32_t f0 = f[0];
int32_t f1 = f[1];
@@ -852,7 +860,6 @@ Postconditions:
|h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
*/
#if !defined(ED25519_COMPACT_FIELD) || !ED25519_COMPACT_FIELD
void fe_neg(fe h, const fe f) {
int32_t f0 = f[0];
int32_t f1 = f[1];
@@ -1400,6 +1407,7 @@ Proof:
#endif
#if !defined(ED25519_COMPACT_FIELD) || !ED25519_COMPACT_FIELD
void fe_tobytes(unsigned char *s, const fe h) {
int32_t h0 = h[0];
int32_t h1 = h[1];
@@ -1506,3 +1514,4 @@ void fe_tobytes(unsigned char *s, const fe h) {
s[30] = (unsigned char) (h9 >> 10);
s[31] = (unsigned char) (h9 >> 18);
}
#endif
+86 -15
View File
@@ -1,15 +1,18 @@
/*
* Fixed-loop form of the ref10 field products in fe.c. Only the headless
* STM32 Companion size recipes opt in; other builds keep the unrolled code.
* Fixed-loop form of the ref10 field arithmetic in fe.c. The existing STM32
* size recipes opt in; other builds keep the unrolled code.
* The radix alternates 26 and 25 bits. Odd-by-odd products therefore have
* weight 2, and terms beyond bit 254 fold back with weight 19, exactly as in
* ref10. Product accumulation and the rounded carry order are unchanged.
* ref10. Product accumulation, decoding, encoding and carry orders are unchanged.
*
* All loops, branches and array addresses depend only on public limb indices
* or the public operation (multiply, square, double-square), not input values.
* Under ref10's 1.65*2^26 / 1.65*2^25 input bounds, even doubled sums fit in
* signed 64 bits. Outputs are written only after reading every input, so h
* may alias f or g. No additional persistent RAM or heap is needed.
* may alias f or g. No additional persistent RAM or heap is needed. Compared
* with the unrolled forms, public-index loop overhead trades CPU time for
* flash; the fixed number of field operations and secret-independent control
* flow are retained for every opted-in Companion and Mini Repeater profile.
*/
void fe_add(fe h, const fe f, const fe g) {
@@ -48,6 +51,84 @@ void fe_cswap(fe f, fe g, unsigned int b) {
}
}
static void fe_compact_carry(fe h, int64_t limbs[10],
const unsigned char *order, int count) {
int i;
for (i = 0; i < count; ++i) {
const int index = order[i];
const int bits = 26 - (index & 1);
const int64_t radix = (int64_t)1 << bits;
const int64_t carry = (limbs[index] + radix / 2) >> bits;
if (index == 9) limbs[0] += carry * 19;
else limbs[index + 1] += carry;
/* A carry may be negative; do not left-shift that signed value. */
limbs[index] -= carry * radix;
}
for (i = 0; i < 10; ++i) h[i] = (int32_t)limbs[i];
}
static const unsigned char fe_decode_carries[] = {9, 1, 3, 5, 7, 0, 2, 4, 6, 8};
void fe_frombytes(fe h, const unsigned char *s) {
static const unsigned char offsets[] = {0, 4, 7, 10, 13, 16, 20, 23, 26, 29};
static const unsigned char shifts[] = {0, 6, 5, 3, 2, 0, 7, 5, 4, 2};
int64_t limbs[10];
int i, j;
for (i = 0; i < 10; ++i) {
uint32_t word = 0;
const int count = i == 0 || i == 5 ? 4 : 3;
for (j = 0; j < count; ++j)
word |= (uint32_t)s[offsets[i] + j] << (j * 8);
if (i == 9) word &= 8388607; /* Ignore the encoded sign bit. */
limbs[i] = (int64_t)word << shifts[i];
}
fe_compact_carry(h, limbs, fe_decode_carries, sizeof(fe_decode_carries));
}
void fe_mul121666(fe h, fe f) {
int64_t limbs[10];
int i;
for (i = 0; i < 10; ++i) limbs[i] = (int64_t)f[i] * 121666;
fe_compact_carry(h, limbs, fe_decode_carries, sizeof(fe_decode_carries));
}
void fe_tobytes(unsigned char *s, const fe h) {
int32_t limbs[10], q = (19 * h[9] + (1 << 24)) >> 25;
int i, index = 0, offset = 0;
for (i = 0; i < 10; ++i) {
limbs[i] = h[i];
q = (limbs[i] + q) >> (26 - (i & 1));
}
limbs[0] += 19 * q;
for (i = 0; i < 10; ++i) {
const int bits = 26 - (i & 1);
const int32_t carry = limbs[i] >> bits;
if (i < 9) limbs[i + 1] += carry;
limbs[i] -= carry * ((int32_t)1 << bits);
}
/* Each byte crosses at most one public radix boundary. Normalized limbs
* are nonnegative, and unsigned shifts avoid overflowing signed int32. */
for (i = 0; i < 32; ++i) {
uint32_t byte = (uint32_t)limbs[index] >> offset;
offset += 8;
if (offset >= 26 - (index & 1)) {
offset -= 26 - (index & 1);
++index;
if (offset && index < 10)
byte |= (uint32_t)limbs[index] << (8 - offset);
}
s[i] = (unsigned char)byte;
}
}
int fe_isnonzero(const fe f) {
unsigned char bytes[32], value = 0;
int i;
fe_tobytes(bytes, f);
for (i = 0; i < 32; ++i) value |= bytes[i];
return value != 0;
}
static void fe_compact_product(fe h, const fe f, const fe g, int doubled) {
static const unsigned char carry_order[] = {0, 4, 1, 5, 2, 6, 3, 7, 4, 8, 9, 0};
int64_t limbs[10] = {0};
@@ -63,17 +144,7 @@ static void fe_compact_product(fe h, const fe f, const fe g, int doubled) {
if (doubled) {
for (i = 0; i < 10; ++i) limbs[i] += limbs[i];
}
for (i = 0; i < (int)sizeof(carry_order); ++i) {
const int index = carry_order[i];
const int bits = 26 - (index & 1);
const int64_t radix = (int64_t)1 << bits;
const int64_t carry = (limbs[index] + radix / 2) >> bits;
if (index == 9) limbs[0] += carry * 19;
else limbs[index + 1] += carry;
/* A carry may be negative; do not left-shift that signed value. */
limbs[index] -= carry * radix;
}
for (i = 0; i < 10; ++i) h[i] = (int32_t)limbs[i];
fe_compact_carry(h, limbs, carry_order, sizeof(carry_order));
}
void fe_mul(fe h, const fe f, const fe g) {