2020-12-17 08:33:49 +02:00
/***********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
2013-05-09 15:24:32 +02:00
2017-08-26 18:44:21 +03:00
#ifndef SECP256K1_TESTRAND_IMPL_H
#define SECP256K1_TESTRAND_IMPL_H
2013-04-20 23:34:41 +02:00
#include <stdint.h>
2020-09-08 13:40:26 -07:00
#include <stdio.h>
2013-04-20 23:34:41 +02:00
#include <string.h>
2014-11-12 15:41:47 -08:00
#include "testrand.h"
2015-02-13 15:56:08 -08:00
#include "hash.h"
2023-03-09 15:29:56 +00:00
#include "util.h"
2013-04-20 23:34:41 +02:00
2021-12-24 11:19:29 -05:00
static uint64_t secp256k1_test_state [ 4 ];
2014-10-17 16:04:00 -07:00
2024-05-27 03:08:07 +02:00
SECP256K1_INLINE static void testrand_seed ( const unsigned char * seed16 ) {
2024-08-15 17:43:29 +02:00
static const unsigned char PREFIX [] = { 's' , 'e' , 'c' , 'p' , '2' , '5' , '6' , 'k' , '1' , ' ' , 't' , 'e' , 's' , 't' , ' ' , 'i' , 'n' , 'i' , 't' };
2021-12-24 11:19:29 -05:00
unsigned char out32 [ 32 ];
secp256k1_sha256 hash ;
int i ;
2014-10-17 16:04:00 -07:00
2021-12-24 11:19:29 -05:00
/* Use SHA256(PREFIX || seed16) as initial state. */
secp256k1_sha256_initialize ( & hash );
secp256k1_sha256_write ( & hash , PREFIX , sizeof ( PREFIX ));
secp256k1_sha256_write ( & hash , seed16 , 16 );
secp256k1_sha256_finalize ( & hash , out32 );
for ( i = 0 ; i < 4 ; ++ i ) {
uint64_t s = 0 ;
int j ;
for ( j = 0 ; j < 8 ; ++ j ) s = ( s << 8 ) | out32 [ 8 * i + j ];
secp256k1_test_state [ i ] = s ;
2015-02-13 15:56:08 -08:00
}
2021-12-24 11:19:29 -05:00
}
SECP256K1_INLINE static uint64_t rotl ( const uint64_t x , int k ) {
return ( x << k ) | ( x >> ( 64 - k ));
}
2024-05-27 03:08:07 +02:00
SECP256K1_INLINE static uint64_t testrand64 ( void ) {
2021-12-24 11:19:29 -05:00
/* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */
const uint64_t result = rotl ( secp256k1_test_state [ 0 ] + secp256k1_test_state [ 3 ], 23 ) + secp256k1_test_state [ 0 ];
const uint64_t t = secp256k1_test_state [ 1 ] << 17 ;
secp256k1_test_state [ 2 ] ^= secp256k1_test_state [ 0 ];
secp256k1_test_state [ 3 ] ^= secp256k1_test_state [ 1 ];
secp256k1_test_state [ 1 ] ^= secp256k1_test_state [ 2 ];
secp256k1_test_state [ 0 ] ^= secp256k1_test_state [ 3 ];
secp256k1_test_state [ 2 ] ^= t ;
secp256k1_test_state [ 3 ] = rotl ( secp256k1_test_state [ 3 ], 45 );
return result ;
2013-04-20 23:34:41 +02:00
}
2024-05-27 03:08:07 +02:00
SECP256K1_INLINE static uint64_t testrand_bits ( int bits ) {
2023-05-10 10:40:08 -04:00
if ( bits == 0 ) return 0 ;
2024-05-27 03:08:07 +02:00
return testrand64 () >> ( 64 - bits );
2015-10-17 20:56:53 +02:00
}
2024-05-27 03:08:07 +02:00
SECP256K1_INLINE static uint32_t testrand32 ( void ) {
return testrand64 () >> 32 ;
2021-12-24 11:19:29 -05:00
}
2024-05-27 03:08:07 +02:00
static uint32_t testrand_int ( uint32_t range ) {
2023-05-10 10:40:08 -04:00
uint32_t mask = 0 ;
uint32_t range_copy ;
/* Reduce range by 1, changing its meaning to "maximum value". */
VERIFY_CHECK ( range != 0 );
range -= 1 ;
/* Count the number of bits in range. */
range_copy = range ;
while ( range_copy ) {
mask = ( mask << 1 ) | 1U ;
range_copy >>= 1 ;
2015-10-17 20:56:53 +02:00
}
2023-05-10 10:40:08 -04:00
/* Generation loop. */
while ( 1 ) {
2024-05-27 03:08:07 +02:00
uint32_t val = testrand64 () & mask ;
2023-05-10 10:40:08 -04:00
if ( val <= range ) return val ;
2015-10-17 20:56:53 +02:00
}
}
2024-05-27 03:08:07 +02:00
static void testrand256 ( unsigned char * b32 ) {
2021-12-24 11:19:29 -05:00
int i ;
for ( i = 0 ; i < 4 ; ++ i ) {
2024-05-27 03:08:07 +02:00
uint64_t val = testrand64 ();
2021-12-24 11:19:29 -05:00
b32 [ 0 ] = val ;
b32 [ 1 ] = val >> 8 ;
b32 [ 2 ] = val >> 16 ;
b32 [ 3 ] = val >> 24 ;
b32 [ 4 ] = val >> 32 ;
b32 [ 5 ] = val >> 40 ;
b32 [ 6 ] = val >> 48 ;
b32 [ 7 ] = val >> 56 ;
b32 += 8 ;
}
2013-04-20 23:34:41 +02:00
}
2024-05-27 03:08:07 +02:00
static void testrand_bytes_test ( unsigned char * bytes , size_t len ) {
2015-10-17 20:56:53 +02:00
size_t bits = 0 ;
memset ( bytes , 0 , len );
while ( bits < len * 8 ) {
2015-02-13 15:56:08 -08:00
int now ;
uint32_t val ;
2024-05-27 03:08:07 +02:00
now = 1 + ( testrand_bits ( 6 ) * testrand_bits ( 5 ) + 16 ) / 31 ;
val = testrand_bits ( 1 );
2015-10-17 20:56:53 +02:00
while ( now > 0 && bits < len * 8 ) {
bytes [ bits / 8 ] |= val << ( bits % 8 );
2013-04-20 23:34:41 +02:00
now -- ;
bits ++ ;
}
}
}
2024-05-27 03:08:07 +02:00
static void testrand256_test ( unsigned char * b32 ) {
testrand_bytes_test ( b32 , 32 );
2015-10-17 20:56:53 +02:00
}
2024-05-27 03:08:07 +02:00
static void testrand_flip ( unsigned char * b , size_t len ) {
b [ testrand_int ( len )] ^= ( 1 << testrand_bits ( 3 ));
2020-05-12 21:23:22 +00:00
}
2024-05-27 03:08:07 +02:00
static void testrand_init ( const char * hexseed ) {
2020-09-08 13:40:26 -07:00
unsigned char seed16 [ 16 ] = { 0 };
2020-09-08 16:27:04 -07:00
if ( hexseed && strlen ( hexseed ) != 0 ) {
2020-09-08 13:40:26 -07:00
int pos = 0 ;
while ( pos < 16 && hexseed [ 0 ] != 0 && hexseed [ 1 ] != 0 ) {
unsigned short sh ;
if (( sscanf ( hexseed , "%2hx" , & sh )) == 1 ) {
seed16 [ pos ] = sh ;
} else {
break ;
}
hexseed += 2 ;
pos ++ ;
}
} else {
2021-05-01 13:06:55 +02:00
FILE * frand = fopen ( "/dev/urandom" , "rb" );
2020-09-08 13:40:26 -07:00
if (( frand == NULL ) || fread ( & seed16 , 1 , sizeof ( seed16 ), frand ) != sizeof ( seed16 )) {
uint64_t t = time ( NULL ) * ( uint64_t ) 1337 ;
fprintf ( stderr , "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG \n " );
seed16 [ 0 ] ^= t ;
seed16 [ 1 ] ^= t >> 8 ;
seed16 [ 2 ] ^= t >> 16 ;
seed16 [ 3 ] ^= t >> 24 ;
seed16 [ 4 ] ^= t >> 32 ;
seed16 [ 5 ] ^= t >> 40 ;
seed16 [ 6 ] ^= t >> 48 ;
seed16 [ 7 ] ^= t >> 56 ;
}
if ( frand ) {
fclose ( frand );
}
}
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 ]);
2024-05-27 03:08:07 +02:00
testrand_seed ( seed16 );
2020-09-08 13:40:26 -07:00
}
2024-05-27 03:08:07 +02:00
static void testrand_finish ( void ) {
2020-09-08 13:40:26 -07:00
unsigned char run32 [ 32 ];
2024-05-27 03:08:07 +02:00
testrand256 ( run32 );
2020-09-08 13:40:26 -07:00
printf ( "random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x \n " , run32 [ 0 ], run32 [ 1 ], run32 [ 2 ], run32 [ 3 ], run32 [ 4 ], run32 [ 5 ], run32 [ 6 ], run32 [ 7 ], run32 [ 8 ], run32 [ 9 ], run32 [ 10 ], run32 [ 11 ], run32 [ 12 ], run32 [ 13 ], run32 [ 14 ], run32 [ 15 ]);
}
2017-08-26 18:44:21 +03:00
#endif /* SECP256K1_TESTRAND_IMPL_H */