EP_ROUND_RAW_DATA_INPUTS
[gnuk/neug.git] / src / random.c
index 39eb1ad..a1786f2 100644 (file)
@@ -12,7 +12,7 @@
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
- * Gnuk is distributed in the hope that it will be useful, but WITHOUT
+ * NeuG is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  * License for more details.
 
 #include "ch.h"
 #include "hal.h"
+#include "sys.h"
 #include "neug.h"
 #include "adc.h"
+#include "sha256.h"
 
 Thread *rng_thread;
 #define ADC_DATA_AVAILABLE ((eventmask_t)1)
 
-#include "sha256.h"
+static uint32_t adc_buf[SHA256_BLOCK_SIZE/sizeof (uint32_t)];
 
 static sha256_context sha256_ctx_data;
 static uint32_t sha256_output[SHA256_DIGEST_SIZE/sizeof (uint32_t)];
 
 /*
- * We did an experiment of measuring entropy of ADC output with MUST.
- * The entropy of a byte by raw sampling of LSBs has more than 6.0 bit/byte.
- *
- * More tests will be required, but for now we assume min-entropy >= 5.0.
- * 
- * To be a full entropy source, the requirement is to have N samples for
- * output of 256-bit, where:
+ * To be a full entropy source, the requirement is to have N samples
+ * for output of 256-bit, where:
  *
  *      N = (256 * 2) / <min-entropy of a sample>
  *
- * For min-entropy = 5.0, N should be more than 103.
+ * For example, N should be more than 103 for min-entropy = 5.0.
  *
- * On the other hand, in the section 6.2 "Full Entropy Source Requirements",
- * it says:
+ * On the other hand, in the section 6.2 "Full Entropy Source
+ * Requirements", it says:
  *
  *     At least twice the block size of the underlying cryptographic
  *     primitive shall be provided as input to the conditioning
  *     function to produce full entropy output.
  *
- * For us, cryptographic primitive is SHA-256 and its blocksize is 512-bit
- * (64-byte), N >= 128.
+ * For us, cryptographic primitive is SHA-256 and its blocksize is
+ * 512-bit (64-byte), thus, N >= 128.
  *
- * We chose N=139, since we love prime number, and we have "additional bits"
- * of 32-byte for last block (feedback from previous output of SHA-256).
+ * We chose N=140.  Note that we have "additional bits" of 16-byte for
+ * last block (feedback from previous output of SHA-256) to feed
+ * hash_df function of SHA-256, together with sample data of 140-byte.
  *
- * This corresponds to min-entropy >= 3.68.
+ * N=140 corresponds to min-entropy >= 3.68.
  *
  */
-#define NUM_NOISE_INPUTS 139
+#define NUM_NOISE_INPUTS 140
 
-#define EP_ROUND_0 0 /* initial-five-byte and 59*8-sample-input */
-#define EP_ROUND_1 1 /* 64*8-sample-input */
-#define EP_ROUND_2 2 /* 16*8-sample-input */
-#define EP_ROUND_RAW_LSB  3 /* 64*8-sample-input */
-#define EP_ROUND_RAW_DATA 4 /* 16-sample-input */
+#define EP_ROUND_0 0 /* initial-five-byte and 3-byte, then 56-byte-input */
+#define EP_ROUND_1 1 /* 64-byte-input */
+#define EP_ROUND_2 2 /* 17-byte-input */
+#define EP_ROUND_RAW      3 /* 32-byte-input */
+#define EP_ROUND_RAW_DATA 4 /* 32-byte-input */
 
-#define EP_ROUND_0_INPUTS 59
+#define EP_ROUND_0_INPUTS 56
 #define EP_ROUND_1_INPUTS 64
-#define EP_ROUND_2_INPUTS 16
-#define EP_ROUND_RAW_LSB_INPUTS 64
-#define EP_ROUND_RAW_DATA_INPUTS 2
+#define EP_ROUND_2_INPUTS 17
+#define EP_ROUND_RAW_INPUTS 32
+#define EP_ROUND_RAW_DATA_INPUTS 32
 
 static uint8_t ep_round;
 
@@ -91,132 +89,115 @@ static uint8_t ep_round;
  */
 static void ep_fill_initial_string (void)
 {
-  memset (adc_samp, 0, 5 * 8 * sizeof (uint16_t));
-  adc_samp[0] = 1;
-  adc_samp[3*8] = 1;
+  adc_buf[0] = 0x01000001; /* Regardless of endian */
+  adc_buf[1] = (CRC->DR & 0xffffff00);
 }
 
 static void ep_init (int mode)
 {
   chEvtClearFlags (ADC_DATA_AVAILABLE);
-  if (mode == NEUG_MODE_RAW_LSB)
+  if (mode == NEUG_MODE_RAW)
     {
-      ep_round = EP_ROUND_RAW_LSB;
-      adc_start_conversion (0, EP_ROUND_RAW_LSB_INPUTS*8/2);
+      ep_round = EP_ROUND_RAW;
+      adc_start_conversion (ADC_CRC32_MODE, adc_buf, EP_ROUND_RAW_INPUTS);
     }
   else if (mode == NEUG_MODE_RAW_DATA)
     {
       ep_round = EP_ROUND_RAW_DATA;
-      adc_start_conversion (0, EP_ROUND_RAW_DATA_INPUTS*8/2);
+      adc_start_conversion (ADC_SAMPLE_MODE, adc_buf, EP_ROUND_RAW_DATA_INPUTS);
     }
   else
     {
       ep_round = EP_ROUND_0;
       ep_fill_initial_string ();
-      /*
-       * We get two samples for a single transaction of DMA.
-       * We take LSBs of each samples.
-       * Thus, we need tansactions of: required_number_of_input_in_byte*8/2 
-       */
-      adc_start_conversion (5*8, EP_ROUND_0_INPUTS*8/2);
+      adc_start_conversion (ADC_CRC32_MODE,
+                           &adc_buf[2], EP_ROUND_0_INPUTS);
     }
 }
 
-static uint8_t ep_get_byte_from_samples (int i)
-{
-  return (  ((adc_samp[i*8+0] & 1) << 0) | ((adc_samp[i*8+1] & 1) << 1)
-         | ((adc_samp[i*8+2] & 1) << 2) | ((adc_samp[i*8+3] & 1) << 3)
-         | ((adc_samp[i*8+4] & 1) << 4) | ((adc_samp[i*8+5] & 1) << 5)
-         | ((adc_samp[i*8+6] & 1) << 6) | ((adc_samp[i*8+7] & 1) << 7));
-}
-
 static void noise_source_continuous_test (uint8_t noise);
 
-static void ep_fill_wbuf (int i, int flip, int mode)
+static void ep_fill_wbuf (int i, int flip, int test)
 {
-  if (mode == NEUG_MODE_RAW_DATA)
-    sha256_ctx_data.wbuf[i] = (adc_samp[i*2+1] << 16) | adc_samp[i*2];
-  else
+  uint32_t v = adc_buf[i];
+
+  if (test)
     {
       uint8_t b0, b1, b2, b3;
 
-      b0 = ep_get_byte_from_samples (i*4 + 0);
-      b1 = ep_get_byte_from_samples (i*4 + 1);
-      b2 = ep_get_byte_from_samples (i*4 + 2);
-      b3 = ep_get_byte_from_samples (i*4 + 3);
+      b3 = v >> 24;
+      b2 = v >> 16;
+      b1 = v >> 8;
+      b0 = v;
+
       noise_source_continuous_test (b0);
       noise_source_continuous_test (b1);
       noise_source_continuous_test (b2);
       noise_source_continuous_test (b3);
-
-      if (flip)
-       sha256_ctx_data.wbuf[i] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
-      else
-       sha256_ctx_data.wbuf[i] = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
     }
+
+  if (flip)
+    v = __builtin_bswap32 (v);
+
+  sha256_ctx_data.wbuf[i] = v;
 }
 
 /* Here assumes little endian architecture.  */
 static int ep_process (int mode)
 {
-  int i, n, flip;
+  int i, n;
 
-  if (ep_round == EP_ROUND_0 || ep_round == EP_ROUND_1)
+  if (ep_round == EP_ROUND_RAW)
     {
-      n = 64 / 4;
-      flip = 1;
+      for (i = 0; i < EP_ROUND_RAW_INPUTS / 4; i++)
+       ep_fill_wbuf (i, 0, 0);
+
+      ep_init (mode);
+      return EP_ROUND_RAW_INPUTS / 4;
     }
-  else if (ep_round == EP_ROUND_2)
+  else if (ep_round == EP_ROUND_RAW_DATA)
     {
-      n = EP_ROUND_2_INPUTS / 4;
-      flip = 0;
+      for (i = 0; i < EP_ROUND_RAW_DATA_INPUTS / 4; i++)
+       ep_fill_wbuf (i, 0, 0);
+
+      ep_init (mode);
+      return EP_ROUND_RAW_DATA_INPUTS / 4;
     }
-  else if (ep_round == EP_ROUND_RAW_LSB)
+
+  if (ep_round == EP_ROUND_0)
     {
-      n = EP_ROUND_RAW_LSB_INPUTS / 4;
-      flip = 0;
+      for (i = 0; i < 64 / 4; i++)
+       ep_fill_wbuf (i, 1, 1);
+
+      adc_start_conversion (ADC_CRC32_MODE, adc_buf, EP_ROUND_1_INPUTS);
+      sha256_start (&sha256_ctx_data);
+      sha256_process (&sha256_ctx_data);
+      ep_round++;
+      return 0;
     }
-  else /* ep_round == EP_ROUND_RAW_DATA */
+  else if (ep_round == EP_ROUND_1)
     {
-      n = EP_ROUND_RAW_DATA_INPUTS;
-      flip = 0;
-    }
+      for (i = 0; i < 64 / 4; i++)
+       ep_fill_wbuf (i, 1, 1);
 
-  for (i = 0; i < n; i++)
-    ep_fill_wbuf (i, flip, mode);
-
-  if (mode != NEUG_MODE_CONDITIONED)
-    {
-      ep_init (mode);
-      return n;
+      adc_start_conversion (ADC_CRC32_MODE, adc_buf, EP_ROUND_2_INPUTS);
+      sha256_process (&sha256_ctx_data);
+      ep_round++;
+      return 0;
     }
   else
     {
-      if (ep_round == EP_ROUND_0)
-       {
-         adc_start_conversion (0, EP_ROUND_1_INPUTS*8/2);
-         sha256_start (&sha256_ctx_data);
-         sha256_process (&sha256_ctx_data);
-         ep_round++;
-         return 0;
-       }
-      else if (ep_round == EP_ROUND_1)
-       {
-         adc_start_conversion (0, EP_ROUND_2_INPUTS*8/2);
-         sha256_process (&sha256_ctx_data);
-         ep_round++;
-         return 0;
-       }
-      else
-       {
-         n = SHA256_DIGEST_SIZE / 2;
-         ep_init (NEUG_MODE_CONDITIONED);
-         memcpy (((uint8_t *)sha256_ctx_data.wbuf)+EP_ROUND_2_INPUTS,
-                 sha256_output, n);
-         sha256_ctx_data.total[0] = 5 + NUM_NOISE_INPUTS + n;
-         sha256_finish (&sha256_ctx_data, (uint8_t *)sha256_output);
-         return SHA256_DIGEST_SIZE / sizeof (uint32_t);
-       }
+      for (i = 0; i < (EP_ROUND_2_INPUTS + 3) / 4; i++)
+       ep_fill_wbuf (i, 0, 1);
+
+      n = SHA256_DIGEST_SIZE / 2;
+      ep_init (NEUG_MODE_CONDITIONED); /* The three-byte is used here.  */
+      memcpy (((uint8_t *)sha256_ctx_data.wbuf)
+             + ((NUM_NOISE_INPUTS+5)%SHA256_BLOCK_SIZE),
+             sha256_output, n); /* Don't use the last three-byte.  */
+      sha256_ctx_data.total[0] = 5 + NUM_NOISE_INPUTS + n;
+      sha256_finish (&sha256_ctx_data, (uint8_t *)sha256_output);
+      return SHA256_DIGEST_SIZE / sizeof (uint32_t);
     }
 }
 
