aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Thulin <fredrik@thulin.net>2016-11-21 11:45:58 +0100
committerFredrik Thulin <fredrik@thulin.net>2016-11-21 14:14:09 +0100
commite7f5fdebef90d0be01edeabd4ea260138ed1fbd0 (patch)
tree2396c0328e3bbee3f8286fe3c0b443bef4c76d58
parentc4678339908e413cbc6751cf863267807acafc85 (diff)
add RNG using ChaCha20 as CSPRNG
-rw-r--r--Makefile2
-rw-r--r--common.mk3
-rw-r--r--src/cc20rng/Makefile56
-rw-r--r--src/cc20rng/cc20_prng.c219
-rw-r--r--src/cc20rng/cc20_prng.h18
-rw-r--r--src/cc20rng/main.c358
-rw-r--r--src/cc20rng/main.h4
-rw-r--r--src/cc20rng/stm32f4xx_hal_msp.c113
-rw-r--r--src/cc20rng/stm32f4xx_it.c208
-rw-r--r--src/cc20rng/stm32f4xx_it.h70
-rw-r--r--src/cc20rng/stm_init.c290
-rw-r--r--src/cc20rng/stm_init.h18
-rw-r--r--src/cc20rng/system_stm32f4xx.c270
-rw-r--r--src/cc20rng/test.c10
14 files changed, 1637 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 134ab13..1e6dfcf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-APPLICATION = entropy
+APPLICATION = cc20rng
SRCDIR = src/$(APPLICATION)
all: target
diff --git a/common.mk b/common.mk
index d9b981b..9006feb 100644
--- a/common.mk
+++ b/common.mk
@@ -31,6 +31,7 @@ OPENOCD_BOARD_DIR ?= /usr/share/openocd/scripts/board
# the OPENOCD_BOARD_DIR directory.
#
OPENOCD_PROC_FILE ?= stm32f4discovery.cfg
+#OPENOCD_PROC_FILE ?= st_nucleo_f4.cfg
# MCU selection parameters
#
@@ -61,7 +62,7 @@ SIZE=arm-none-eabi-size
GDB=arm-none-eabi-gdb
OPENOCD=openocd
-CFLAGS = -ggdb -O2 -Wall -Wextra -Warray-bounds
+CFLAGS = -ggdb -O1 -Wall -Wextra -Warray-bounds
CFLAGS += -mcpu=cortex-m4 -mthumb -mlittle-endian -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += $(STDPERIPH_SETTINGS)
diff --git a/src/cc20rng/Makefile b/src/cc20rng/Makefile
new file mode 100644
index 0000000..2873505
--- /dev/null
+++ b/src/cc20rng/Makefile
@@ -0,0 +1,56 @@
+# put your *.o targets here, make should handle the rest!
+SRCS = main.c stm_init.c system_stm32f4xx.c stm32f4xx_it.c stm32f4xx_hal_msp.c cc20_prng.c
+
+# all the files will be generated with this name
+PROJ_NAME=cc20rng
+
+TOPLEVEL=../..
+include $(TOPLEVEL)/common.mk
+
+
+OBJS = $(SRCS:.c=.o)
+
+###################################################
+
+.PHONY: lib proj
+
+all: lib proj
+
+lib:
+ $(MAKE) -C $(STD_PERIPH_LIB) STDPERIPH_SETTINGS="$(STDPERIPH_SETTINGS)"
+
+
+proj: $(PROJ_NAME).elf
+
+$(PROJ_NAME).elf: $(SRCS)
+ $(CC) $(CFLAGS) $^ -o $@ -L$(STD_PERIPH_LIB) -lstmf4 -L$(LDSCRIPT_INC) -T$(MCU_LINKSCRIPT) -g
+ $(OBJCOPY) -O ihex $(PROJ_NAME).elf $(PROJ_NAME).hex
+ $(OBJCOPY) -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
+ $(OBJDUMP) -St $(PROJ_NAME).elf >$(PROJ_NAME).lst
+ $(SIZE) $(PROJ_NAME).elf
+
+clean:
+ find ./ -name '*~' | xargs rm -f
+ rm -f *.o
+ rm -f $(PROJ_NAME).elf
+ rm -f $(PROJ_NAME).hex
+ rm -f $(PROJ_NAME).bin
+ rm -f $(PROJ_NAME).map
+ rm -f $(PROJ_NAME).lst
+
+really-clean: clean
+ $(MAKE) -C $(STD_PERIPH_LIB) clean
+
+debug:
+ $(GDB) -ex "target remote localhost:3333" \
+ -ex "set remote hardware-breakpoint-limit 6" \
+ -ex "set remote hardware-watchpoint-limit 4" $(PROJ_NAME).elf
+
+flash-target:
+ $(OPENOCD) -f $(OPENOCD_BOARD_DIR)/$(OPENOCD_PROC_FILE) \
+ -c "program $(PROJ_NAME).elf verify" -c "reset"
+
+# test program not using cross compiling
+test: clean test.c cc20_prng.c
+ cc -DCHACHA20_PRNG_DEBUG -O2 -g -o test test.c cc20_prng.c
+ ./test
diff --git a/src/cc20rng/cc20_prng.c b/src/cc20rng/cc20_prng.c
new file mode 100644
index 0000000..3d52fc6
--- /dev/null
+++ b/src/cc20rng/cc20_prng.c
@@ -0,0 +1,219 @@
+/*
+ * Simple implementation of chacha20 used as a CSPRNG.
+ *
+ * Copyright (c) 2016 NORDUnet A/S
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the NORDUnet nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cc20_prng.h"
+
+/* "expand 32-byte k" */
+#define CHACHA20_CONSTANT0 0x61707865
+#define CHACHA20_CONSTANT1 0x3320646e
+#define CHACHA20_CONSTANT2 0x79622d32
+#define CHACHA20_CONSTANT3 0x6b206574
+
+#ifdef CHACHA20_PRNG_DEBUG
+void _dump(struct cc20_state *cc, char *str);
+#endif
+
+inline uint32_t rotl32 (uint32_t x, uint32_t n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+
+inline void _qr(struct cc20_state *cc, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+ cc->i[a] += cc->i[b];
+ cc->i[d] ^= cc->i[a];
+ cc->i[d] = rotl32(cc->i[d], 16);
+
+ cc->i[c] += cc->i[d];
+ cc->i[b] ^= cc->i[c];
+ cc->i[b] = rotl32(cc->i[b], 12);
+
+ cc->i[a] += cc->i[b];
+ cc->i[d] ^= cc->i[a];
+ cc->i[d] = rotl32(cc->i[d], 8);
+
+ cc->i[c] += cc->i[d];
+ cc->i[b] ^= cc->i[c];
+ cc->i[b] = rotl32(cc->i[b], 7);
+}
+
+void chacha20_prng_reseed(struct cc20_state *cc, uint32_t *entropy)
+{
+ uint32_t i = 256 / 8 / 4;
+ while (i--) {
+ cc->i[i] = entropy[i];
+ }
+}
+
+void chacha20_prng_block(struct cc20_state *cc, uint32_t block_counter, struct cc20_state *out)
+{
+ uint32_t i;
+
+ out->i[0] = CHACHA20_CONSTANT0;
+ out->i[1] = CHACHA20_CONSTANT1;
+ out->i[2] = CHACHA20_CONSTANT2;
+ out->i[3] = CHACHA20_CONSTANT3;
+
+ cc->i[12] = block_counter;
+
+ for (i = 4; i < CHACHA20_NUM_WORDS; i++) {
+ out->i[i] = cc->i[i];
+ }
+
+ for (i = 10; i; i--) {
+ _qr(out, 0, 4, 8,12);
+ _qr(out, 1, 5, 9,13);
+ _qr(out, 2, 6,10,14);
+ _qr(out, 3, 7,11,15);
+ _qr(out, 0, 5,10,15);
+ _qr(out, 1, 6,11,12);
+ _qr(out, 2, 7, 8,13);
+ _qr(out, 3, 4, 9,14);
+ }
+
+ for (i = 0; i < CHACHA20_NUM_WORDS; i++) {
+ out->i[i] += cc->i[i];
+ }
+}
+
+int chacha20_prng_self_test1()
+{
+ /* Test vector from RFC7539, section 2.3.2.
+ * https://tools.ietf.org/html/rfc7539#section-2.3.2
+ */
+ struct cc20_state test = {
+ {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
+ 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c,
+ 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c,
+ 0x00000001, 0x09000000, 0x4a000000, 0x00000000,
+ }};
+ struct cc20_state expected = {
+ {0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3,
+ 0xc7f4d1c7, 0x0368c033, 0x9aaa2204, 0x4e6cd4c3,
+ 0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9,
+ 0xd19c12b5, 0xb94e16de, 0xe883d0cb, 0x4e3c50a2,
+ }};
+ uint32_t i;
+ struct cc20_state out;
+
+#ifdef CHACHA20_PRNG_DEBUG
+ _dump(&test, "Test vector from RFC7539, section 2.3.2. Input:");
+#endif
+
+ chacha20_prng_block(&test, 1, &out);
+#ifdef CHACHA20_PRNG_DEBUG
+ _dump(&out, "Test vector from RFC7539, section 2.3.2. Output:");
+#endif
+
+ for (i = 0; i < CHACHA20_NUM_WORDS; i++) {
+ if (out.i[i] != expected.i[i]) return 0;
+ }
+
+ return 1;
+}
+
+int chacha20_prng_self_test2()
+{
+ /* Two-block test vector from RFC7539, section 2.4.2.
+ * https://tools.ietf.org/html/rfc7539#section-2.4.2
+ */
+ struct cc20_state test = {
+ {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
+ 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c,
+ 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c,
+ 0x00000001, 0x00000000, 0x4a000000, 0x00000000,
+ }};
+ struct cc20_state expected1 = {
+ {0xf3514f22, 0xe1d91b40, 0x6f27de2f, 0xed1d63b8,
+ 0x821f138c, 0xe2062c3d, 0xecca4f7e, 0x78cff39e,
+ 0xa30a3b8a, 0x920a6072, 0xcd7479b5, 0x34932bed,
+ 0x40ba4c79, 0xcd343ec6, 0x4c2c21ea, 0xb7417df0,
+ }};
+ struct cc20_state expected2 = {
+ {0x9f74a669, 0x410f633f, 0x28feca22, 0x7ec44dec,
+ 0x6d34d426, 0x738cb970, 0x3ac5e9f3, 0x45590cc4,
+ 0xda6e8b39, 0x892c831a, 0xcdea67c1, 0x2b7e1d90,
+ 0x037463f3, 0xa11a2073, 0xe8bcfb88, 0xedc49139,
+ }};
+ struct cc20_state out;
+ uint32_t i;
+
+#ifdef CHACHA20_PRNG_DEBUG
+ _dump(&test, "Test vector from RFC7539, section 2.4.2. Input:");
+#endif
+
+ chacha20_prng_block(&test, 1, &out);
+#ifdef CHACHA20_PRNG_DEBUG
+ _dump(&out, "First block");
+#endif
+ for (i = 0; i < CHACHA20_NUM_WORDS; i++) {
+ if (out.i[i] != expected1.i[i]) return 0;
+ }
+
+ chacha20_prng_block(&test, 2, &out);
+#ifdef CHACHA20_PRNG_DEBUG
+ _dump(&out, "Second block");
+#endif
+ for (i = 0; i < CHACHA20_NUM_WORDS; i++) {
+ if (out.i[i] != expected2.i[i]) return 0;
+ }
+
+ return 1;
+}
+
+#ifdef CHACHA20_PRNG_DEBUG
+#include <stdio.h>
+void _dump(struct cc20_state *cc, char *str)
+{
+ uint32_t i;
+
+ printf("%s\n", str);
+
+ for (i = 0; i < 4; i++) {
+ printf("%02i %08x %08x %08x %08x\n", i * 4, cc->i[i * 4 + 0],
+ cc->i[i * 4 + 1], cc->i[i * 4 + 2], cc->i[i * 4 + 3]);
+ }
+ printf("\n");
+}
+#endif
+
+/* Test vector from RFC, used as simple power-on self-test of ability to compute
+ * a block correctly.
+ */
+int chacha20_prng_self_test()
+{
+ return \
+ chacha20_prng_self_test1() && \
+ chacha20_prng_self_test2();
+}
diff --git a/src/cc20rng/cc20_prng.h b/src/cc20rng/cc20_prng.h
new file mode 100644
index 0000000..6940f53
--- /dev/null
+++ b/src/cc20rng/cc20_prng.h
@@ -0,0 +1,18 @@
+#ifndef __STM32_CHACHA20_H
+#define __STM32_CHACHA20_H
+
+#include <stdint.h>
+
+#define CHACHA20_MAX_BLOCK_COUNTER 0xffffffff
+#define CHACHA20_NUM_WORDS 16
+#define CHACHA20_BLOCK_SIZE (CHACHA20_NUM_WORDS * 4)
+
+struct cc20_state {
+ uint32_t i[CHACHA20_NUM_WORDS];
+};
+
+extern void chacha20_prng_reseed(struct cc20_state *cc, uint32_t *entropy);
+extern void chacha20_prng_block(struct cc20_state *cc, uint32_t block_counter, struct cc20_state *out);
+extern int chacha20_prng_self_test();
+
+#endif /* __STM32_CHACHA20_H */
diff --git a/src/cc20rng/main.c b/src/cc20rng/main.c
new file mode 100644
index 0000000..2c2650c
--- /dev/null
+++ b/src/cc20rng/main.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2014, 2015, 2016 NORDUnet A/S
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the NORDUnet nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include "main.h"
+#include "stm_init.h"
+#include "cc20_prng.h"
+
+#define UART_RANDOM_BYTES_PER_CHUNK 8
+#define RESEED_BLOCKS CHACHA20_MAX_BLOCK_COUNTER
+
+extern DMA_HandleTypeDef hdma_tim;
+
+UART_HandleTypeDef *huart;
+__IO ITStatus UartReady = RESET;
+
+static union {
+ uint8_t rnd[257]; /* 256 bytes + 1 for use in the POST */
+ uint32_t rnd32[64];
+} buf;
+
+/* First DMA value (DMA_counters[0]) is unreliable, leftover in DMA FIFO perhaps? */
+#define FIRST_DMA_IDX_USED 3
+
+/*
+ * Number of counters used to produce 8 bits of entropy is:
+ * 8 * 4 - four flanks are used to produce two (hopefully) uncorrelated bits (a and b)
+ * * 2 - von Neumann will on average discard 1/2 of the bits 'a' and 'b'
+ */
+#define DMA_COUNTERS_NUM ((UART_RANDOM_BYTES_PER_CHUNK * 8 * 4 * 2) + FIRST_DMA_IDX_USED + 1)
+struct DMA_params {
+ volatile uint32_t buf0[DMA_COUNTERS_NUM];
+ volatile uint32_t buf1[DMA_COUNTERS_NUM];
+ volatile uint32_t write_buf;
+};
+
+static struct DMA_params DMA = {
+ {},
+ {},
+ 0,
+};
+
+
+/* The main work horse functions */
+void get_entropy32(uint32_t num_bytes, uint32_t buf_idx);
+/* Various support functions */
+inline uint32_t get_one_bit(void) __attribute__((__always_inline__));
+volatile uint32_t *restart_DMA(void);
+inline volatile uint32_t *get_DMA_read_buf(void);
+inline uint32_t safe_get_counter(volatile uint32_t *dmabuf, const uint32_t dmabuf_idx);
+void check_uart_rx(UART_HandleTypeDef *this);
+void Error_Handler(void);
+void cc_reseed(struct cc20_state *cc);
+
+
+int
+main()
+{
+ uint32_t i, timeout, block_counter = 0;
+ struct cc20_state cc, out;
+ HAL_StatusTypeDef res;
+
+ /* Initialize buffers */
+ memset(buf.rnd, 0, sizeof(buf.rnd));
+ for (i = 0; i < DMA_COUNTERS_NUM; i++) {
+ DMA.buf0[i] = 0xffff0000 + i;
+ DMA.buf1[i] = 0xffff0100 + i;
+ }
+
+ stm_init((uint32_t *) &DMA.buf0, DMA_COUNTERS_NUM);
+
+ if (! chacha20_prng_self_test()) {
+ Error_Handler();
+ }
+
+ /* Ensure there is actual Timer IC counters in both DMA buffers. */
+ restart_DMA();
+ restart_DMA();
+
+ huart = &huart1;
+
+ /* Toggle GREEN LED to show we've initialized */
+ {
+ for (i = 0; i < 10; i++) {
+ HAL_GPIO_TogglePin(LED_PORT, LED_GREEN);
+ HAL_Delay(125);
+ }
+ }
+
+ /* Generate initial block of random data directly into buf */
+ cc_reseed(&cc);
+ block_counter = RESEED_BLOCKS;
+ chacha20_prng_block(&cc, block_counter--, (struct cc20_state *) buf.rnd32);
+
+ /*
+ * Main loop
+ */
+ while (1) {
+ if (! (block_counter % 1000)) {
+ HAL_GPIO_TogglePin(LED_PORT, LED_YELLOW);
+ }
+
+ if (! block_counter) {
+ cc_reseed(&cc);
+ block_counter = RESEED_BLOCKS;
+ }
+
+ /* Send buf on UART (non blocking interrupt driven send). */
+ UartReady = RESET;
+ res = HAL_UART_Transmit_IT(huart, &buf.rnd[0], CHACHA20_BLOCK_SIZE);
+
+ /* Generate next block while this block is being transmitted */
+ chacha20_prng_block(&cc, block_counter--, &out);
+ /* Copying using a loop is faster than memcpy on STM32 */
+ for (i = 0; i < CHACHA20_NUM_WORDS; i++) {
+ buf.rnd32[i] = out.i[i];
+ }
+
+ if (res == HAL_OK) {
+ timeout = 0xffff;
+ while (UartReady != SET && timeout) { timeout--; }
+ }
+
+ if (UartReady != SET) {
+ /* Failed to send, turn on RED LED for one second */
+ HAL_GPIO_WritePin(LED_PORT, LED_RED, GPIO_PIN_SET);
+ HAL_Delay(1000);
+ HAL_GPIO_WritePin(LED_PORT, LED_RED, GPIO_PIN_RESET);
+ }
+
+ /* Check for UART change request */
+ check_uart_rx(&huart1);
+ check_uart_rx(&huart2);
+ }
+}
+
+
+/**
+ * @brief Reseed chacha20 state with hardware generated entropy.
+ * @param cc: ChaCha20 state
+ * @retval None
+ */
+void
+cc_reseed(struct cc20_state *cc)
+{
+ HAL_GPIO_WritePin(LED_PORT, LED_BLUE, GPIO_PIN_SET);
+
+ get_entropy32(CHACHA20_BLOCK_SIZE / 4, 0);
+ restart_DMA();
+ chacha20_prng_reseed(cc, (uint32_t *) &buf);
+
+ HAL_GPIO_WritePin(LED_PORT, LED_BLUE, GPIO_PIN_RESET);
+}
+
+/**
+ * @brief Collect `count' times 32 bits of entropy.
+ * @param count: Number of 32 bit words to collect.
+ * @param start: Start index value into buf.rnd32.
+ * @retval None
+ */
+inline void get_entropy32(uint32_t count, const uint32_t start)
+{
+ uint32_t i, bits, buf_idx;
+
+ buf_idx = start;
+
+ do {
+ bits = 0;
+ /* Get 32 bits of entropy.
+ */
+ for (i = 32; i; i--) {
+ bits <<= 1;
+ bits += get_one_bit();
+ }
+
+ /* Store the 32 bits in output buffer */
+ buf.rnd32[buf_idx++] = bits;
+ } while (--count);
+}
+
+/**
+ * @brief Return one bit of entropy.
+ * @param None
+ * @retval One bit, in the LSB of an uint32_t since this is a 32 bit MCU.
+ */
+inline uint32_t get_one_bit()
+{
+ register uint32_t a, b, temp;
+ /* Start at end of buffer so restart_DMA() is called. */
+ static uint32_t dmabuf_idx = DMA_COUNTERS_NUM - 1;
+ volatile uint32_t *dmabuf;
+
+ dmabuf = get_DMA_read_buf();
+
+ do {
+ if (dmabuf_idx > DMA_COUNTERS_NUM - 1 - 4) {
+ /* If there are less than four counters available in the dmabuf,
+ * we need to get a fresh DMA buffer first.
+ */
+ dmabuf = restart_DMA();
+ dmabuf_idx = FIRST_DMA_IDX_USED;
+ }
+
+ /* Get one bit from two subsequent counter values */
+ a = safe_get_counter(dmabuf, dmabuf_idx++) & 1;
+ temp = safe_get_counter(dmabuf, dmabuf_idx++) & 1;
+ a ^= temp;
+
+ /* Get another bit from two other counter values. Getting
+ * two bits from two unrelated [1] pairs of counters is
+ * supposed to help against phase correlations between the
+ * frequency of the noise and the MCU sampling rate.
+ *
+ * [1] This is how it is done in the ARRGH board, although
+ * since this is a faster MCU and DMA is used the two
+ * pairs are more likely to still be related since they
+ * are more likely to be directly subsequent diode
+ * breakdowns. Have to evaluate if this is enough.
+ */
+ b = safe_get_counter(dmabuf, dmabuf_idx++) & 1;
+ temp = safe_get_counter(dmabuf, dmabuf_idx++) & 1;
+ b ^= temp;
+
+ /* Do von Neumann extraction of a and b to eliminate bias
+ * (only eliminates bias if a and b are uncorrelated)
+ */
+ } while (a == b);
+
+ return a;
+}
+
+/**
+ * @brief Return a pointer to the DMA.buf NOT currently being written to
+ * @param None
+ * @retval Pointer to buffer currently being read from.
+ */
+inline volatile uint32_t *get_DMA_read_buf(void)
+{
+ return DMA.write_buf ? DMA.buf0 : DMA.buf1;
+}
+
+/**
+ * @brief Return a pointer to the DMA.buf currently being written to
+ * @param None
+ * @retval Pointer to buffer currently being written to.
+ */
+inline volatile uint32_t *get_DMA_write_buf(void)
+{
+ return DMA.write_buf ? DMA.buf1 : DMA.buf0;
+}
+
+/**
+ * @brief Initiate DMA collection of another buffer of Timer IC values.
+ * @param None
+ * @retval Pointer to buffer full of Timer IC values ready to be consumed.
+ */
+volatile uint32_t *restart_DMA(void)
+{
+ /* Wait for transfer complete flag to become SET. Trying to change the
+ * M0AR register while the DMA is running is a no-no.
+ */
+ while(__HAL_DMA_GET_FLAG(&hdma_tim, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_tim)) == RESET) { ; }
+
+ /* Switch buffer being written to */
+ DMA.write_buf ^= 1;
+ hdma_tim.Instance->M0AR = (uint32_t) get_DMA_write_buf();
+
+ /* Start at 0 to help manual inspection */
+ TIM2->CNT = 0;
+
+ /* Clear the transfer complete flag before re-enabling DMA */
+ __HAL_DMA_CLEAR_FLAG(&hdma_tim, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_tim));
+ __HAL_DMA_ENABLE(&hdma_tim);
+
+ return get_DMA_read_buf();
+}
+
+/**
+ * @brief Get one counter value, guaranteed to not have been used before.
+ * @param dmabuf: Pointer to the current DMA read buffer.
+ * @param dmabuf_idx: Word index into `dmabuf'.
+ * @retval One Timer IC counter value.
+ */
+inline uint32_t safe_get_counter(volatile uint32_t *dmabuf, const uint32_t dmabuf_idx) {
+ register uint32_t a;
+ /* Prevent re-use of values. DMA stored values are <= 0xffff. */
+ do {
+ a = dmabuf[dmabuf_idx];
+ } while (a > 0xffff);
+ dmabuf[dmabuf_idx] = 0xffff0000;
+ return a;
+}
+
+/* UART transmit complete callback */
+void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UH)
+{
+ if ((UH->Instance == USART1 && huart->Instance == USART1) ||
+ (UH->Instance == USART2 && huart->Instance == USART2)) {
+ /* Signal UART transmit complete to the code in the main loop. */
+ UartReady = SET;
+ }
+}
+
+/*
+ * If a newline is received on UART1 or UART2, redirect output to that UART.
+ */
+void check_uart_rx(UART_HandleTypeDef *this) {
+ uint8_t rx = 0;
+ if (HAL_UART_Receive(this, &rx, 1, 0) == HAL_OK) {
+ if (rx == '\n') {
+ huart = this;
+ /* Signal UART transmit complete to the code in the main loop. */
+ UartReady = SET;
+ }
+ }
+}
+
+/**
+ * @brief This function is executed in case of error occurrence.
+ * @param None
+ * @retval None
+ */
+
+void Error_Handler(void)
+{
+ /* Turn on RED LED and then loop indefinitely */
+ HAL_GPIO_WritePin(LED_PORT, LED_RED, GPIO_PIN_SET);
+ while(1) { ; }
+}
diff --git a/src/cc20rng/main.h b/src/cc20rng/main.h
new file mode 100644
index 0000000..902ecf4
--- /dev/null
+++ b/src/cc20rng/main.h
@@ -0,0 +1,4 @@
+#ifndef __MAIN_H
+#define __MAIN_H
+
+#endif /* __MAIN_H */
diff --git a/src/cc20rng/stm32f4xx_hal_msp.c b/src/cc20rng/stm32f4xx_hal_msp.c
new file mode 100644
index 0000000..536a78c
--- /dev/null
+++ b/src/cc20rng/stm32f4xx_hal_msp.c
@@ -0,0 +1,113 @@
+#include "stm_init.h"
+#include "stm32f4xx_hal.h"
+
+static void Error_Handler(void);
+extern void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma);
+
+void HAL_TIM_IC_MspInit(TIM_HandleTypeDef* htim)
+{
+ if (htim->Instance == TIM2) {
+ /* Configure DMA input capturing.
+ *
+ * Amplified avalanche noise is present at pin PA1,
+ * which has Alternate Function TIM2_CH2.
+ *
+ * TIM2_CH2 is DMA1 stream 6, channel 3 according to Table 28
+ * (DMA1 request mapping) in the reference manual (RM0368).
+ */
+ __DMA1_CLK_ENABLE();
+ __TIM2_CLK_ENABLE();
+ __GPIOA_CLK_ENABLE();
+
+ hdma_tim.Instance = DMA1_Stream6;
+
+ hdma_tim.Init.Channel = DMA_CHANNEL_3;
+ hdma_tim.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hdma_tim.Init.Mode = DMA_NORMAL;
+ hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
+ hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+ hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
+ hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
+ hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
+
+ /* Link hdma_tim to hdma[2] (channel3) */
+ __HAL_LINKDMA(htim, hdma[TIM_DMA_ID_CC2], hdma_tim);
+
+ /* Initialize TIMx DMA handle */
+ if (HAL_DMA_Init(&hdma_tim) != HAL_OK) {
+ Error_Handler();
+ }
+ }
+}
+
+void HAL_UART_MspInit(UART_HandleTypeDef* huart)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ if (huart->Instance == USART1) {
+ /* Peripheral clock enable */
+ __USART1_CLK_ENABLE();
+
+ /**USART1 GPIO Configuration
+ PA9 ------> USART1_TX
+ PA10 ------> USART1_RX
+ */
+ GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
+ GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ /* NVIC for interrupt mode */
+ HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
+ HAL_NVIC_EnableIRQ(USART1_IRQn);
+ } else if (huart->Instance == USART2) {
+ /* Peripheral clock enable */
+ __USART2_CLK_ENABLE();
+ GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
+ GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ /* NVIC for interrupt mode */
+ HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
+ HAL_NVIC_EnableIRQ(USART2_IRQn);
+ }
+}
+
+void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
+{
+ if (huart->Instance == USART1) {
+ /* Peripheral clock disable */
+ __USART1_CLK_DISABLE();
+
+ /**USART1 GPIO Configuration
+ PA9 ------> USART1_TX
+ PA10 ------> USART1_RX
+ */
+ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);
+ } else if (huart->Instance == USART2) {
+ __USART2_CLK_DISABLE();
+ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2 | GPIO_PIN_3);
+ }
+}
+
+/**
+ * @brief This function is executed in case of error occurrence.
+ * @param None
+ * @retval None
+ */
+static void Error_Handler(void)
+{
+ /* Turn on RED LED and then loop indefinitely */
+ HAL_GPIO_WritePin(LED_PORT, LED_RED, GPIO_PIN_SET);
+
+ while (1) { ; }
+}
diff --git a/src/cc20rng/stm32f4xx_it.c b/src/cc20rng/stm32f4xx_it.c
new file mode 100644
index 0000000..d60a229
--- /dev/null
+++ b/src/cc20rng/stm32f4xx_it.c
@@ -0,0 +1,208 @@
+/**
+ ******************************************************************************
+ * @file GPIO/GPIO_IOToggle/Src/stm32f4xx_it.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief Main Interrupt Service Routines.
+ * This file provides template for all exceptions handler and
+ * peripherals interrupt service routine.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx_it.h"
+#include "stm_init.h"
+
+/** @addtogroup STM32F4xx_HAL_Examples
+ * @{
+ */
+
+/** @addtogroup GPIO_IOToggle
+ * @{
+ */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+
+/******************************************************************************/
+/* Cortex-M4 Processor Exceptions Handlers */
+/******************************************************************************/
+
+/**
+ * @brief This function handles NMI exception.
+ * @param None
+ * @retval None
+ */
+void NMI_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles Hard Fault exception.
+ * @param None
+ * @retval None
+ */
+void HardFault_Handler(void)
+{
+ /* Go to infinite loop when Hard Fault exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles Memory Manage exception.
+ * @param None
+ * @retval None
+ */
+void MemManage_Handler(void)
+{
+ /* Go to infinite loop when Memory Manage exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles Bus Fault exception.
+ * @param None
+ * @retval None
+ */
+void BusFault_Handler(void)
+{
+ /* Go to infinite loop when Bus Fault exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles Usage Fault exception.
+ * @param None
+ * @retval None
+ */
+void UsageFault_Handler(void)
+{
+ /* Go to infinite loop when Usage Fault exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles SVCall exception.
+ * @param None
+ * @retval None
+ */
+void SVC_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles Debug Monitor exception.
+ * @param None
+ * @retval None
+ */
+void DebugMon_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles PendSVC exception.
+ * @param None
+ * @retval None
+ */
+void PendSV_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles SysTick Handler.
+ * @param None
+ * @retval None
+ */
+void SysTick_Handler(void)
+{
+ HAL_IncTick();
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripherals Interrupt Handlers */
+/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
+/* available peripheral interrupt handler's name please refer to the startup */
+/* file (startup_stm32f4xx.s). */
+/******************************************************************************/
+
+/**
+ * @brief This function handles UART interrupt request.
+ * @param None
+ * @retval None
+ * @Note HAL_UART_IRQHandler will call HAL_UART_TxCpltCallback in main.c.
+ */
+void USART1_IRQHandler(void)
+{
+ HAL_UART_IRQHandler(&huart1);
+}
+
+/**
+ * @brief This function handles UART interrupt request.
+ * @param None
+ * @retval None
+ * @Note HAL_UART_IRQHandler will call HAL_UART_TxCpltCallback in main.c.
+ */
+void USART2_IRQHandler(void)
+{
+ HAL_UART_IRQHandler(&huart2);
+}
+
+/**
+ * @brief This function handles DMA1 Stream 6 interrupt request.
+ * @param None
+ * @retval None
+ */
+void DMA1_Stream6_IRQHandler(void)
+{
+ HAL_DMA_IRQHandler(&hdma_tim);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/cc20rng/stm32f4xx_it.h b/src/cc20rng/stm32f4xx_it.h
new file mode 100644
index 0000000..04c5a36
--- /dev/null
+++ b/src/cc20rng/stm32f4xx_it.h
@@ -0,0 +1,70 @@
+/**
+ ******************************************************************************
+ * @file GPIO/GPIO_IOToggle/Inc/stm32f4xx_it.h
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief This file contains the headers of the interrupt handlers.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_IT_H
+#define __STM32F4xx_IT_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+
+void NMI_Handler(void);
+void HardFault_Handler(void);
+void MemManage_Handler(void);
+void BusFault_Handler(void);
+void UsageFault_Handler(void);
+void SVC_Handler(void);
+void DebugMon_Handler(void);
+void PendSV_Handler(void);
+void SysTick_Handler(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F4xx_IT_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/cc20rng/stm_init.c b/src/cc20rng/stm_init.c
new file mode 100644
index 0000000..548f57b
--- /dev/null
+++ b/src/cc20rng/stm_init.c
@@ -0,0 +1,290 @@
+/**
+ ******************************************************************************
+ * @file GPIO/GPIO_IOToggle/Src/main.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief This example describes how to configure and use GPIOs through
+ * the STM32F4xx HAL API.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm_init.h"
+
+/** @addtogroup STM32F4xx_HAL_Examples
+ * @{
+ */
+
+/** @addtogroup GPIO_IOToggle
+ * @{
+ */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+
+#define UART1_BAUD_RATE 921600 /* FTDI/USB */
+#define UART2_BAUD_RATE 115200 /* R-Pi GPIO */
+
+
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+
+static GPIO_InitTypeDef GPIO_InitStruct;
+TIM_HandleTypeDef htim2;
+UART_HandleTypeDef huart1;
+UART_HandleTypeDef huart2;
+DMA_HandleTypeDef hdma_tim;
+
+/* Private function prototypes -----------------------------------------------*/
+static void SystemClock_Config(void);
+static void MX_GPIO_Init(void);
+static void MX_TIM2_Init(uint32_t *counters_buf, uint16_t counters);
+static void MX_USART1_UART_Init(void);
+static void MX_USART2_UART_Init(void);
+/* Private functions ---------------------------------------------------------*/
+
+extern void Error_Handler(void);
+
+
+/**
+ * @brief Main program
+ * @param None
+ * @retval None
+ */
+void stm_init(uint32_t *buf0, uint16_t counters)
+{
+ /* Generic STM32 initialization.
+
+ To proceed, 3 steps are required: */
+
+ /* STM32F4xx HAL library initialization:
+ - Configure the Flash prefetch, instruction and Data caches
+ - Configure the Systick to generate an interrupt each 1 msec
+ - Set NVIC Group Priority to 4
+ - Global MSP (MCU Support Package) initialization
+ */
+ HAL_Init();
+
+ /* Configure the system clock */
+ SystemClock_Config();
+
+ /* System interrupt init*/
+ /* Sets the priority grouping field */
+ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
+ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
+
+ /* Initialize all configured peripherals */
+ MX_GPIO_Init();
+ MX_TIM2_Init(buf0, counters);
+ MX_USART1_UART_Init();
+ MX_USART2_UART_Init();
+}
+
+
+/**
+ * @brief System Clock Configuration
+ * The system Clock is configured as follow :
+ * System Clock source = PLL (HSE)
+ * SYSCLK(Hz) = 42000000
+ * HCLK(Hz) = 42000000
+ * AHB Prescaler = 1
+ * APB1 Prescaler = 1
+ * APB2 Prescaler = 1
+ * HSI Frequency(Hz) = 16000000
+ * PLL_M = 8
+ * PLL_N = 336
+ * PLL_P = 8
+ * PLL_Q = 7 (unused)
+ * VDD(V) = 3.3
+ * Main regulator output voltage = Scale2 mode
+ * Flash Latency(WS) = 1
+ * @param None
+ * @retval None
+ */
+static void SystemClock_Config(void)
+{
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+
+ /* Enable Power Control clock */
+ __PWR_CLK_ENABLE();
+
+ /* The voltage scaling allows optimizing the power consumption when the device is
+ clocked below the maximum system frequency, to update the voltage scaling value
+ regarding system frequency refer to product datasheet. */
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
+
+ /* Enable HSE Oscillator and activate PLL with HSE as source.
+ *
+ * With 8 MHz HSE oscillator, M=/8, N=*336, P=/8 gives 42 MHz SYSCLK.
+ * Divider Q is unused in this configuration.
+ */
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLM = 8;
+ RCC_OscInitStruct.PLL.PLLN = 336;
+ RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV8;
+ RCC_OscInitStruct.PLL.PLLQ = 7;
+
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ Error_Handler();
+ }
+
+ /* Select PLL as system clock source */
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; /* AHB prescaler */
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; /* APB1 prescaler /1 gives 42 MHz APB1 */
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; /* APB2 prescaler /1 gives 42 MHz APB2 */
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
+ Error_Handler();
+ }
+
+}
+
+
+/** Configure pins as
+
+ PB12 ------> GREEN LED
+ PB13 ------> YELLOW LED
+ PB14 ------> GREEN lED
+ PB15 ------> BLUE LED
+ PA1 ------> TIM2_CH2 (Avalanche noise)
+*/
+void MX_GPIO_Init(void)
+{
+ /* GPIO Ports Clock Enable */
+ __GPIOA_CLK_ENABLE();
+ __GPIOB_CLK_ENABLE();
+ __GPIOC_CLK_ENABLE();
+
+ /*Configure LED GPIO pins PB12==red, PB13==yellow, PB14==green, PB15==blue */
+ GPIO_InitStruct.Pin = LED_RED | LED_YELLOW | LED_GREEN | LED_BLUE;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
+
+ /* Configure PA1 (TIM2_Channel2) (Avalanche noise trigger) */
+ GPIO_InitStruct.Pin = GPIO_PIN_1;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+}
+
+/* TIM2 init function.
+ * TIM2 is used in capture mode, triggered off the avalanche noise pin PA1.
+ */
+void MX_TIM2_Init(uint32_t *counters_buf, uint16_t counters)
+{
+ TIM_IC_InitTypeDef sICConfig;
+
+ __DMA1_CLK_ENABLE();
+ __TIM2_CLK_ENABLE();
+ __GPIOA_CLK_ENABLE();
+
+ htim2.Instance = TIM2;
+ htim2.Init.Prescaler = 0;
+ htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
+ htim2.Init.Period = 0xffff;
+ htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ htim2.Init.RepetitionCounter = 0;
+
+ /* Configure the Input Capture of channel 2.
+ * Trigger on rising edge. ICFilter = 0 means trigger on every event.
+ */
+ sICConfig.ICPolarity = TIM_ICPOLARITY_RISING;
+ sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
+ sICConfig.ICPrescaler = TIM_ICPSC_DIV1;
+ sICConfig.ICFilter = 0; /* If set - Ignore additional state changes for a short while */
+
+ if (HAL_TIM_IC_Init(&htim2) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+
+ if (HAL_TIM_IC_ConfigChannel(&htim2, &sICConfig, TIM_CHANNEL_2) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+
+ /* Start the TIM input capture operation */
+ if (HAL_TIM_IC_Start_DMA(&htim2, TIM_CHANNEL_2, counters_buf, counters) != HAL_OK) {
+ /* Starting Error */
+ Error_Handler();
+ }
+}
+
+
+/* USART1 init function
+ *
+ * USART1 uses PA9 and PA10.
+ */
+void MX_USART1_UART_Init(void)
+{
+ huart1.Instance = USART1;
+ huart1.Init.BaudRate = UART1_BAUD_RATE;
+ huart1.Init.WordLength = UART_WORDLENGTH_8B;
+ huart1.Init.StopBits = UART_STOPBITS_1;
+ huart1.Init.Parity = UART_PARITY_NONE;
+ huart1.Init.Mode = UART_MODE_TX_RX;
+ huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ huart1.Init.OverSampling = UART_OVERSAMPLING_16;
+
+ if (HAL_UART_Init(&huart1) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+}
+
+/* USART2 init function */
+void MX_USART2_UART_Init(void)
+{
+ huart2.Instance = USART2;
+ huart2.Init.BaudRate = UART2_BAUD_RATE;
+ huart2.Init.WordLength = UART_WORDLENGTH_8B;
+ huart2.Init.StopBits = UART_STOPBITS_1;
+ huart2.Init.Parity = UART_PARITY_NONE;
+ huart2.Init.Mode = UART_MODE_TX_RX;
+ huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ huart2.Init.OverSampling = UART_OVERSAMPLING_16;
+
+ if (HAL_UART_Init(&huart2) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/cc20rng/stm_init.h b/src/cc20rng/stm_init.h
new file mode 100644
index 0000000..d58c254
--- /dev/null
+++ b/src/cc20rng/stm_init.h
@@ -0,0 +1,18 @@
+#ifndef __STM_INIT_H
+#define __STM_INIT_H
+
+#include "stm32f4xx_hal.h"
+
+#define LED_PORT GPIOB
+#define LED_RED GPIO_PIN_12
+#define LED_YELLOW GPIO_PIN_13
+#define LED_GREEN GPIO_PIN_14
+#define LED_BLUE GPIO_PIN_15
+
+extern UART_HandleTypeDef huart1;
+extern UART_HandleTypeDef huart2;
+extern DMA_HandleTypeDef hdma_tim;
+
+extern void stm_init(uint32_t *buf0, uint16_t counters);
+
+#endif /* __STM_INIT_H */
diff --git a/src/cc20rng/system_stm32f4xx.c b/src/cc20rng/system_stm32f4xx.c
new file mode 100644
index 0000000..35f79ba
--- /dev/null
+++ b/src/cc20rng/system_stm32f4xx.c
@@ -0,0 +1,270 @@
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 26-February-2014
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ *
+ * This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f4xx_hal.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+ /* This variable is updated in three ways:
+ 1) by calling CMSIS function SystemCoreClockUpdate()
+ 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+ 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+ Note: If you use this function to configure the system clock; then there
+ is no need to call the 2 first functions listed above, since SystemCoreClock
+ variable is updated automatically.
+ */
+ uint32_t SystemCoreClock = 16000000;
+ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the FPU setting, vector table location and External memory
+ * configuration.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
+ * depends on the application requirements), user has to ensure that HSE_VALUE
+ * is same as the real frequency of the crystal used. Otherwise, this function
+ * may have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/cc20rng/test.c b/src/cc20rng/test.c
new file mode 100644
index 0000000..e2bdae0
--- /dev/null
+++ b/src/cc20rng/test.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#include "cc20_prng.h"
+
+int main()
+{
+ uint32_t i;
+ i = chacha20_prng_self_test();
+ printf("test result: %i (%s)\n", i, (i == 0)?"FAIL":"SUCCESS");
+}