From 42e59d38c5b3f6e67ed397e45fd353df91dcc3a6 Mon Sep 17 00:00:00 2001 From: Triss Date: Wed, 23 Aug 2023 05:02:35 +0200 Subject: [PATCH] initial --- .gitignore | 3 + CMakeLists.txt | 40 +++++++++ README.md | 1 + pico_sdk_import.cmake | 62 ++++++++++++++ src/main.c | 55 +++++++++++++ src/rorand.c | 184 ++++++++++++++++++++++++++++++++++++++++++ src/rorand.h | 11 +++ src/util.c | 22 +++++ src/util.h | 12 +++ 9 files changed, 390 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 pico_sdk_import.cmake create mode 100644 src/main.c create mode 100644 src/rorand.c create mode 100644 src/rorand.h create mode 100644 src/util.c create mode 100644 src/util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..706b96c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +cmake-build/ +test*.* +screenlog.* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6737c79 --- /dev/null +++ b/CMakeLists.txt @@ -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") diff --git a/README.md b/README.md new file mode 100644 index 0000000..0c804df --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# rorand diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake new file mode 100644 index 0000000..28efe9e --- /dev/null +++ b/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /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}) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b1c87b9 --- /dev/null +++ b/src/main.c @@ -0,0 +1,55 @@ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#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; +} + diff --git a/src/rorand.c b/src/rorand.c new file mode 100644 index 0000000..505433d --- /dev/null +++ b/src/rorand.c @@ -0,0 +1,184 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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; + } +} + diff --git a/src/rorand.h b/src/rorand.h new file mode 100644 index 0000000..a5755aa --- /dev/null +++ b/src/rorand.h @@ -0,0 +1,11 @@ + +#ifndef RORAND_H_ +#define RORAND_H_ + +#include + +void rorand_init(void); +void rorand_get(void* dst, size_t nbits); + +#endif + diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..213bee0 --- /dev/null +++ b/src/util.c @@ -0,0 +1,22 @@ + +#include + +#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' : ' '); + } + } +} + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..4297ee3 --- /dev/null +++ b/src/util.h @@ -0,0 +1,12 @@ + +#ifndef UTIL_H_ +#define UTIL_H_ + +#include +#include +#include + +void hexdump(const char* pfix, uintptr_t baseaddr, const void* data, size_t nbytes); + +#endif +