Commit 418b3932 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Started new random number generator integration.

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent b20a3830
bin_PROGRAMS = audiowmark
COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc
COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc
audiowmark_SOURCES = audiowmark.cc wavdata.cc wavdata.hh fft.cc fft.hh $(COMMON_SRC)
audiowmark_LDFLAGS = $(SNDFILE_LIBS) $(FFTW_LIBS)
audiowmark_LDFLAGS = $(SNDFILE_LIBS) $(FFTW_LIBS) $(LIBGCRYPT_LIBS)
noinst_PROGRAMS = testconvcode testrandom
testconvcode_SOURCES = testconvcode.cc $(COMMON_SRC)
testconvcode_LDFLAGS = $(LIBGCRYPT_LIBS)
testrandom_SOURCES = testrandom.cc
testrandom_SOURCES = testrandom.cc $(COMMON_SRC)
testrandom_LDFLAGS = $(LIBGCRYPT_LIBS)
......@@ -8,6 +8,7 @@
#include "wavdata.hh"
#include "utils.hh"
#include "convcode.hh"
#include "random.hh"
#include <assert.h>
......@@ -241,23 +242,12 @@ get_frame (const WavData& wav_data, int f, int ch)
return result;
}
std::mt19937_64
init_rng (uint64_t seed)
{
const uint64_t prime = 3126986573;
std::mt19937_64 rng;
rng.seed (seed + prime * Params::seed);
return rng;
}
void
get_up_down (int f, vector<int>& up, vector<int>& down)
{
vector<int> used (Params::frame_size / 2);
std::mt19937_64 rng = init_rng (f); // use per frame random seed, may want to have cryptographically secure algorithm
Random rng (f, Random::Stream::up_down); // use per frame random seed
auto choose_bands = [&used, &rng] (vector<int>& bands) {
while (bands.size() < Params::bands_per_frame)
......@@ -275,9 +265,9 @@ get_up_down (int f, vector<int>& up, vector<int>& down)
}
template<class T> void
gen_shuffle (vector<T>& result, int seed)
gen_shuffle (vector<T>& result, int seed, Random::Stream stream)
{
std::mt19937_64 rng = init_rng (seed); // should use cryptographically secure generator, properly seeded
Random rng (seed, stream);
// Fisher–Yates shuffle
for (size_t i = 0; i < result.size() - 1; i++)
......@@ -295,7 +285,7 @@ randomize_bit_order (const vector<T>& bit_vec, bool encode)
for (size_t i = 0; i < bit_vec.size(); i++)
order.push_back (i);
gen_shuffle (order, /* seed */ 0);
gen_shuffle (order, /* seed */ 0, Random::Stream::bit_order);
vector<T> out_bits (bit_vec.size());
for (size_t i = 0; i < bit_vec.size(); i++)
......@@ -330,7 +320,7 @@ gen_mix_entries (int block)
for (size_t i = 0; i < up.size(); i++)
mix_entries.push_back ({ f, up[i], down[i] });
}
gen_shuffle (mix_entries, /* seed */ block);
gen_shuffle (mix_entries, /* seed */ block, Random::Stream::mix);
return mix_entries;
}
......
#include "random.hh"
Random::Random (uint64_t seed, Stream stream)
{
std::vector<unsigned char> ctr = get_start_counter (seed, stream);
#if 0
printf ("CTR: ");
for (auto ch : ctr)
printf ("%02x ", ch);
printf ("\n");
#endif
gcry_error_t gcry_ret = gcry_cipher_open (&aes_ctr_cipher, GCRY_CIPHER, GCRY_CIPHER_MODE_CTR, 0);
die_on_error ("gcry_cipher_open", gcry_ret);
gcry_ret = gcry_cipher_setkey (aes_ctr_cipher, &aes_key[0], aes_key.size());
die_on_error ("gcry_cipher_setkey", gcry_ret);
gcry_ret = gcry_cipher_setctr (aes_ctr_cipher, &ctr[0], ctr.size());
die_on_error ("gcry_cipher_setctr", gcry_ret);
}
Random::~Random()
{
gcry_cipher_close (aes_ctr_cipher);
}
std::vector<unsigned char>
Random::get_start_counter (uint64_t seed, Stream stream)
{
gcry_error_t gcry_ret;
gcry_cipher_hd_t cipher_hd;
gcry_ret = gcry_cipher_open (&cipher_hd, GCRY_CIPHER, GCRY_CIPHER_MODE_ECB, 0);
die_on_error ("gcry_cipher_open", gcry_ret);
gcry_ret = gcry_cipher_setkey (cipher_hd, &aes_key[0], aes_key.size());
die_on_error ("gcry_cipher_setkey", gcry_ret);
std::vector<unsigned char> cipher_text (16);
std::vector<unsigned char> plain_text (16);
/* this has to be endian independent: use big endian order */
plain_text[0] = seed >> 56;
plain_text[1] = seed >> 48;
plain_text[2] = seed >> 40;
plain_text[3] = seed >> 32;
plain_text[4] = seed >> 24;
plain_text[5] = seed >> 16;
plain_text[6] = seed >> 8;
plain_text[7] = seed;
plain_text[8] = uint8_t (stream);
#if 0
printf ("[[ ");
for (auto ch : plain_text)
printf ("%02x ", ch);
printf (" ]]\n");
#endif
gcry_ret = gcry_cipher_encrypt (cipher_hd, &cipher_text[0], cipher_text.size(),
&plain_text[0], plain_text.size());
die_on_error ("gcry_cipher_encrypt", gcry_ret);
gcry_cipher_close (cipher_hd);
#if 0
printf ("[[ ");
for (auto ch : cipher_text)
printf ("%02x ", ch);
printf (" ]]\n");
#endif
return cipher_text;
}
uint64_t
Random::operator()()
{
const size_t block_size = 8;
unsigned char zeros[block_size] = { 0, };
unsigned char cipher_text[block_size];
gcry_error_t gcry_ret = gcry_cipher_encrypt (aes_ctr_cipher, cipher_text, block_size, zeros, block_size);
die_on_error ("gcry_cipher_encrypt", gcry_ret);
#if 0
printf ("[[ ");
for (auto ch : cipher_text)
printf ("%02x ", ch);
printf (" ]]\n");
#endif
/* this has to be endian independent: use big endian order */
uint64_t result = (uint64_t (cipher_text[0]) << 56)
+ (uint64_t (cipher_text[1]) << 48)
+ (uint64_t (cipher_text[2]) << 40)
+ (uint64_t (cipher_text[3]) << 32)
+ (uint64_t (cipher_text[4]) << 24)
+ (uint64_t (cipher_text[5]) << 16)
+ (uint64_t (cipher_text[6]) << 8)
+ cipher_text[7];
return result;
}
#ifndef AUDIOWMARK_RANDOM_HH
#define AUDIOWMARK_RANDOM_HH
#include <gcrypt.h>
#include <stdint.h>
#include <vector>
class Random
{
public:
enum class Stream {
up_down = 1,
mix = 2,
bit_order = 3
};
private:
std::vector<unsigned char> aes_key = std::vector<unsigned char> (16);
gcry_cipher_hd_t aes_ctr_cipher;
static constexpr auto GCRY_CIPHER = GCRY_CIPHER_AES128;
void
die_on_error (const char *func, gcry_error_t error)
{
if (error)
{
fprintf (stderr, "%s failed: %s/%s\n", func, gcry_strsource (error), gcry_strerror (error));
exit (1); /* can't recover here */
}
}
std::vector<unsigned char> get_start_counter (uint64_t seed, Stream stream);
public:
Random (uint64_t seed, Stream stream);
~Random();
uint64_t operator()();
};
#endif /* AUDIOWMARK_RANDOM_HH */
#include "utils.hh"
#include "random.hh"
#include <sys/time.h>
#include <gcrypt.h>
using std::vector;
using std::string;
......@@ -15,121 +15,6 @@ gettime()
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
static constexpr auto GCRY_CIPHER = GCRY_CIPHER_AES128;
class Random
{
vector<unsigned char> aes_key = vector<unsigned char> (16);
gcry_cipher_hd_t aes_ctr_cipher;
void
die_on_error (const char *func, gcry_error_t error)
{
if (error)
{
fprintf (stderr, "%s failed: %s/%s\n", func, gcry_strsource (error), gcry_strerror (error));
exit (1); /* can't recover here */
}
}
public:
enum class Stream {
up_down = 1,
mix = 2,
bit_order = 3
};
Random (uint64_t seed, Stream stream)
{
vector<unsigned char> ctr = get_start_counter (seed, stream);
printf ("CTR: ");
for (auto ch : ctr)
printf ("%02x ", ch);
printf ("\n");
gcry_error_t gcry_ret = gcry_cipher_open (&aes_ctr_cipher, GCRY_CIPHER, GCRY_CIPHER_MODE_CTR, 0);
die_on_error ("gcry_cipher_open", gcry_ret);
gcry_ret = gcry_cipher_setkey (aes_ctr_cipher, &aes_key[0], aes_key.size());
die_on_error ("gcry_cipher_setkey", gcry_ret);
gcry_ret = gcry_cipher_setctr (aes_ctr_cipher, &ctr[0], ctr.size());
die_on_error ("gcry_cipher_setctr", gcry_ret);
}
~Random()
{
gcry_cipher_close (aes_ctr_cipher);
}
vector<unsigned char>
get_start_counter (uint64_t seed, Stream stream)
{
gcry_error_t gcry_ret;
gcry_cipher_hd_t cipher_hd;
gcry_ret = gcry_cipher_open (&cipher_hd, GCRY_CIPHER, GCRY_CIPHER_MODE_ECB, 0);
die_on_error ("gcry_cipher_open", gcry_ret);
gcry_ret = gcry_cipher_setkey (cipher_hd, &aes_key[0], aes_key.size());
die_on_error ("gcry_cipher_setkey", gcry_ret);
vector<unsigned char> cipher_text (16);
vector<unsigned char> plain_text (16);
/* this has to be endian independent: use big endian order */
plain_text[0] = seed >> 56;
plain_text[1] = seed >> 48;
plain_text[2] = seed >> 40;
plain_text[3] = seed >> 32;
plain_text[4] = seed >> 24;
plain_text[5] = seed >> 16;
plain_text[6] = seed >> 8;
plain_text[7] = seed;
plain_text[8] = uint8_t (stream);
printf ("[[ ");
for (auto ch : plain_text)
printf ("%02x ", ch);
printf (" ]]\n");
gcry_ret = gcry_cipher_encrypt (cipher_hd, &cipher_text[0], cipher_text.size(),
&plain_text[0], plain_text.size());
die_on_error ("gcry_cipher_encrypt", gcry_ret);
gcry_cipher_close (cipher_hd);
printf ("[[ ");
for (auto ch : cipher_text)
printf ("%02x ", ch);
printf (" ]]\n");
return cipher_text;
}
uint64_t operator()()
{
const size_t block_size = 8;
unsigned char zeros[block_size] = { 0, };
unsigned char cipher_text[block_size];
gcry_error_t gcry_ret = gcry_cipher_encrypt (aes_ctr_cipher, cipher_text, block_size, zeros, block_size);
die_on_error ("gcry_cipher_encrypt", gcry_ret);
printf ("[[ ");
for (auto ch : cipher_text)
printf ("%02x ", ch);
printf (" ]]\n");
/* this has to be endian independent: use big endian order */
uint64_t result = (uint64_t (cipher_text[0]) << 56)
+ (uint64_t (cipher_text[1]) << 48)
+ (uint64_t (cipher_text[2]) << 40)
+ (uint64_t (cipher_text[3]) << 32)
+ (uint64_t (cipher_text[4]) << 24)
+ (uint64_t (cipher_text[5]) << 16)
+ (uint64_t (cipher_text[6]) << 8)
+ cipher_text[7];
return result;
}
};
int
main (int argc, char **argv)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment