This commit is contained in:
Triss 2023-08-23 05:02:35 +02:00
commit 42e59d38c5
9 changed files with 390 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
cmake-build/
test*.*
screenlog.*

40
CMakeLists.txt Normal file
View File

@ -0,0 +1,40 @@
set(PROJECT "rorand")
option(PICO_NO_FLASH "Disable writing the compiled program to flash, and only load it to RAM. Useful for testing, but not much else (OFF by default)." OFF)
option(PICO_COPY_TO_RAM "Run all code in RAM, while the program is also stored on flash. On bootup, everything will be copied to RAM (OFF by default)." OFF)
cmake_minimum_required(VERSION 3.11)
include(${CMAKE_CURRENT_SOURCE_DIR}/pico_sdk_import.cmake)
project(${PROJECT})
pico_sdk_init()
add_executable(${PROJECT})
# use usb output
pico_enable_stdio_uart(${PROJECT} 0)
pico_enable_stdio_usb(${PROJECT} 1)
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
${CMAKE_CURRENT_SOURCE_DIR}/src/rorand.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
)
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/
)
target_link_libraries(${PROJECT}
pico_stdlib pico_unique_id hardware_pio hardware_dma hardware_clocks
hardware_resets hardware_sync hardware_pwm cmsis_core pico_multicore
tinyusb_device_unmarked pico_usb_reset_interface_headers pico_unique_id
)
pico_add_extra_outputs(${PROJECT})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type -Werror=aggressive-loop-optimizations")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--cref")

1
README.md Normal file
View File

@ -0,0 +1 @@
# rorand

62
pico_sdk_import.cmake Normal file
View File

@ -0,0 +1,62 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

55
src/main.c Normal file
View File

@ -0,0 +1,55 @@
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <hardware/structs/bus_ctrl.h>
#include <hardware/structs/rosc.h>
#include <hardware/clocks.h>
#include <hardware/vreg.h>
#include <pico/stdlib.h>
#include <pico/time.h>
#include "rorand.h"
#include "util.h"
int main() {
vreg_set_voltage(VREG_VOLTAGE_1_15);
set_sys_clock_khz(250*1000, true);
for (size_t i = 0; i < 0x100; ++i) asm volatile("nop");
busy_wait_ms(16);
stdio_init_all();
while (!stdio_usb_connected()) ;
busy_wait_ms(16);
iprintf("hello world!\n");
if ((clocks_hw->clk[clk_sys].ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) ==
(CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB)) {
panic("System is running from ring oscillator. This makes it impossible to be used as randomness source.\n");
}
rorand_init();
uint8_t data[32];
memset(data, 0, sizeof(data));
const uintptr_t total = 1024*1024;
for (uintptr_t off = 0; off < total; off += count_of(data)) {
rorand_get(data, count_of(data)*CHAR_BIT);
hexdump(NULL, off, data, sizeof(data));
}
iprintf("done\n");
/*uint32_t a = 0;
while(1) {
iprintf("a%lu ", a);
++a;
if (a>16)break;
}
iprintf("\n");*/
while(1);
return 0;
}

184
src/rorand.c Normal file
View File

