cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

npcm7xx_rng-test.c (8239B)


      1/*
      2 * QTest testcase for the Nuvoton NPCM7xx Random Number Generator
      3 *
      4 * Copyright 2020 Google LLC
      5 *
      6 * This program is free software; you can redistribute it and/or modify it
      7 * under the terms of the GNU General Public License as published by the
      8 * Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful, but WITHOUT
     12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
     14 * for more details.
     15 */
     16
     17#include "qemu/osdep.h"
     18
     19#include <math.h>
     20
     21#include "libqtest-single.h"
     22#include "qemu/bitops.h"
     23#include "qemu-common.h"
     24
     25#define RNG_BASE_ADDR   0xf000b000
     26
     27/* Control and Status Register */
     28#define RNGCS   0x00
     29# define DVALID     BIT(1)  /* Data Valid */
     30# define RNGE       BIT(0)  /* RNG Enable */
     31/* Data Register */
     32#define RNGD    0x04
     33/* Mode Register */
     34#define RNGMODE 0x08
     35# define ROSEL_NORMAL   (2) /* RNG only works in this mode */
     36
     37/* Number of bits to collect for randomness tests. */
     38#define TEST_INPUT_BITS  (128)
     39
     40static void dump_buf_if_failed(const uint8_t *buf, size_t size)
     41{
     42    if (g_test_failed()) {
     43        qemu_hexdump(stderr, "", buf, size);
     44    }
     45}
     46
     47static void rng_writeb(unsigned int offset, uint8_t value)
     48{
     49    writeb(RNG_BASE_ADDR + offset, value);
     50}
     51
     52static uint8_t rng_readb(unsigned int offset)
     53{
     54    return readb(RNG_BASE_ADDR + offset);
     55}
     56
     57/* Disable RNG and set normal ring oscillator mode. */
     58static void rng_reset(void)
     59{
     60    rng_writeb(RNGCS, 0);
     61    rng_writeb(RNGMODE, ROSEL_NORMAL);
     62}
     63
     64/* Reset RNG and then enable it. */
     65static void rng_reset_enable(void)
     66{
     67    rng_reset();
     68    rng_writeb(RNGCS, RNGE);
     69}
     70
     71/* Wait until Data Valid bit is set. */
     72static bool rng_wait_ready(void)
     73{
     74    /* qemu_guest_getrandom may fail. Assume it won't fail 10 times in a row. */
     75    int retries = 10;
     76
     77    while (retries-- > 0) {
     78        if (rng_readb(RNGCS) & DVALID) {
     79            return true;
     80        }
     81    }
     82
     83    return false;
     84}
     85
     86/*
     87 * Perform a frequency (monobit) test, as defined by NIST SP 800-22, on the
     88 * sequence in buf and return the P-value. This represents the probability of a
     89 * truly random sequence having the same proportion of zeros and ones as the
     90 * sequence in buf.
     91 *
     92 * An RNG which always returns 0x00 or 0xff, or has some bits stuck at 0 or 1,
     93 * will fail this test. However, an RNG which always returns 0x55, 0xf0 or some
     94 * other value with an equal number of zeroes and ones will pass.
     95 */
     96static double calc_monobit_p(const uint8_t *buf, unsigned int len)
     97{
     98    unsigned int i;
     99    double s_obs;
    100    int sn = 0;
    101
    102    for (i = 0; i < len; i++) {
    103        /*
    104         * Each 1 counts as 1, each 0 counts as -1.
    105         * s = cp - (8 - cp) = 2 * cp - 8
    106         */
    107        sn += 2 * ctpop8(buf[i]) - 8;
    108    }
    109
    110    s_obs = abs(sn) / sqrt(len * BITS_PER_BYTE);
    111
    112    return erfc(s_obs / sqrt(2));
    113}
    114
    115/*
    116 * Perform a runs test, as defined by NIST SP 800-22, and return the P-value.
    117 * This represents the probability of a truly random sequence having the same
    118 * number of runs (i.e. uninterrupted sequences of identical bits) as the
    119 * sequence in buf.
    120 */
    121static double calc_runs_p(const unsigned long *buf, unsigned int nr_bits)
    122{
    123    unsigned int j;
    124    unsigned int k;
    125    int nr_ones = 0;
    126    int vn_obs = 0;
    127    double pi;
    128
    129    g_assert(nr_bits % BITS_PER_LONG == 0);
    130
    131    for (j = 0; j < nr_bits / BITS_PER_LONG; j++) {
    132        nr_ones += __builtin_popcountl(buf[j]);
    133    }
    134    pi = (double)nr_ones / nr_bits;
    135
    136    for (k = 0; k < nr_bits - 1; k++) {
    137        vn_obs += (test_bit(k, buf) ^ test_bit(k + 1, buf));
    138    }
    139    vn_obs += 1;
    140
    141    return erfc(fabs(vn_obs - 2 * nr_bits * pi * (1.0 - pi))
    142                / (2 * sqrt(2 * nr_bits) * pi * (1.0 - pi)));
    143}
    144
    145/*
    146 * Verifies that DVALID is clear, and RNGD reads zero, when RNGE is cleared,
    147 * and DVALID eventually becomes set when RNGE is set.
    148 */
    149static void test_enable_disable(void)
    150{
    151    /* Disable: DVALID should not be set, and RNGD should read zero */
    152    rng_reset();
    153    g_assert_cmphex(rng_readb(RNGCS), ==, 0);
    154    g_assert_cmphex(rng_readb(RNGD), ==, 0);
    155
    156    /* Enable: DVALID should be set, but we can't make assumptions about RNGD */
    157    rng_writeb(RNGCS, RNGE);
    158    g_assert_true(rng_wait_ready());
    159    g_assert_cmphex(rng_readb(RNGCS), ==, DVALID | RNGE);
    160
    161    /* Disable: DVALID should not be set, and RNGD should read zero */
    162    rng_writeb(RNGCS, 0);
    163    g_assert_cmphex(rng_readb(RNGCS), ==, 0);
    164    g_assert_cmphex(rng_readb(RNGD), ==, 0);
    165}
    166
    167/*
    168 * Verifies that the RNG only produces data when RNGMODE is set to 'normal'
    169 * ring oscillator mode.
    170 */
    171static void test_rosel(void)
    172{
    173    rng_reset_enable();
    174    g_assert_true(rng_wait_ready());
    175    rng_writeb(RNGMODE, 0);
    176    g_assert_false(rng_wait_ready());
    177    rng_writeb(RNGMODE, ROSEL_NORMAL);
    178    g_assert_true(rng_wait_ready());
    179    rng_writeb(RNGMODE, 0);
    180    g_assert_false(rng_wait_ready());
    181}
    182
    183/*
    184 * Verifies that a continuous sequence of bits collected after enabling the RNG
    185 * satisfies a monobit test.
    186 */
    187static void test_continuous_monobit(void)
    188{
    189    uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
    190    unsigned int i;
    191
    192    rng_reset_enable();
    193    for (i = 0; i < sizeof(buf); i++) {
    194        g_assert_true(rng_wait_ready());
    195        buf[i] = rng_readb(RNGD);
    196    }
    197
    198    g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
    199    dump_buf_if_failed(buf, sizeof(buf));
    200}
    201
    202/*
    203 * Verifies that a continuous sequence of bits collected after enabling the RNG
    204 * satisfies a runs test.
    205 */
    206static void test_continuous_runs(void)
    207{
    208    union {
    209        unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
    210        uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
    211    } buf;
    212    unsigned int i;
    213
    214    rng_reset_enable();
    215    for (i = 0; i < sizeof(buf); i++) {
    216        g_assert_true(rng_wait_ready());
    217        buf.c[i] = rng_readb(RNGD);
    218    }
    219
    220    g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
    221    dump_buf_if_failed(buf.c, sizeof(buf));
    222}
    223
    224/*
    225 * Verifies that the first data byte collected after enabling the RNG satisfies
    226 * a monobit test.
    227 */
    228static void test_first_byte_monobit(void)
    229{
    230    /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
    231    uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
    232    unsigned int i;
    233
    234    rng_reset();
    235    for (i = 0; i < sizeof(buf); i++) {
    236        rng_writeb(RNGCS, RNGE);
    237        g_assert_true(rng_wait_ready());
    238        buf[i] = rng_readb(RNGD);
    239        rng_writeb(RNGCS, 0);
    240    }
    241
    242    g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
    243    dump_buf_if_failed(buf, sizeof(buf));
    244}
    245
    246/*
    247 * Verifies that the first data byte collected after enabling the RNG satisfies
    248 * a runs test.
    249 */
    250static void test_first_byte_runs(void)
    251{
    252    /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
    253    union {
    254        unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
    255        uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
    256    } buf;
    257    unsigned int i;
    258
    259    rng_reset();
    260    for (i = 0; i < sizeof(buf); i++) {
    261        rng_writeb(RNGCS, RNGE);
    262        g_assert_true(rng_wait_ready());
    263        buf.c[i] = rng_readb(RNGD);
    264        rng_writeb(RNGCS, 0);
    265    }
    266
    267    g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
    268    dump_buf_if_failed(buf.c, sizeof(buf));
    269}
    270
    271int main(int argc, char **argv)
    272{
    273    int ret;
    274
    275    g_test_init(&argc, &argv, NULL);
    276    g_test_set_nonfatal_assertions();
    277
    278    qtest_add_func("npcm7xx_rng/enable_disable", test_enable_disable);
    279    qtest_add_func("npcm7xx_rng/rosel", test_rosel);
    280    /*
    281     * These tests fail intermittently; only run them on explicit
    282     * request until we figure out why.
    283     */
    284    if (getenv("QEMU_TEST_FLAKY_RNG_TESTS")) {
    285        qtest_add_func("npcm7xx_rng/continuous/monobit", test_continuous_monobit);
    286        qtest_add_func("npcm7xx_rng/continuous/runs", test_continuous_runs);
    287        qtest_add_func("npcm7xx_rng/first_byte/monobit", test_first_byte_monobit);
    288        qtest_add_func("npcm7xx_rng/first_byte/runs", test_first_byte_runs);
    289    }
    290
    291    qtest_start("-machine npcm750-evb");
    292    ret = g_test_run();
    293    qtest_end();
    294
    295    return ret;
    296}