@@ -234,7 +215,10 @@ static const uint32_t *ep_output (int mode)
 #define ADAPTIVE_PROPORTION_4096   4
 
 uint8_t neug_err_state;
-uint16_t neug_err_count;
+uint16_t neug_err_cnt;
+uint16_t neug_err_cnt_rc;
+uint16_t neug_err_cnt_p64;
+uint16_t neug_err_cnt_p4k;
 
 static void noise_source_error_reset (void)
 {
@@ -244,7 +228,14 @@ static void noise_source_error_reset (void)
 static void noise_source_error (uint32_t err)
 {
   neug_err_state |= err;
-  neug_err_count++;
+  neug_err_cnt++;
+
+  if ((err & REPETITION_COUNT))
+    neug_err_cnt_rc++;
+  if ((err & ADAPTIVE_PROPORTION_64))
+    neug_err_cnt_p64++;
+  if ((err & ADAPTIVE_PROPORTION_4096))
+    neug_err_cnt_p4k++;
 
 #include "board.h"
 #if defined(BOARD_FST_01)
@@ -255,10 +246,19 @@ static void noise_source_error (uint32_t err)
 #endif
 }
 
+/*
+ * For health tests, we assumes that the device noise source has
+ * min-entropy >= 4.2.  Observing raw data stream (before CRC-32) has
+ * more than 4.2 bit/byte entropy.  When the data stream after CRC-32
+ * filter will be less than 4.2 bit/byte entropy, that must be
+ * something wrong.  Note that even we observe < 4.2, we still have
+ * some margin, since we use NUM_NOISE_INPUTS=140.
+ *
+ */
 
-/* Cuttoff = 10, when min-entropy = 3.7, W= 2^-30 */
-/* ceiling of (1+30/3.7) */
-#define REPITITION_COUNT_TEST_CUTOFF 10
+/* Cuttoff = 9, when min-entropy = 4.2, W= 2^-30 */
+/* ceiling of (1+30/4.2) */
+#define REPITITION_COUNT_TEST_CUTOFF 9
 
 static uint8_t rct_a;
 static uint8_t rct_b;
@@ -278,9 +278,9 @@ static void repetition_count_test (uint8_t sample)
     }
 }
 
-/* Cuttoff = 22, when min-entropy = 3.7, W= 2^-30 */
-/* With R, qbinom(1-2^-30,64,2^-3.7) */
-#define ADAPTIVE_PROPORTION_64_TEST_CUTOFF 22
+/* Cuttoff = 18, when min-entropy = 4.2, W= 2^-30 */
+/* With R, qbinom(1-2^-30,64,2^-4.2) */
+#define ADAPTIVE_PROPORTION_64_TEST_CUTOFF 18
 
 static uint8_t ap64t_a;
 static uint8_t ap64t_b;
@@ -306,9 +306,9 @@ static void adaptive_proportion_64_test (uint8_t sample)
     }
 }
 
-/* Cuttoff = 422, when min-entropy = 3.7, W= 2^-30 */
-/* With R, qbinom(1-2^-30,4096,2^-3.7) */
-#define ADAPTIVE_PROPORTION_4096_TEST_CUTOFF 422
+/* Cuttoff = 315, when min-entropy = 4.2, W= 2^-30 */
+/* With R, qbinom(1-2^-30,4096,2^-4.2) */
+#define ADAPTIVE_PROPORTION_4096_TEST_CUTOFF 315
 
 static uint8_t ap4096t_a;
 static uint16_t ap4096t_b;