@ -0,0 +1,184 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <RP2040.h>
#include <hardware/structs/psm.h>
#include <hardware/structs/rosc.h>
#include <hardware/structs/systick.h>
#include <pico/stdlib.h>
#include <pico/critical_section.h>
#include "rorand.h"
#define IMPL 2
static inline uint32_t enter_critical_section(void) {
__DSB();
__ISB();
uint32_t dis = __get_PRIMASK();
__disable_irq();
return dis;
}
static inline void exit_critical_section(uint32_t dis) {
__DSB();
__ISB();
__set_PRIMASK(dis);
}
static inline void rosc_wait_stab(void) {
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS)) ;
}
static uint32_t tests[256];
static uint32_t testind;
static critical_section_t cs;
static void test_monitor(uint32_t v) {
tests[testind] = v;
++testind;
if (testind == count_of(tests)) {
//iprintf("[tst] do test!\n");
// get average
uint64_t avg = 0;
for (size_t i = 0; i < count_of(tests); ++i) avg += tests[i];
avg >>= 8;
// get variance
uint64_t var = 0;
for (size_t i = 0; i < count_of(tests); ++i) {
uint64_t x = tests[i] - avg;
var += x * x;
}
var >>= 8;
float stddev = sqrtf((uint32_t)var);
printf("[tst] avg=%llu, var=%llu stddev=%f\n", avg, var, stddev);
testind = 0;
}
}
static uint __time_critical_func(get_raw_bit_a)(void) {
busy_wait_us_32(1);
// 1. power-gate rosc and wait a bit for the value to become indeterminate
psm_hw->frce_off = PSM_FRCE_OFF_ROSC_BITS;
busy_wait_us_32(1);
// 2. bring it back
psm_hw->frce_on = PSM_FRCE_ON_ROSC_BITS;
while (!(psm_hw->done & PSM_DONE_ROSC_BITS)) ;
rorand_init();
uint bit = rosc_hw->randombit & 1;
// TODO: test monitor?
return bit;
}
static uint __time_critical_func(get_raw_bit_b)(void) {
volatile uint32_t* tick = &SysTick->VAL;
volatile uint32_t* count = &rosc_hw->count;
uint32_t a, b;
critical_section_enter_blocking(&cs);
uint32_t v = enter_critical_section();
{
*tick = 0;
__COMPILER_BARRIER();
a = *tick;
__COMPILER_BARRIER();
for (size_t i = 0; i < 0x1/*000*/; ++i) {
*count = 0x80;
// TODO: tweak the above parameter.
// * 0x20 seems to result in a few weak test results in dieharder (1 MiB data)
// * 0x80 seems to pass them
// -> take something in the middle to speed up things while still being good?
// problematic test are diehard_operm5, sts_monobit
__COMPILER_BARRIER();
while (*count) __COMPILER_BARRIER();
}
__COMPILER_BARRIER();
b = *tick;
}
exit_critical_section(v);
critical_section_exit(&cs);
uint32_t diff = a - b;
//iprintf("[---] diff=%lu a=%lu b=%lu\n", diff, a, b);
uint bit = diff & 1;
uint32_t test = diff >> 1;
//test_monitor(test);
return bit ^ rosc_hw->randombit;
}
inline static uint get_raw_bit(void) {
/*#if IMPL == 1
return get_raw_bit_a();
#else*/
return get_raw_bit_b();
/*#endif*/
}
static uint neumann_filter(void) {
uint a, b;
uint32_t counter = 0;
const uint32_t limit = 0x40;
do {
a = get_raw_bit();
b = get_raw_bit();
++counter;
} while (a == b && counter < limit);
if (counter == limit) iprintf("[---] aaaaaaa!\n");
//iprintf("[---] emit bit %u%s\n", b, (counter == 0x100) ? "aaaaaa" : "");
return b;
}
void rorand_init(void) {
critical_section_init(&cs);
testind = 0;
memset(tests, 0, sizeof(tests));
SysTick->LOAD = 0xffffffffu;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
/*psm_hw->frce_on = PSM_FRCE_ON_ROSC_BITS;
while (!(psm_hw->done & PSM_DONE_ROSC_BITS)) ;
iprintf("[---] rosc power on\n");*/
//rosc_hw->dormant = 1;
rosc_hw->ctrl = 0xfabfa7; // enable, high freqrange
rosc_hw->freqa = 0x96967777;
rosc_hw->freqb = 0x96967777;
//rosc_hw->dormant = 0;
rosc_wait_stab();
iprintf("[---] rosc now stab\n");
}
void rorand_get(void* dst_, size_t nbits) {
uint8_t* dst = (uint8_t*)dst_;
for (size_t j = 0; j < nbits; j += 8) {
size_t bs = nbits - j;
if (bs > 8) bs = 8;
//iprintf("[===] byte %u (%u bits)\n", j>>3, bs);
uint8_t v = 0;
for (size_t i = 0; i < bs; ++i) {
v <<= 1;
uint r = neumann_filter();
v |= r;
}
//iprintf("[===] emit byte %02hhx\n", v);
*dst = v;
++dst;
}
}

11
src/rorand.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef RORAND_H_
#define RORAND_H_
#include <stddef.h>
void rorand_init(void);
void rorand_get(void* dst, size_t nbits);
#endif

22
src/util.c Normal file
View File

@ -0,0 +1,22 @@
#include <stdio.h>
#include "util.h"
void hexdump(const char* pfix, uintptr_t baseaddr, const void* data_, size_t nbytes) {
char fmt[8];
const uint8_t* data = (const uint8_t*)data_;
if (pfix) iprintf("%s:\n", pfix);
uint32_t nybs = ((32 - __builtin_clz(baseaddr + nbytes)) + 3) >> 2;
sniprintf(fmt, sizeof fmt, "%%0%lulx\t", nybs);
for (size_t i = 0; i < nbytes; i += 16) {
iprintf(fmt, baseaddr + i);
for (size_t j = 0; i + j < nbytes && j < 16; ++j) {
iprintf("%02hhx%c", data[i+j], (j == 15 || i+j == nbytes-1) ? '\n' : ' ');
}
}
}

12
src/util.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef UTIL_H_
#define UTIL_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
void hexdump(const char* pfix, uintptr_t baseaddr, const void* data, size_t nbytes);
#endif