/ src / secp256k1 / src / testrand_impl.h
testrand_impl.h
  1  /***********************************************************************
  2   * Copyright (c) 2013-2015 Pieter Wuille                               *
  3   * Distributed under the MIT software license, see the accompanying    *
  4   * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
  5   ***********************************************************************/
  6  
  7  #ifndef SECP256K1_TESTRAND_IMPL_H
  8  #define SECP256K1_TESTRAND_IMPL_H
  9  
 10  #include <stdint.h>
 11  #include <stdio.h>
 12  #include <string.h>
 13  
 14  #include "testrand.h"
 15  #include "hash.h"
 16  #include "util.h"
 17  
 18  static uint64_t secp256k1_test_state[4];
 19  
 20  SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) {
 21      static const unsigned char PREFIX[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', ' ', 't', 'e', 's', 't', ' ', 'i', 'n', 'i', 't'};
 22      unsigned char out32[32];
 23      secp256k1_sha256 hash;
 24      int i;
 25      const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(secp256k1_context_static);
 26  
 27      /* Use SHA256(PREFIX || seed16) as initial state. */
 28      secp256k1_sha256_initialize(&hash);
 29      secp256k1_sha256_write(hash_ctx, &hash, PREFIX, sizeof(PREFIX));
 30      secp256k1_sha256_write(hash_ctx, &hash, seed16, 16);
 31      secp256k1_sha256_finalize(hash_ctx, &hash, out32);
 32      for (i = 0; i < 4; ++i) {
 33          uint64_t s = 0;
 34          int j;
 35          for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j];
 36          secp256k1_test_state[i] = s;
 37      }
 38  }
 39  
 40  SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) {
 41      return (x << k) | (x >> (64 - k));
 42  }
 43  
 44  SECP256K1_INLINE static uint64_t testrand64(void) {
 45      /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */
 46      const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0];
 47      const uint64_t t = secp256k1_test_state[1] << 17;
 48      secp256k1_test_state[2] ^= secp256k1_test_state[0];
 49      secp256k1_test_state[3] ^= secp256k1_test_state[1];
 50      secp256k1_test_state[1] ^= secp256k1_test_state[2];
 51      secp256k1_test_state[0] ^= secp256k1_test_state[3];
 52      secp256k1_test_state[2] ^= t;
 53      secp256k1_test_state[3] = rotl(secp256k1_test_state[3], 45);
 54      return result;
 55  }
 56  
 57  SECP256K1_INLINE static uint64_t testrand_bits(int bits) {
 58      if (bits == 0) return 0;
 59      return testrand64() >> (64 - bits);
 60  }
 61  
 62  SECP256K1_INLINE static uint32_t testrand32(void) {
 63      return testrand64() >> 32;
 64  }
 65  
 66  static uint32_t testrand_int(uint32_t range) {
 67      uint32_t mask = 0;
 68      uint32_t range_copy;
 69      /* Reduce range by 1, changing its meaning to "maximum value". */
 70      VERIFY_CHECK(range != 0);
 71      range -= 1;
 72      /* Count the number of bits in range. */
 73      range_copy = range;
 74      while (range_copy) {
 75          mask = (mask << 1) | 1U;
 76          range_copy >>= 1;
 77      }
 78      /* Generation loop. */
 79      while (1) {
 80          uint32_t val = testrand64() & mask;
 81          if (val <= range) return val;
 82      }
 83  }
 84  
 85  static void testrand256(unsigned char *b32) {
 86      int i;
 87      for (i = 0; i < 4; ++i) {
 88          uint64_t val = testrand64();
 89          b32[0] = val;
 90          b32[1] = val >> 8;
 91          b32[2] = val >> 16;
 92          b32[3] = val >> 24;
 93          b32[4] = val >> 32;
 94          b32[5] = val >> 40;
 95          b32[6] = val >> 48;
 96          b32[7] = val >> 56;
 97          b32 += 8;
 98      }
 99  }
100  
101  static void testrand_bytes_test(unsigned char *bytes, size_t len) {
102      size_t bits = 0;
103      memset(bytes, 0, len);
104      while (bits < len * 8) {
105          int now;
106          uint32_t val;
107          now = 1 + (testrand_bits(6) * testrand_bits(5) + 16) / 31;
108          val = testrand_bits(1);
109          while (now > 0 && bits < len * 8) {
110              bytes[bits / 8] |= val << (bits % 8);
111              now--;
112              bits++;
113          }
114      }
115  }
116  
117  static void testrand256_test(unsigned char *b32) {
118      testrand_bytes_test(b32, 32);
119  }
120  
121  static void testrand_flip(unsigned char *b, size_t len) {
122      b[testrand_int(len)] ^= (1 << testrand_bits(3));
123  }
124  
125  static void testrand_init(const char* hexseed) {
126      unsigned char seed16[16] = {0};
127      if (hexseed && strlen(hexseed) != 0) {
128          int pos = 0;
129          while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) {
130              unsigned short sh;
131              if ((sscanf(hexseed, "%2hx", &sh)) == 1) {
132                  seed16[pos] = sh;
133              } else {
134                  break;
135              }
136              hexseed += 2;
137              pos++;
138          }
139      } else {
140          FILE *frand = fopen("/dev/urandom", "rb");
141          if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) {
142              uint64_t t = time(NULL) * (uint64_t)1337;
143              fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n");
144              seed16[0] ^= t;
145              seed16[1] ^= t >> 8;
146              seed16[2] ^= t >> 16;
147              seed16[3] ^= t >> 24;
148              seed16[4] ^= t >> 32;
149              seed16[5] ^= t >> 40;
150              seed16[6] ^= t >> 48;
151              seed16[7] ^= t >> 56;
152          }
153          if (frand) {
154              fclose(frand);
155          }
156      }
157  
158      printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]);
159      testrand_seed(seed16);
160  }
161  
162  #endif /* SECP256K1_TESTRAND_IMPL_H */