@@ -390,42 +390,7 @@ static uint32_t rb_del (struct rng_rb *rb)
   return v;
 }
 
-static uint8_t neug_mode;
-
-/**
- * @brief  Random number generation from ADC sampling.
- * @param  RB: Pointer to ring buffer structure
- * @return -1 when failure, 0 otherwise.
- * @note   Called holding the mutex, with RB->full == 0.
- *         Keep generating until RB->full == 1.
- */
-static int rng_gen (struct rng_rb *rb)
-{
-  int n;
-  int mode = neug_mode;
-
-  while (1)
-    {
-      chEvtWaitOne (ADC_DATA_AVAILABLE); /* Got a series of ADC sampling.  */
-
-      if ((n = ep_process (mode)))
-       {
-         int i;
-         const uint32_t *vp;
-
-         vp = ep_output (mode);
-         for (i = 0; i < n; i++)
-           {
-             rb_add (rb, *vp);
-             vp++;
-             if (rb->full)
-               return 0;
-           }
-       }
-    }
-
-  return 0;                    /* success */
-}
+uint8_t neug_mode;
 
 /**
  * @brief Random number generation thread.
@@ -439,28 +404,44 @@ static msg_t rng (void *arg)
   /* Enable ADCs */
   adc_start ();
 
-  ep_init (0);
+  ep_init (NEUG_MODE_CONDITIONED);
 
   while (!chThdShouldTerminate ())
     {
-      chMtxLock (&rb->m);
-      while (rb->full)
-       chCondWait (&rb->space_available);
-      while (1)
+      int n;
+      int mode = neug_mode;
+
+      chEvtWaitOne (ADC_DATA_AVAILABLE); /* Get ADC sampling.  */
+
+      if ((n = ep_process (mode)))
        {
-         rng_gen (rb);
-         if (neug_err_state != 0)
+         int i;
+         const uint32_t *vp;
+
+         if (neug_err_state != 0
+             && neug_mode == NEUG_MODE_CONDITIONED)
            {
-             if (neug_mode == NEUG_MODE_CONDITIONED)
-               while (!rb->empty)
-                 (void)rb_del (rb);
+             /* Don't use the result and do it again.  */
              noise_source_error_reset ();
+             continue;
+           }
+
+         vp = ep_output (mode);
+
+         chMtxLock (&rb->m);
+         while (rb->full)
+           chCondWait (&rb->space_available);
+
+         for (i = 0; i < n; i++)
+           {
+             rb_add (rb, *vp++);
+             if (rb->full)
+               break;
            }
-         else
-           break;
+
+         chCondSignal (&rb->data_available);
+         chMtxUnlock ();
        }
-      chCondSignal (&rb->data_available);
-      chMtxUnlock ();
     }
 
   adc_stop ();
@@ -477,7 +458,19 @@ static WORKING_AREA(wa_rng, 256);
 void
 neug_init (uint32_t *buf, uint8_t size)
 {
+  const uint32_t *u = (const uint32_t *)unique_device_id ();
   struct rng_rb *rb = &the_ring_buffer;
+  int i;
+
+  RCC->AHBENR |= RCC_AHBENR_CRCEN;
+  CRC->CR = CRC_CR_RESET;
+
+  /*
+   * This initialization ensures that it generates different sequence
+   * even if all physical conditions are same.
+   */
+  for (i = 0; i < 3; i++)
+    CRC->DR = *u++;
 
   neug_mode = NEUG_MODE_CONDITIONED;
   rb_init (rb, buf, size);
@@ -564,11 +557,16 @@ void
 neug_mode_select (uint8_t mode)
 {
   neug_wait_full ();
+  while (rng_thread->p_state != THD_STATE_WTCOND)
+    chThdSleep (MS2ST (1));
+
   if (neug_mode != mode)
     ep_init (mode);
+
 #if defined(BOARD_FST_01)
   palClearPad (IOPORT1, 2);
 #endif
+
   neug_mode = mode;
   neug_flush ();
 }