Compare commits

..

2 commits

Author SHA1 Message Date
Imbus
b16c3b098a Safe mulmod, used in modexp and friends 2025-02-13 00:35:52 +01:00
Imbus
50e640ea84 Seed saving to flash with regular intervals 2025-02-13 00:35:28 +01:00
4 changed files with 137 additions and 39 deletions

71
rand.c
View file

@ -1,22 +1,79 @@
#include "rand.h"
#include "ch32fun.h"
#include <stdint.h> #include <stdint.h>
#include <stdint.h> #define BUILD_SEED \
((uint64_t)(__TIME__[0]) * (uint64_t)(__TIME__[1]) * \
(uint64_t)(__TIME__[3]) * (uint64_t)(__TIME__[4]) * \
(uint64_t)(__TIME__[6]) * (uint64_t)(__TIME__[7]))
#define BUILD_SEED ((uint64_t)(__TIME__[0]) * (uint64_t)(__TIME__[1]) * \ #define FLASH_SEED_ADDR ((uintptr_t *)0x08003700) // PRNG state storage
(uint64_t)(__TIME__[3]) * (uint64_t)(__TIME__[4]) * \ #define PRNG_SAVE_INTERVAL 50 // Save every 1000 calls to prand()
(uint64_t)(__TIME__[6]) * (uint64_t)(__TIME__[7]))
static uint64_t seed = BUILD_SEED; static uint64_t seed = BUILD_SEED;
void sprand(uint64_t s) { // Initialize this to something close to interval
seed = s ? s : 1; // Ensure the seed is never 0 static int prand_counter = PRNG_SAVE_INTERVAL - 10;
}
uint64_t prand() { uint64_t prand() {
seed = seed * 6364136223846793005ULL + 1; seed = seed * 6364136223846793005ULL + 1;
if (++prand_counter >= PRNG_SAVE_INTERVAL) {
rand_save_to_flash();
prand_counter = 0;
}
return seed; return seed;
} }
uint64_t prand_range(uint64_t min, uint64_t max) { uint64_t prand_range(uint64_t min, uint64_t max) {
return min + (prand() % (max - min + 1)); return min + (prand() % (max - min + 1));
} }
void sprand(uint64_t s) {
if (s) {
seed = s;
} else {
rand_reseed();
}
}
void rand_reseed() {
uint64_t stored_seed = *(volatile uint64_t *)FLASH_SEED_ADDR;
if (stored_seed == 0 || stored_seed == 0xFFFFFFFFFFFFFFFFULL) {
seed = BUILD_SEED;
} else {
seed = stored_seed;
}
}
// See:
// https://github.com/cnlohr/ch32v003fun/blob/2ac62072272f2ccd2122e688a9e0566de3976a94/examples/flashtest/flashtest.c
void rand_save_to_flash() {
FLASH->KEYR = 0x45670123; // Unlock flash
FLASH->KEYR = 0xCDEF89AB;
FLASH->MODEKEYR = 0x45670123; // Unlock programming mode
FLASH->MODEKEYR = 0xCDEF89AB;
// Erase the flash page
FLASH->CTLR = CR_PAGE_ER;
FLASH->ADDR = (intptr_t)FLASH_SEED_ADDR;
FLASH->CTLR = CR_STRT_Set | CR_PAGE_ER;
while (FLASH->STATR & FLASH_STATR_BSY); // Wait for erase
// Write new seed
FLASH->CTLR = CR_PAGE_PG;
FLASH->CTLR = CR_BUF_RST | CR_PAGE_PG;
FLASH->ADDR = (intptr_t)FLASH_SEED_ADDR;
((uint32_t *)FLASH_SEED_ADDR)[0] = (uint32_t)seed;
((uint32_t *)FLASH_SEED_ADDR)[1] = (uint32_t)(seed >> 32);
FLASH->CTLR = CR_PAGE_PG | FLASH_CTLR_BUF_LOAD;
while (FLASH->STATR & FLASH_STATR_BSY); // Wait for completion
FLASH->CTLR = CR_PAGE_PG | CR_STRT_Set; // Commit write
while (FLASH->STATR & FLASH_STATR_BSY); // Wait for completion
}

25
rand.h
View file

@ -2,18 +2,18 @@
#include <stdint.h> #include <stdint.h>
/** /**
* @brief Sets the seed for the custom random number generator. * @brief Sets the seed for the PRNG.
* *
* This function initializes the seed value used by rand_custom(). * @param s The specific seed value or zero. If zero is passed, it will call
* Providing the same seed will produce the same sequence of random numbers. * rand_reseed().
*
* @param s The seed value (must be nonzero for best results).
*/ */
void sprand(uint64_t s); void sprand(uint64_t s);
/** /**
* @brief Generates a pseudo-random 64-bit number. * @brief Generates a pseudo-random 64-bit number.
* *
* Saves PRNG state to flash periodically.
*
* Uses a simple Linear Congruential Generator (LCG) to produce * Uses a simple Linear Congruential Generator (LCG) to produce
* a sequence of pseudo-random numbers. * a sequence of pseudo-random numbers.
* *
@ -32,3 +32,18 @@ uint64_t prand();
* @return A random number between min and max. * @return A random number between min and max.
*/ */
uint64_t prand_range(uint64_t min, uint64_t max); uint64_t prand_range(uint64_t min, uint64_t max);
/**
* @brief Saves the current PRNG seed to flash memory.
*
* This function erases the designated flash page and writes the current seed
* to ensure the PRNG state persists across resets.
*/
void rand_save_to_flash();
/**
* @brief Re-seeds the PRNG seed state from either flash or BUILD_SEED.
*
* This function will not write to flash.
*/
void rand_reseed();

