Now it's part of https://github.com/maciejczyzewski/libchaos library!!!
Last active
January 12, 2017 21:28
-
-
Save maciejczyzewski/d3acad06cc5019b83a7bc0b3457f7c53 to your computer and use it in GitHub Desktop.
Appendix from https://eprint.iacr.org/2016/468 rewritten to C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CHAOS_HH | |
#define CHAOS_HH | |
#include <iostream> | |
#include <stdexcept> | |
#include <vector> | |
namespace chaos { //::chaos //////////////////////////////////////////////////// | |
namespace engines { //::chaos::engines ///////////////////////////////////////// | |
/* NCG written in 2015 by Maciej A. Czyzewski | |
To the extent possible under law, the author has dedicated all copyright | |
and related and neighboring rights to this software to the public domain | |
worldwide. This software is distributed without any warranty. | |
See <http://creativecommons.org/publicdomain/zero/1.0/>. */ | |
class ncg { | |
public: | |
// metadata | |
static const std::string name, authors; | |
// typename | |
const size_t __size_push = 32, __size_pull = 32; | |
// defaults | |
const size_t __default_space = 8, __default_time = 1; | |
const std::vector<uint8_t> __default_key = {0x14, 0x15, 0x92, 0x65, | |
0x35, 0x89, 0x79, 0x32}; | |
// interface | |
void __push(uint32_t); | |
uint32_t __pull(void); | |
// cleaning | |
void __reset(void); | |
protected: | |
// costs | |
size_t __cost_space = 0, __cost_time = 0; | |
// methods | |
virtual void __set_key(std::vector<uint8_t> value) { | |
// resize key if needed | |
value.resize(this->__cost_space); | |
// set starting variable | |
for (std::vector<uint8_t>::size_type i = 0; i != value.size(); i++) { | |
// in NCG one hybrid system is build upon two cells in buffer | |
this->buffer[i * 2] = (value[i] >> 4) & 0x0F; | |
this->buffer[i * 2 + 1] = (value[i] >> 0) & 0x0F; | |
} | |
} | |
virtual void __set_space(size_t value) { | |
// set new space parameter | |
this->__cost_space = value; | |
// resize machine spaces if needed | |
this->buffer.resize(this->__cost_space * 2); | |
} | |
virtual void __set_time(size_t value) { | |
// set new time parameter | |
this->__cost_time = value; | |
} | |
private: | |
// spaces in algorithm | |
std::vector<uint16_t> buffer, params = {0, 0}; | |
// variables in the algorithm | |
uint16_t a, b, Y; | |
// S - seed, I - increment, X - mask, i - temporary | |
uint32_t S, I, X, i; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// metadata | |
const std::string ncg::name = "NCG (Naive Czyzewski Generator)"; | |
const std::string ncg::authors = "Maciej A. Czyzewski"; | |
// @1: abbreviation for getting values from the tape | |
#define M(i) ((i) % (this->__cost_space * 2)) | |
// @2: bits rotation formula | |
#define R(x, y) (((x) << (y)) | ((x) >> (16 - (y)))) | |
void ncg::__push(uint32_t block) { | |
// preparation | |
I = block * 0x3C6EF35F; | |
for (S = block, i = 0; i < this->__cost_space * 2; i++) { | |
// reinforcement | |
buffer[M(i)] ^= ((I * (S + 1)) ^ S) >> 16; | |
buffer[M(i)] ^= ((I * (S - 1)) ^ S) >> 00; | |
// finalization | |
I ^= ((buffer[M(I - 1)] + buffer[M(i)]) << 16) ^ | |
((buffer[M(I + 1)] - buffer[M(i)]) << 00); | |
} | |
} | |
uint32_t ncg::__pull(void) { | |
// variables | |
a = buffer[M(I + 0)]; | |
b = buffer[M(I + 1)]; | |
// initialization | |
X = (a + I) * (b - S); | |
// chaos | |
Y = (buffer[M(X - b)] << (a % 9)) ^ (buffer[M(X + a)] >> (b % 9)); | |
// rounds | |
for (i = 0; i < this->__cost_time * 2; i += 2) { | |
// absorption | |
params[0] ^= buffer[M(I + i - 2)]; | |
params[1] ^= buffer[M(I + i + 2)]; | |
// mixing + modification | |
params[0] ^= (params[1] ^= R(Y, params[0] % 17)); | |
buffer[M(I + i - 2)] -= (params[1] += (X & params[0])); | |
params[1] += (params[0] += R(X, params[1] % 17)); | |
buffer[M(I + i + 2)] += (params[0] += (Y & params[1])); | |
} | |
// transformation | |
buffer[M(I + 0)] = // chaotic map | |
R(params[0], X % 17) ^ R(params[1], X % 17) ^ (X & a) ^ (Y & b); | |
buffer[M(I + 1)] = (b >> 1) ^ (-(b & 1u) & 0xB400u); // LFSR | |
// finalization | |
X += params[0] ^ (b << 8) ^ (params[1] << 16) ^ (a & 0xFF) ^ ((a >> 8) << 24); | |
// cleaning | |
params[0] = params[1] = 0xFFFF; | |
// increment | |
I += 2; | |
return X; | |
} | |
void ncg::__reset(void) { | |
// clear parameters space | |
std::fill(params.begin(), params.end(), 0); | |
S = 0x19660D00; // seed is not defined (prime) | |
I = 0x3C6EF35F; // increment should be set | |
} | |
#undef M // @1 | |
#undef R // @2 | |
} //::chaos::engines /////////////////////////////////////////////////////////// | |
template <class algorithm> class machine : public virtual algorithm { | |
private: | |
// memory | |
std::vector<uint8_t> key; | |
// cache | |
uint_fast64_t cache[2] = {0, 0}; | |
size_t padding[2] = {0, 0}; | |
public: | |
explicit machine(std::vector<uint8_t> key = {}); | |
// configuration | |
void set_key(std::vector<uint8_t>); | |
void set_space(size_t); | |
void set_time(size_t); | |
// I/O single | |
void push(uint8_t); | |
uint8_t pull(void); | |
// I/O stream | |
void message(std::vector<uint8_t> &); | |
std::vector<uint8_t> digest(size_t); | |
// cleaning | |
void reset(void); | |
}; | |
/// methods //////////////////////////////////////////////////////////////////// | |
template <class algorithm> | |
machine<algorithm>::machine(std::vector<uint8_t> key) { | |
// check if algorithm is supported by this container | |
if (!(this->__size_push == 8 || this->__size_push == 16 || | |
this->__size_push == 32 || this->__size_push == 64)) | |
throw std::invalid_argument("wrong __size_push data type. Supported " | |
"types: uint8_t, uint16_t, uint32_t, uint64_t"); | |
if (!(this->__size_pull == 8 || this->__size_pull == 16 || | |
this->__size_pull == 32 || this->__size_pull == 64)) | |
throw std::invalid_argument("wrong __size_pull data type. Supported " | |
"types: uint8_t, uint16_t, uint32_t, uint64_t"); | |
// check if there is a initial secret key | |
this->key = key.size() != 0 ? key : this->__default_key; | |
// configure space and time parameter | |
this->set_space(this->key.size()); | |
this->set_time(this->__default_time); | |
// set starting variable | |
this->reset(); | |
} | |
template <class algorithm> | |
void machine<algorithm>::set_key(std::vector<uint8_t> key) { | |
// check if received key is not empty | |
this->key = key.size() != 0 ? key : this->__default_key; | |
this->set_space(this->key.size()); // set new space parameter | |
this->__set_key(key); // pass via algorithm | |
}; | |
template <class algorithm> void machine<algorithm>::set_time(size_t value) { | |
this->__set_time(value); // pass via algorithm | |
}; | |
template <class algorithm> void machine<algorithm>::set_space(size_t value) { | |
this->__set_space(value); // pass via algorithm | |
}; | |
template <class algorithm> void machine<algorithm>::push(uint8_t block) { | |
// do not use cache if 8 bit | |
if (this->__size_push == 8) | |
return this->__push(block); | |
// add block to cache variable | |
this->cache[0] ^= block << (this->__size_push - (this->padding[0] + 1) * 8); | |
if (this->__size_push == (this->padding[0] + 1) * 8) { | |
// clear cache and push to engine | |
this->__push(this->cache[0]); | |
this->padding[0] = this->cache[0] = this->padding[1] = 0; | |
} else { | |
this->padding[0]++; // increment | |
} | |
} | |
template <class algorithm> uint8_t machine<algorithm>::pull(void) { | |
// do not use cache if 8 bit | |
if (this->__size_pull == 8) | |
return this->__pull(); | |
// if input cache is not full | |
if (this->padding[0] > 0) { | |
this->__push(this->cache[0]); // push to engine | |
this->padding[0] = this->cache[0] = this->padding[1] = 0; | |
} | |
// if there is empty cache | |
if (this->padding[1] == 0 || this->__size_pull == this->padding[1] * 8) { | |
this->cache[1] = this->__pull(); | |
this->padding[1] = 0; // reset padding | |
} | |
this->padding[1]++; // increment | |
return (uint8_t)(this->cache[1] >> | |
(this->__size_pull - this->padding[1] * 8)); | |
} | |
template <class algorithm> | |
void machine<algorithm>::message(std::vector<uint8_t> &blocks) { | |
if (blocks.size() == 0) | |
return; // empty vector, nothing to do | |
// try to predict left padding (cache module) | |
size_t left_padding = this->__size_push / 8 - this->padding[0]; | |
// if input cache is not full | |
if (this->padding[0] > 0) { | |
for (size_t i = this->padding[0]; i < this->__size_push / 8; i++) { | |
this->cache[0] ^= blocks[i - this->padding[0]] | |
<< (this->__size_push - (i + 1) * 8); | |
} // send cached bytes | |
this->__push(this->cache[0]); | |
} else { // if there is no need to pad | |
left_padding = 0; | |
} | |
// calculate marginal/right padded blocks | |
size_t right_padding = | |
(((blocks.size() - left_padding) * 8) % this->__size_push) / 8; | |
// choose correct datatype used by __push() | |
switch (this->__size_push) { | |
case 8: | |
for (size_t i = left_padding; // pass via algorithm's engine | |
i < blocks.size() - left_padding - right_padding; i += 1) | |
this->__push((uint8_t)(blocks[i])); | |
break; | |
case 16: | |
for (size_t i = left_padding; // pass via algorithm's engine | |
i < blocks.size() - left_padding - right_padding; i += 2) | |
this->__push(((uint16_t)blocks[i + 1]) | ((uint16_t)blocks[i] << 8)); | |
break; | |
case 32: | |
for (size_t i = left_padding; // pass via algorithm's engine | |
i < blocks.size() - left_padding - right_padding; i += 4) | |
this->__push(((uint32_t)blocks[i + 3]) | ((uint32_t)blocks[i + 2] << 8) | | |
((uint32_t)blocks[i + 1] << 16) | | |
((uint32_t)blocks[i] << 24)); | |
break; | |
case 64: | |
for (size_t i = left_padding; // pass via algorithm's engine | |
i < blocks.size() - left_padding - right_padding; i += 8) | |
this->__push( | |
((uint64_t)blocks[i + 7]) | ((uint64_t)blocks[i + 6] << 8) | | |
((uint64_t)blocks[i + 5] << 16) | ((uint64_t)blocks[i + 4] << 24) | | |
((uint64_t)blocks[i + 3] << 32) | ((uint64_t)blocks[i + 2] << 40) | | |
((uint64_t)blocks[i + 1] << 48) | ((uint64_t)blocks[i] << 56)); | |
break; | |
} | |
// reset local cache environment | |
this->padding[0] = this->cache[0] = this->padding[1] = 0; | |
// blocks that couldn't be used by algorithm __push() function | |
for (size_t i = 0; i < right_padding; i++) | |
this->push(blocks[blocks.size() + i - right_padding]); | |
} | |
template <class algorithm> | |
std::vector<uint8_t> machine<algorithm>::digest(size_t length) { | |
// pass via interface | |
std::vector<uint8_t> blocks(length); | |
for (size_t i = 0; i < length; i++) | |
blocks[i] = this->pull(); | |
return blocks; | |
} | |
template <class algorithm> void machine<algorithm>::reset(void) { | |
// remove cache and padding | |
this->cache[0] = this->cache[1] = this->padding[0] = this->padding[1] = 0; | |
// replace memory with our key | |
this->__set_key(this->key); | |
// call reset function in algorithm | |
this->__reset(); | |
} | |
} //::chaos //////////////////////////////////////////////////////////////////// | |
#endif // CHAOS_HH |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Testing: | |
// $ ./fake_dev_random | xxd -l 1024 | |
#include <ctime> | |
#include <iostream> | |
#include "chaos.hpp" // library header | |
// create seed on the base of time | |
uint8_t seed = static_cast<uint8_t>(time(NULL)); | |
// initialize chaos machine using NCG algorithm/engine | |
chaos::machine<chaos::engines::ncg> x_machine; | |
int main(void) { | |
// configure machine with parameters (t=2, m=256) | |
x_machine.set_time(2); x_machine.set_space(256); | |
// initialize with seed (still pseudo-randomness) | |
x_machine.push(seed); // can be anything | |
// serve like /dev/random | |
while (true) | |
putc_unlocked(x_machine.pull(), stdout); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Testing: | |
// $ cmp -bl <(./fake_hash_function "Lorem ipsum dolor sit...") \ | |
// <(./fake_hash_function "Lorem ipsum bolor sit...") | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include "chaos.hpp" // library header | |
// allocate std::vector (our starting variable) | |
std::vector<uint8_t> y_secret = {0x14, 0x15, 0x92, 0x65, | |
0x35, 0x89, 0x79, 0x32}; | |
// initialize chaos machine using NCG algorithm/engine | |
chaos::machine<chaos::engines::ncg> x_machine(y_secret); | |
int main(int argc, char** argv) { | |
// allocate std::vector (our message/bitstrings) | |
std::string y_string = argv[1]; // "Lorem ipsum dolor sit..." | |
std::vector<uint8_t> y_vector(y_string.begin(), y_string.end()); | |
// make use of chaos machine (push/pull interface) | |
x_machine.message(y_vector); // push | |
std::vector<uint8_t> y_result = x_machine.digest(256); // pull | |
// print values in hexadecimal format | |
for (size_t i = 0; i < y_result.size(); i++) | |
printf("%02x", y_result[i]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment