Как получить случайные байты на этапе компиляции?

Рейтинг: 1Ответов: 3Опубликовано: 11.01.2023

Как можно получить N байт на этапе компиляции максимально просто?

constexpr unsigned char bytes[] = ???;

Ответы

▲ 3
dd if=/dev/urandom of=./randomkey.bin bs=32 count=1
xxd  -n bytes -i ./randomkey.bin ./randomkey.h
rm ./randomkey.bin

Сгенерирует заголовочный файл, который можно ставить через #include в нужное место.

unsigned char bytes[] = {
  0x72, 0xdb, 0x7c, 0x53, 0x3a, 0x13, 0xad, 0x76, 0xfa, 0x94, 0xf2, 0xd2,
  0x6a, 0x8c, 0xcd, 0x87, 0xdd, 0x4e, 0x3f, 0x8a, 0xf3, 0x61, 0xc2, 0x9f,
  0xcd, 0xc6, 0x6a, 0x25, 0xc6, 0x7e, 0x8c, 0x7e
};
unsigned int bytes_len = 32;
▲ 2
#include <boost/preprocessor/repeat.hpp>

#define RAND_CHARS_ITEM(_unused1, I, SEED) (unsigned char)( ( size_t( (I^2531011u) *1222943u + SEED  )%214013u  ^(23167u) )  ),
#define RAND_CHARS( SIZE, SEED )  BOOST_PP_REPEAT(SIZE, RAND_CHARS_ITEM, SEED)
#define RAND_SEED()  ( (__TIME__[3] + __TIME__[6]*11u +  __TIME__[5]*19u  ) *32803u +  __LINE__*17u +12224189u )

unsigned char bytes[] = { RAND_CHARS(128, RAND_SEED() ) };

Получим:

bytes:
        .ascii  "t\245\326\004\263\344\025F\365#T\2054b\223\304s\244\322\003\262"
        .ascii  "\343\021B\361\"S\2010a\222\300o\240\321\002\261\337\020A\360"
        .ascii  "\036O\200/`\216\277n\237\315\376\255\336\017=\354\035N|+\\\215"
        .ascii  "\276~\257\335\016\275\356\037M\374-^\214;l\235\316}\253\334\r"
        .ascii  "\274\352\033L\373,Z\213:k\231\312y\252\333\t\270\351\032H\367"
        .ascii  "(Y\2129g\230\311x\246\327\b\267\350\026G\366'U\2065f\227\305"

https://godbolt.org/z/fv8To5K6P

▲ 1

Метод тот же что и у @eri, но хочется немного развернуть ответ. Идея в том чтобы вставлять случайные байты на этапе компляции через директивы препроцессора. Большинство компиляторов позволяют определять константы препроцессора через флаг -D.

#include <iostream>
#include <iomanip>

#ifndef RANDOM_BYTES
#define DUMMY_BYTES 0x00
#define RANDOM_BYTES DUMMY_BYTES
#endif

int
main()
{
    constexpr unsigned char bytes[] = {
        RANDOM_BYTES
    };

    for (unsigned int i : bytes) {
        std::cout
            << std::hex
            << std::setw(2)
            << std::setfill('0')
            << i
            << ' ';
    }

    std::cout << std::endl;
}

По необходимости, определяем RANDOM_BYTES чтобы избежать предупреждений компилятора и линтера. Это полезно если в вашем редакторе кода используется автоматическая проверка файла через LSP или его аналоги. Однако в случае если RANDOM_BYTES не была определена во время компиляции, то компилятор молча подставит DUMMY_BYTES!

И соответствующий Makefile:

LEN := 128
BYTES := $(shell dd if=/dev/urandom bs=$(LEN) count=1 status=none | xxd -i)

main: main.cpp
    @g++ -D"RANDOM_BYTES=$(BYTES)" -o $@ $<

.DELETE_ON_ERROR:

Есть также статья «Random number generator for C++ template metaprograms», в которой предлагается, compile-time решение с помощью шаблонов.