65
rsa.c
View file

@ -3,28 +3,28 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#define NULL ((void *)0)
uint64_t gcd(uint64_t a, uint64_t b) { uint64_t gcd(uint64_t a, uint64_t b) {
while (b != 0) { return extended_euclid(a, b, NULL, NULL);
uint64_t temp = b;
b = a % b;
a = temp;
}
return a;
} }
int extended_euclid(int a, int b, int *x, int *y) { int extended_euclid(int a, int b, int *x, int *y) {
if (b == 0) { if (b == 0) {
*x = 1; if (x)
*y = 0; *x = 1;
if (y)
*y = 0;
return a; return a;
} }
int x1, y1; int x1, y1;
int gcd = extended_euclid(b, a % b, &x1, &y1); int gcd = extended_euclid(b, a % b, &x1, &y1);
// Update x and y using results from recursive call if (x)
*x = y1; *x = y1;
*y = x1 - (a / b) * y1; if (y)
*y = x1 - (a / b) * y1;
return gcd; return gcd;
} }
@ -51,18 +51,31 @@ int totient(int n) {
return result; return result;
} }
uint64_t modexp(uint64_t a, uint64_t b, uint64_t m) { uint64_t mulmod(uint64_t a, uint64_t b, uint64_t m) {
uint64_t result = 1; uint64_t result = 0;
a = a % m; // In case a is greater than m a %= m;
while (b > 0) { while (b > 0) {
// If b is odd, multiply a with result if (b & 1) {
if (b % 2 == 1) result = (result + a) % m; // Avoid overflow
result = (result * a) % m; }
a = (a * 2) % m; // Double a, keep within mod
b >>= 1;
}
// b must be even now return result;
b = b >> 1; // b = b // 2 }
a = (a * a) % m; // Change a to a^2
uint64_t modexp(uint64_t a, uint64_t b, uint64_t m) {
uint64_t result = 1;
a %= m;
while (b > 0) {
if (b & 1) {
result = mulmod(result, a, m);
}
b >>= 1;
a = mulmod(a, a, m);
} }
return result; return result;
@ -70,7 +83,7 @@ uint64_t modexp(uint64_t a, uint64_t b, uint64_t m) {
uint64_t gen_prime(uint64_t min, uint64_t max) { uint64_t gen_prime(uint64_t min, uint64_t max) {
uint64_t cand = 0; uint64_t cand = 0;
while (!miller_rabin(cand, 5)) cand = prand_range(min, max); while (!miller_rabin(cand, 10)) cand = prand_range(min, max);
return cand; return cand;
} }
@ -119,17 +132,17 @@ bool miller_rabin(uint64_t n, uint64_t k) {
return true; // Likely prime return true; // Likely prime
} }
int mod_inverse(int a, int m) { uint64_t mod_inverse(uint64_t a, uint64_t m) {
int m0 = m; uint64_t m0 = m;
int y = 0, x = 1; uint64_t y = 0, x = 1;
if (m == 1) if (m == 1)
return 0; return 0;
while (a > 1) { while (a > 1) {
// q is quotient // q is quotient
int q = a / m; uint64_t q = a / m;
int t = m; uint64_t t = m;
// m is remainder now // m is remainder now
m = a % m; m = a % m;

15
rsa.h
View file

@ -21,6 +21,19 @@ uint64_t gcd(uint64_t a, uint64_t b);
*/ */
int totient(int n); int totient(int n);
/**
* @brief Computes (a * b) % m safely without overflow.
*
* Uses repeated addition and bit shifting to handle large values,
* ensuring correctness even on 32-bit microcontrollers.
*
* @param a The first operand.
* @param b The second operand.
* @param m The modulus.
* @return (a * b) % m computed safely.
*/
uint64_t mulmod(uint64_t a, uint64_t b, uint64_t m);
/** /**
* @brief Modular exponentiation (a^b) mod m * @brief Modular exponentiation (a^b) mod m
* *
@ -37,7 +50,7 @@ uint64_t modexp(uint64_t a, uint64_t b, uint64_t m);
* @param m The modulus. * @param m The modulus.
* @return The modular inverse of a modulo m, or -1 if no inverse exists. * @return The modular inverse of a modulo m, or -1 if no inverse exists.
*/ */
int mod_inverse(int a, int m); uint64_t mod_inverse(uint64_t a, uint64_t m);
/** /**
* @brief Generates a random prime number within the given range. * @brief Generates a random prime number within the given range.