diff --git a/Makefile b/Makefile index bdf06c6..bf87868 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ CC := $(TOOL_PREFIX)-gcc OBJDUMP := $(TOOL_PREFIX)-objdump OBJCOPY := $(TOOL_PREFIX)-objcopy -SRC := ch32fun.c main.c rsa.c rand.c +SRC := ch32fun.c main.c CFLAGS = -g \ -Os \ diff --git a/assert.h b/assert.h deleted file mode 100644 index e2fc017..0000000 --- a/assert.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -#define ASSERT(expr) \ - do { \ - if (!(expr)) { \ - printf("ASSERTION FAILED: %s at %s:%d\n", #expr, __FILE__, \ - __LINE__); \ - while (1); \ - } \ - } while (0) - -#define ASSERT_EQ(expr, expected) \ - do { \ - uint64_t result = (expr); \ - if (result != (expected)) { \ - printf("ASSERTION FAILED: %s at %s:%d\n", #expr, __FILE__, \ - __LINE__); \ - printf("Expected: %lu, Got: %lu\n", (unsigned long)(expected), \ - (unsigned long)result); \ - while (1); \ - } \ - } while (0) diff --git a/funconfig.h b/funconfig.h index 561ab22..589e69e 100644 --- a/funconfig.h +++ b/funconfig.h @@ -5,14 +5,4 @@ #define CH32V003 1 -#define NULL ((void *)0) - -typedef int8_t i8; -typedef uint8_t u8; -typedef int16_t i16; -typedef uint32_t u32; -typedef int32_t i32; -typedef int64_t i64; -typedef uint64_t u64; - #endif diff --git a/main.c b/main.c index 28a423d..0191f1e 100644 --- a/main.c +++ b/main.c @@ -1,122 +1,15 @@ -#include "assert.h" #include -#include -#include -#include -#include -#include #define LED_PIN PD6 -#define RANDOM -#define W 16 - -void exit_blink() { - for (int i = 0; i < 4; i++) { - funDigitalWrite(LED_PIN, FUN_HIGH); - Delay_Ms(50); - funDigitalWrite(LED_PIN, FUN_LOW); - Delay_Ms(50); - } -} - -void enter_blink() { - for (int i = 0; i < 2; i++) { - funDigitalWrite(LED_PIN, FUN_HIGH); - Delay_Ms(200); - funDigitalWrite(LED_PIN, FUN_LOW); - Delay_Ms(200); - } -} - -void test_mulmod() { - ASSERT_EQ(mulmod(3, 2, 4), 2); - ASSERT_EQ((3 * 2) % 4, 2); - - ASSERT_EQ(mulmod(31, 3, 8), 5); - ASSERT_EQ(mulmod((u64)1 << 63, 2, 1000000007ULL), 582344008); -} - -void test_modexp() { - ASSERT_EQ(modexp(3, 2, 4), 1); - ASSERT_EQ((3 ^ 2) % 4, 1); - - ASSERT_EQ(modexp(31, 3, 8), 7); - ASSERT_EQ(modexp((u64)1 << 63, 2, 1000000007ULL), 319908071); -} - -void debug_string(char *str) { - printf("Got string: %s\n", str); - for (int i = 0; i < strlen(str); i++) { - printf("decoded[%d] = '%c' (ASCII: %d)\n", i, str[i], - str[i]); // Print decoded chars and ASCII values - } -} - int main() { SystemInit(); - sprand(0); funGpioInitAll(); funPinMode(LED_PIN, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP); - enter_blink(); + funDigitalWrite(LED_PIN, 1); + Delay_Ms(100); + funDigitalWrite(LED_PIN, 0); - test_mulmod(); - test_modexp(); - - const u64 p = gen_prime(1 << (W - 1), 1 << W); - printf("P: %u\n", (u32)p); - - u64 qprev = p; - while (p == qprev) qprev = gen_prime(1 << (W - 1), 1 << W); - - const u64 q = qprev; - printf("Q: %u\n", (u32)q); - - ASSERT(gcd(p - 1, PUBEXP) == 1); - ASSERT(gcd(q - 1, PUBEXP) == 1); - - u64 n = p * q; - printf("N: %u\n", (u32)n); - - u64 phi_n = (p - 1) * (q - 1); - printf("Phi_N: %u\n", (u32)phi_n); - - u64 d = mod_inverse(PUBEXP, phi_n); - printf("D: %u\n", (u32)d); - if (d == 0 || d == 1) { - printf("Modular inverse not found..."); - } - - ASSERT_EQ(mulmod(PUBEXP, d, phi_n), 1); - - char msg[] = "Hello"; - u64 coded[sizeof(msg)] = {0}; - char decoded[sizeof(msg)] = {0}; - - // Encode the message - for (int i = 0; i < strlen(msg); i++) { - coded[i] = modexp((u64)msg[i], PUBEXP, n); - } - - // Decode the message - for (int i = 0; i < strlen(msg); i++) { - u64 dec = modexp(coded[i], d, n); - decoded[i] = dec & 0xFF; - } - - { - printf("Message: %s\n", msg); - printf("Decoded: %s\n", decoded); - - for (int i = 0; i < strlen(msg); i++) { - printf("coded[%d] = 0x%016lx\n", i, (unsigned long)coded[i]); - } - - debug_string(decoded); - } - - // Exit and hang forever - exit_blink(); while (1); } diff --git a/rand.c b/rand.c deleted file mode 100644 index d2e2c28..0000000 --- a/rand.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "rand.h" -#include "ch32fun.h" -#include "ch32v003hw.h" -#include - -#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 FLASH_SEED_ADDR ((uintptr_t *)0x08003700) // PRNG state storage -#define PRNG_SAVE_INTERVAL 50 // Save every 1000 calls to prand() - -static uint64_t seed = BUILD_SEED; - -// Initialize this to something close to interval -static int prand_counter = PRNG_SAVE_INTERVAL - 10; - -uint64_t prand() { - seed = seed * 6364136223846793005ULL + 1; - - if (++prand_counter >= PRNG_SAVE_INTERVAL) { - rand_save_to_flash(); - prand_counter = 0; - } - - return seed; -} - -uint64_t prand_range(uint64_t min, uint64_t max) { - 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 = FLASH_KEY1; // Unlock flash - FLASH->KEYR = FLASH_KEY2; - - FLASH->MODEKEYR = FLASH_KEY1; // Unlock programming mode - FLASH->MODEKEYR = FLASH_KEY2; - - // 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 -} diff --git a/rand.h b/rand.h deleted file mode 100644 index 26c4194..0000000 --- a/rand.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include - -/** - * @brief Sets the seed for the PRNG. - * - * @param s The specific seed value or zero. If zero is passed, it will call - * rand_reseed(). - */ -void sprand(uint64_t s); - -/** - * @brief Generates a pseudo-random 64-bit number. - * - * Saves PRNG state to flash periodically. - * - * Uses a simple Linear Congruential Generator (LCG) to produce - * a sequence of pseudo-random numbers. - * - * @return A pseudo-random 64-bit unsigned integer. - */ -uint64_t prand(); - -/** - * @brief Generates a random number within a specified range. - * - * Produces a random number in the inclusive range [min, max]. - * Ensures uniform distribution by applying a modulo operation. - * - * @param min The lower bound of the range (inclusive). - * @param max The upper bound of the range (inclusive). - * @return A random number between min and 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(); diff --git a/rsa.c b/rsa.c deleted file mode 100644 index 5a588eb..0000000 --- a/rsa.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "rsa.h" -#include "funconfig.h" -#include "rand.h" -#include - -u64 gcd(u64 a, u64 b) { return extended_euclid(a, b, NULL, NULL); } - -u64 extended_euclid(u64 a, u64 b, u64 *x, u64 *y) { - if (b == 0) { - if (x) *x = 1; - if (y) *y = 0; - return a; - } - - u64 x1, y1; - u64 gcd = extended_euclid(b, a % b, &x1, &y1); - - if (x) *x = y1; - if (y) *y = x1 - (a / b) * y1; - - return gcd; -} - -u64 totient(u64 n) { - int result = n; - - // Check for prime factors - for (int p = 2; p * p <= n; p++) { - if (n % p == 0) { - // If p is a prime factor of n, remove all occurrences of p - while (n % p == 0) { - n /= p; - } - result -= result / p; - } - } - - // If n is still greater than 1, then it's a prime factor itself - if (n > 1) { - result -= result / n; - } - - return result; -} - -u64 mulmod(u64 a, u64 b, u64 m) { - u64 result = 0; - a %= m; - - // Perform the multiplication bit by bit (binary multiplication) - while (b > 0) { - if (b & 1) { - result = (result + a) % m; - } - a = (a * 2) % m; // Double a, keep it within the modulus - b >>= 1; // Right shift b (divide by 2) - } - - return result; -} - -u64 modexp(u64 a, u64 b, u64 m) { - u64 result = 1; - a %= m; - - while (b > 0) { - if (b & 1) { - result = mulmod(result, a, m); - } - b >>= 1; - a = mulmod(a, a, m); - } - - return result; -} - -u64 gen_prime(u64 min, u64 max) { - u64 cand = 0; - while (!miller_rabin(cand, 10)) cand = prand_range(min, max); - - return cand; -} - -bool is_prime(u64 n) { - if (n < 2) return false; - - for (int i = 2; i < n / 2 + 1; i++) { - if (n % i == 0) return false; - } - - return true; -} - -bool miller_rabin(u64 n, u64 k) { - if (n < 2) return false; - - u64 d = n - 1; - u64 s = 0; - - while (d % 2 == 0) { - d /= 2; - s++; - } - - for (u64 i = 0; i < k; i++) { - u64 a = prand_range(2, n - 2); - u64 x = modexp(a, d, n); - - if (x == 1 || x == n - 1) continue; - - for (u64 r = 1; r < s; r++) { - x = modexp(x, 2, n); - if (x == n - 1) break; - } - - if (x != n - 1) return false; // Not prime - } - - return true; // Likely prime -} - -u64 mod_inverse(u64 a, u64 m) { - u64 m0 = m; - u64 y = 0, x = 1; - - // Modular inverse does not exist when m is 1 - if (m == 1) return 0; - - while (a > 1) { - // q is quotient - u64 q = a / m; - u64 t = m; - - // m is remainder now - m = a % m; - a = t; - t = y; - - // Update x and y - y = x - q * y; - x = t; - } - - // Make x positive - if (x < 0) x += m0; - - return x; -} diff --git a/rsa.h b/rsa.h deleted file mode 100644 index 910ae1a..0000000 --- a/rsa.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once -#include "funconfig.h" -#include -#include - -// Common public exponent, in Fermat prime form -#define PUBEXP ((1 << 16) | 0x1) - -/** - * @brief Calculates greatest common divider of two integers using the euclidean - * algorithm - * - * @param a First number - * @param b Second number - * @return The greatest common divider - */ -u64 gcd(u64 a, u64 b); - -/** - * @brief Computes Euler's Totient function φ(n), which counts the number of - * integers from 1 to n that are coprime to n. - * - * @param n The input number. - * @return The number of integers from 1 to n that are coprime to n. - */ -u64 totient(u64 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. - */ -u64 mulmod(u64 a, u64 b, u64 m); - -/** - * @brief Modular exponentiation (a^b) mod m - * - * @param a The base - * @param b The exponent - * @param m The modulus - */ -u64 modexp(u64 a, u64 b, u64 m); - -/** - * @brief Computes the modular inverse of a modulo m. - * - * @param a The integer whose modular inverse is to be found. - * @param m The modulus. - * @return The modular inverse of a modulo m, or -1 if no inverse exists. - */ -u64 mod_inverse(u64 a, u64 m); - -/** - * @brief Generates a random prime number within the given range. - * - * @param min The lower bound (inclusive). - * @param max The upper bound (inclusive). - * @return A prime number in the range [min, max]. - */ -u64 gen_prime(u64 min, u64 max); - -/** - * @brief Checks if a number is prime. - * - * @param n The number to check. - * @return true if n is prime, false otherwise. - */ -bool is_prime(u64 n); - -/** - * @brief Performs the Miller-Rabin primality test to check if a number is - * probably prime. - * - * @param n The number to test for primality. - * @param k The number of rounds of testing to perform. - * @return true if n is probably prime, false if n is composite. - */ -bool miller_rabin(u64 n, u64 k); - -/** - * @brief Computes the greatest common divisor (GCD) of two integers a and b - * using the Extended Euclidean Algorithm. Also finds coefficients x and y such - * that ax + by = gcd(a, b). - * - * @param a The first integer. - * @param b The second integer. - * @param x Pointer to an integer to store the coefficient x in the equation ax - * + by = gcd(a, b). - * @param y Pointer to an integer to store the coefficient y in the equation ax - * + by = gcd(a, b). - * @return The greatest common divisor (gcd) of a and b. - */ -u64 extended_euclid(u64 a, u64 b, u64 *x, u64 *y);