Delete sample code
This commit is contained in:
parent
88def95e47
commit
aaf7652391
8 changed files with 4 additions and 522 deletions
2
Makefile
2
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 \
|
||||
|
|
25
assert.h
25
assert.h
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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)
|
10
funconfig.h
10
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
|
||||
|
|
113
main.c
113
main.c
|
@ -1,122 +1,15 @@
|
|||
#include "assert.h"
|
||||
#include <ch32fun.h>
|
||||
#include <rand.h>
|
||||
#include <rsa.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
80
rand.c
80
rand.c
|
@ -1,80 +0,0 @@
|
|||
#include "rand.h"
|
||||
#include "ch32fun.h"
|
||||
#include "ch32v003hw.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 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
|
||||
}
|
49
rand.h
49
rand.h
|
@ -1,49 +0,0 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @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();
|
148
rsa.c
148
rsa.c
|
@ -1,148 +0,0 @@
|
|||
#include "rsa.h"
|
||||
#include "funconfig.h"
|
||||
#include "rand.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
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;
|
||||
}
|
99
rsa.h
99
rsa.h
|
@ -1,99 +0,0 @@
|
|||
#pragma once
|
||||
#include "funconfig.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// 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);
|
Loading…
Add table
Reference in a new issue