optimized chacha20, added benchmark functionality, added some 'immutables'

This commit is contained in:
Johannes Loher 2016-07-06 02:00:03 +02:00
parent 0a9fef2cae
commit f6a718e331
6 changed files with 152 additions and 121 deletions

View file

@ -16,8 +16,8 @@ enum string randomDeviceName = "/dev/random";
void encrypt(string keyFileName, Cipher cipher, bool armor) void encrypt(string keyFileName, Cipher cipher, bool armor)
{ {
auto key = loadKey(keyFileName, armor); immutable key = loadKey(keyFileName, armor);
ubyte[8] nonce; immutable ubyte[8] nonce;
if (armor) if (armor)
{ {
ubyte[base64ChunkSize] buf; ubyte[base64ChunkSize] buf;
@ -61,9 +61,9 @@ void encrypt(string keyFileName, Cipher cipher, bool armor)
void decrypt(string keyFileName, Cipher cipher, bool armor) void decrypt(string keyFileName, Cipher cipher, bool armor)
{ {
import std.range; import std.range : inputRangeObject, InputRange;
auto key = loadKey(keyFileName, armor); immutable key = loadKey(keyFileName, armor);
ubyte[8] nonce; immutable ubyte[8] nonce;
ubyte[chunkSize] buf; ubyte[chunkSize] buf;
int counter; int counter;
InputRange!ubyte r; InputRange!ubyte r;
@ -110,6 +110,11 @@ void generateKey(bool armor)
} }
} }
void bench()
{
}
private: private:
ubyte[32] loadKey(string filename, bool armor) ubyte[32] loadKey(string filename, bool armor)

View file

@ -7,7 +7,7 @@ import actions;
int main(string[] args) int main(string[] args)
{ {
bool[string] actions = ["genKey" : false, "encrypt" : false, "decrypt" : false]; bool[string] actions = ["genKey" : false, "encrypt" : false, "decrypt" : false, "benchmark" : false];
Cipher cipher = Cipher.chacha20; Cipher cipher = Cipher.chacha20;
string keyFileName = "symkey.asc"; string keyFileName = "symkey.asc";
@ -20,6 +20,7 @@ int main(string[] args)
"Generate a new 256 bit key.", &actions["genKey"], "Generate a new 256 bit key.", &actions["genKey"],
"encrypt|e", "Encrypt a message.", &actions["encrypt"], "encrypt|e", "Encrypt a message.", &actions["encrypt"],
"decrypt|d", "Decrypt a message.", &actions["decrypt"], "decrypt|d", "Decrypt a message.", &actions["decrypt"],
"benchmark|b", "Perform some benchmarks.", &actions["benchmark"],
"cipher|c", "The cipher to use (default: %s).".format(cipher), &cipher, "key|k", "cipher|c", "The cipher to use (default: %s).".format(cipher), &cipher, "key|k",
"The file which contains the key (default: %s).".format(keyFileName), "The file which contains the key (default: %s).".format(keyFileName),
&keyFileName, "armor|a", "use ascii-armored I/O.", &armor); &keyFileName, "armor|a", "use ascii-armored I/O.", &armor);
@ -50,6 +51,10 @@ int main(string[] args)
{ {
decrypt(keyFileName, cipher, armor); decrypt(keyFileName, cipher, armor);
} }
else if (actions["benchmark"])
{
bench();
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -72,6 +77,6 @@ void printHelp(Option[] options)
{ {
defaultGetoptPrinter("Usage: ./learncrypt [options]\n\nCommon options:", options[$ - 1 .. $]); defaultGetoptPrinter("Usage: ./learncrypt [options]\n\nCommon options:", options[$ - 1 .. $]);
defaultGetoptPrinter("\nGlobal options:", options[$ - 2 .. $ - 1]); defaultGetoptPrinter("\nGlobal options:", options[$ - 2 .. $ - 1]);
defaultGetoptPrinter("\nActions:", options[0 .. 3]); defaultGetoptPrinter("\nActions:", options[0 .. 4]);
defaultGetoptPrinter("\nAction options:", options[3 .. 5]); defaultGetoptPrinter("\nAction options:", options[4 .. 5]);
} }

View file

@ -1,15 +1,21 @@
module chacha20; module chacha20;
private import std.string : format; private:
private import std.range : isInputRange, isForwardRange, ElementType;
private import std.array; import std.string : format;
import std.range : isInputRange, isForwardRange, ElementType;
import std.array;
import bitmanip;
import utility;
private import bitmanip;
public: public:
// TODO: Check unittests (Use reliable software to check if the results are correct) // TODO: Check unittests (Use reliable software to check if the results are correct)
// TODO: Implement random access
auto chacha20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce) auto chacha20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce)
if (isInputRange!R && is(ElementType!R : ubyte)) if (isInputRange!R && is(ElementType!R : ubyte))
{ {
@ -18,27 +24,26 @@ auto chacha20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce)
private: private:
ulong count; ulong count;
R range; R range;
ubyte[] chachaSection; ubyte[64] chachaSection;
uint chachaCounter;
public: public:
bool empty() @property bool empty() @property
{ {
return range.empty || (count == ulong.max && chachaSection.empty); return range.empty || (count == ulong.max && chachaCounter == 64);
} }
ubyte front() @property ubyte front() @property
{ {
assert(!empty); assert(!empty);
return range.front ^ chachaSection.front; return range.front ^ chachaSection[chachaCounter];
} }
void popFront() void popFront()
{ {
assert(!empty); assert(!empty);
chachaSection.popFront(); if (++chachaCounter == 64)
if (chachaSection.empty)
{ {
++count; chachaSection = chacha20Exp(key, concat!(ubyte[16])(nonce, littleEndianInv(++count)));
chachaSection = chacha20Exp(key, nonce ~ littleEndianInv(count));
} }
range.popFront(); range.popFront();
} }
@ -46,11 +51,25 @@ auto chacha20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce)
{ {
auto save() @property auto save() @property
{ {
return rangeResult(count, range.save, chachaSection.dup); return rangeResult(count, range.save, chachaSection);
} }
} }
} }
return rangeResult(0UL, range, chacha20Exp(key, nonce ~ littleEndianInv(0UL))); return rangeResult(0UL, range, chacha20Exp(key, concat!(ubyte[16])(nonce, littleEndianInv(0UL))));
}
// TODO: Create more unittests!!!
@safe unittest
{
ubyte[] test = new ubyte[64];
ubyte[32] key;
ubyte[8] nonce;
test = test.chacha20Cipher(key, nonce).array;
assert(test == [140,111, 5,175,106, 91,125,127, 60,125, 18, 49, 73, 47,186, 94,
234,193,178,253,211,130, 18, 77,243,176, 91,203,126, 83, 82,194,
77,251,230, 8,208,202, 74,201,254, 13,148,163, 20, 1,151,129,
168,147,213,247, 92, 23,242, 73,135, 68,217,123, 87,123,234,199]);
} }
private: private:
@ -63,7 +82,7 @@ enum string quarterRound(alias _x0, alias _x1, alias _x2, alias _x3) = q{
}.format(__traits(identifier, _x0), __traits(identifier, _x1), }.format(__traits(identifier, _x0), __traits(identifier, _x1),
__traits(identifier, _x2), __traits(identifier, _x3)); __traits(identifier, _x2), __traits(identifier, _x3));
unittest @safe unittest
{ {
uint a1 = 0x00000000, a2 = 0x00000000, a3 = 0x00000000, a4 = 0x00000000, uint a1 = 0x00000000, a2 = 0x00000000, a3 = 0x00000000, a4 = 0x00000000,
b1 = 0x00000001, b2 = 0x00000000, b3 = 0x00000000, b4 = 0x00000000, b1 = 0x00000001, b2 = 0x00000000, b3 = 0x00000000, b4 = 0x00000000,
@ -107,7 +126,7 @@ enum string rowRound(alias _x00, alias _x01, alias _x02, alias _x03,
__traits(identifier, _x12), __traits(identifier, _x13), __traits(identifier, _x12), __traits(identifier, _x13),
__traits(identifier, _x14), __traits(identifier, _x15)); __traits(identifier, _x14), __traits(identifier, _x15));
unittest @safe unittest
{ {
uint y00 = 0x00000001, y01 = 0x00000000, y02 = 0x00000000, y03 = 0x00000000, uint y00 = 0x00000001, y01 = 0x00000000, y02 = 0x00000000, y03 = 0x00000000,
y04 = 0x00000001, y05 = 0x00000000, y06 = 0x00000000, y07 = 0x00000000, y04 = 0x00000001, y05 = 0x00000000, y06 = 0x00000000, y07 = 0x00000000,
@ -125,10 +144,10 @@ unittest
mixin(rowRound!(x00, x01, x02, x03, x04, x05, x06, x07, mixin(rowRound!(x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15)); x08, x09, x10, x11, x12, x13, x14, x15));
uint[] test0 = [y00, y01, y02, y03, y04, y05, y06, y07, immutable uint[16] test0 = [y00, y01, y02, y03, y04, y05, y06, y07,
y08, y09, y10, y11, y12, y13, y14, y15]; y08, y09, y10, y11, y12, y13, y14, y15];
uint[] test1 = [x00, x01, x02, x03, x04, x05, x06, x07, immutable uint[16] test1 = [x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15]; x08, x09, x10, x11, x12, x13, x14, x15];
assert(test0 == [0x10000001, 0x10000000, 0x00001000, 0x10001001, assert(test0 == [0x10000001, 0x10000000, 0x00001000, 0x10001001,
@ -159,7 +178,7 @@ enum string colRound(alias _x00, alias _x01, alias _x02, alias _x03,
__traits(identifier, _x12), __traits(identifier, _x13), __traits(identifier, _x12), __traits(identifier, _x13),
__traits(identifier, _x14), __traits(identifier, _x15)); __traits(identifier, _x14), __traits(identifier, _x15));
unittest{ @safe unittest{
uint y00 = 0x00000001, y01 = 0x00000000, y02 = 0x00000000, y03 = 0x00000000, uint y00 = 0x00000001, y01 = 0x00000000, y02 = 0x00000000, y03 = 0x00000000,
y04 = 0x00000001, y05 = 0x00000000, y06 = 0x00000000, y07 = 0x00000000, y04 = 0x00000001, y05 = 0x00000000, y06 = 0x00000000, y07 = 0x00000000,
y08 = 0x00000001, y09 = 0x00000000, y10 = 0x00000000, y11 = 0x00000000, y08 = 0x00000001, y09 = 0x00000000, y10 = 0x00000000, y11 = 0x00000000,
@ -177,10 +196,10 @@ unittest{
mixin(colRound!(x00, x01, x02, x03, x04, x05, x06, x07, mixin(colRound!(x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15)); x08, x09, x10, x11, x12, x13, x14, x15));
uint[] test0 = [y00, y01, y02, y03, y04, y05, y06, y07, immutable uint[16] test0 = [y00, y01, y02, y03, y04, y05, y06, y07,
y08, y09, y10, y11, y12, y13, y14, y15]; y08, y09, y10, y11, y12, y13, y14, y15];
uint[] test1 = [x00, x01, x02, x03, x04, x05, x06, x07, immutable uint[16] test1 = [x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15]; x08, x09, x10, x11, x12, x13, x14, x15];
assert(test0 == [0x30000002, 0x00000000, 0x00000000, 0x00000000, assert(test0 == [0x30000002, 0x00000000, 0x00000000, 0x00000000,
@ -194,16 +213,7 @@ unittest{
0xf5529d13, 0xfbee0de7, 0x7c5c8c13, 0x9c847b82]); 0xf5529d13, 0xfbee0de7, 0x7c5c8c13, 0x9c847b82]);
} }
ubyte[] chacha20(in ubyte[] input) @safe nothrow pure ubyte[64] chacha20(in ubyte[64] input) @safe nothrow pure @nogc
in
{
assert(input.length == 64);
}
out(result)
{
assert(result.length == 64);
}
body
{ {
auto x00 = littleEndian(input[00..04]), x01 = littleEndian(input[04..08]), auto x00 = littleEndian(input[00..04]), x01 = littleEndian(input[04..08]),
x02 = littleEndian(input[08..12]), x03 = littleEndian(input[12..16]), x02 = littleEndian(input[08..12]), x03 = littleEndian(input[12..16]),
@ -228,41 +238,49 @@ body
x08, x09, x10, x11, x12, x13, x14, x15)); x08, x09, x10, x11, x12, x13, x14, x15));
} }
return littleEndianInv(x00 + y00) ~ littleEndianInv(x01 + y01) ~ return concat!(ubyte[64])(littleEndianInv(x00 + y00),
littleEndianInv(x02 + y02) ~ littleEndianInv(x03 + y03) ~ littleEndianInv(x01 + y01),
littleEndianInv(x04 + y04) ~ littleEndianInv(x05 + y05) ~ littleEndianInv(x02 + y02),
littleEndianInv(x06 + y06) ~ littleEndianInv(x07 + y07) ~ littleEndianInv(x03 + y03),
littleEndianInv(x08 + y08) ~ littleEndianInv(x09 + y09) ~ littleEndianInv(x04 + y04),
littleEndianInv(x10 + y10) ~ littleEndianInv(x11 + y11) ~ littleEndianInv(x05 + y05),
littleEndianInv(x12 + y12) ~ littleEndianInv(x13 + y13) ~ littleEndianInv(x06 + y06),
littleEndianInv(x14 + y14) ~ littleEndianInv(x15 + y15); littleEndianInv(x07 + y07),
littleEndianInv(x08 + y08),
littleEndianInv(x09 + y09),
littleEndianInv(x10 + y10),
littleEndianInv(x11 + y11),
littleEndianInv(x12 + y12),
littleEndianInv(x13 + y13),
littleEndianInv(x14 + y14),
littleEndianInv(x15 + y15));
} }
unittest @safe unittest
{ {
ubyte[] test0 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ubyte[64] test0 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
test0 = chacha20(test0); test0 = chacha20(test0);
ubyte[] test1 = [211,159, 13,115, 76, 55, 82,183, 3,117,222, 37,191,187,234,136, ubyte[64] test1 = [211,159, 13,115, 76, 55, 82,183, 3,117,222, 37,191,187,234,136,
49,237,179, 48, 1,106,178,219,175,199,166, 48, 86, 16,179,207, 49,237,179, 48, 1,106,178,219,175,199,166, 48, 86, 16,179,207,
31,240, 32, 63, 15, 83, 93,161,116,147, 48,113,238, 55,204, 36, 31,240, 32, 63, 15, 83, 93,161,116,147, 48,113,238, 55,204, 36,
79,201,235, 79, 3, 81,156, 47,203, 26,244,243, 88,118,104, 54]; 79,201,235, 79, 3, 81,156, 47,203, 26,244,243, 88,118,104, 54];
test1 = chacha20(test1); test1 = chacha20(test1);
ubyte[] test2 = [ 88,118,104, 54, 79,201,235, 79, 3, 81,156, 47,203, 26,244,243, ubyte[64] test2 = [ 88,118,104, 54, 79,201,235, 79, 3, 81,156, 47,203, 26,244,243,
191,187,234,136,211,159, 13,115, 76, 55, 82,183, 3,117,222, 37, 191,187,234,136,211,159, 13,115, 76, 55, 82,183, 3,117,222, 37,
86, 16,179,207, 49,237,179, 48, 1,106,178,219,175,199,166, 48, 86, 16,179,207, 49,237,179, 48, 1,106,178,219,175,199,166, 48,
238, 55,204, 36, 31,240, 32, 63, 15, 83, 93,161,116,147, 48,113]; 238, 55,204, 36, 31,240, 32, 63, 15, 83, 93,161,116,147, 48,113];
test2 = chacha20(test2); test2 = chacha20(test2);
ubyte[] test3 = [ 6,124, 83,146, 38,191, 9, 50, 4,161, 47,222,122,182,223,185, ubyte[64] test3 = [ 6,124, 83,146, 38,191, 9, 50, 4,161, 47,222,122,182,223,185,
75, 27, 0,216, 16,122, 7, 89,162,104,101,147,213, 21, 54, 95, 75, 27, 0,216, 16,122, 7, 89,162,104,101,147,213, 21, 54, 95,
225,253,139,176,105,132, 23,116, 76, 41,176,207,221, 34,157,108, 225,253,139,176,105,132, 23,116, 76, 41,176,207,221, 34,157,108,
94, 94, 99, 52, 90,117, 91,220,146,190,239,143,196,176,130,186]; 94, 94, 99, 52, 90,117, 91,220,146,190,239,143,196,176,130,186];
foreach (i; 0..1000000) foreach (i; 0..1_000_000)
test3 = chacha20(test3); test3 = chacha20(test3);
assert(test0 == [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, assert(test0 == [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -286,39 +304,32 @@ unittest
29,214,235,224, 96, 42, 55, 53,188, 35, 81,171, 81,218,221, 44]); 29,214,235,224, 96, 42, 55, 53,188, 35, 81,171, 81,218,221, 44]);
} }
enum ubyte[4] σ0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma0 = [101, 120, 112, 97];
enum ubyte[4] σ1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51];
enum ubyte[4] σ2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121];
enum ubyte[4] σ3 = [116, 101, 32, 107]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107];
ubyte[64] chacha20Exp(in ubyte[32] key, in ubyte[16] n) @safe pure nothrow @nogc
ubyte[] chacha20Exp(in ubyte[] key, in ubyte[] n) @safe nothrow pure
in
{ {
assert(key.length == 32); return chacha20(concat!(ubyte[64])(sigma0,
assert(n.length == 16); key[0..16],
} sigma1,
out(result) n,
{ sigma2,
assert(result.length == 64); key[16..$],
} sigma3));
body
{
return chacha20(σ0 ~ key[0..16] ~ σ1 ~ n ~ σ2 ~ key[16..$] ~ σ3);
} }
unittest @safe unittest
{ {
ubyte[] key; immutable ubyte[32] key = [ 1, 2, 3, 4, 5, 6, 7, 8,
ubyte[] n; 9, 10, 11, 12, 13, 14, 15, 16,
key.length = 32; 201,202,203,204,205,206,207,208,
n.length = 16; 209,210,211,212,213,214,215,216];
foreach (i; 0..16)
key[i] = cast(ubyte)(i + 1);
foreach (i; 16..32)
key[i] = cast(ubyte)(i + 200 - 15);
foreach (i; 0..16) immutable ubyte[16] n = [101,102,103,104,105,106,107,108,
n[i] = cast(ubyte)(i + 1+ 100); 109,110,111,112,113,114,115,116];
assert(chacha20Exp(key, n) == [ 2, 7, 55,183,240,232, 0,145,207,208,120,131,146, 9,130, 31, assert(chacha20Exp(key, n) == [ 2, 7, 55,183,240,232, 0,145,207,208,120,131,146, 9,130, 31,
99,154, 60, 98,194,161,191, 80,167, 61,100,101,173,193, 48,203, 99,154, 60, 98,194,161,191, 80,167, 61,100,101,173,193, 48,203,

View file

@ -1,13 +1,13 @@
module cipher; module cipher;
private import std.range : isInputRange, isForwardRange, ElementType, private:
import std.range : isInputRange, isForwardRange, ElementType,
InputRange, ForwardRange, inputRangeObject; InputRange, ForwardRange, inputRangeObject;
import std.string : format;
private import std.string : format; import salsa20;
import chacha20;
private import salsa20;
private import chacha20;
public: public:

View file

@ -41,7 +41,6 @@ auto salsa20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce)
assert(!empty); assert(!empty);
if (++salsaCounter == 64) if (++salsaCounter == 64)
{ {
import std.stdio;
salsaSection = salsa20Exp(key, concat!(ubyte[16])(nonce, littleEndianInv(++count))); salsaSection = salsa20Exp(key, concat!(ubyte[16])(nonce, littleEndianInv(++count)));
salsaCounter = 0; salsaCounter = 0;
} }
@ -58,7 +57,7 @@ auto salsa20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce)
return rangeResult(0UL, range, salsa20Exp(key, concat!(ubyte[16])(nonce, littleEndianInv(0UL)))); return rangeResult(0UL, range, salsa20Exp(key, concat!(ubyte[16])(nonce, littleEndianInv(0UL))));
} }
// TODO: Create more unittest!!! // TODO: Create more unittests!!!
@safe unittest @safe unittest
{ {
@ -144,10 +143,10 @@ enum string rowRound(alias _x00, alias _x01, alias _x02, alias _x03,
mixin(rowRound!(x00, x01, x02, x03, x04, x05, x06, x07, mixin(rowRound!(x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15)); x08, x09, x10, x11, x12, x13, x14, x15));
uint[] test0 = [y00, y01, y02, y03, y04, y05, y06, y07, immutable uint[16] test0 = [y00, y01, y02, y03, y04, y05, y06, y07,
y08, y09, y10, y11, y12, y13, y14, y15]; y08, y09, y10, y11, y12, y13, y14, y15];
uint[] test1 = [x00, x01, x02, x03, x04, x05, x06, x07, immutable uint[16] test1 = [x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15]; x08, x09, x10, x11, x12, x13, x14, x15];
assert(test0 == [0x08008145, 0x00000080, 0x00010200, 0x20500000, assert(test0 == [0x08008145, 0x00000080, 0x00010200, 0x20500000,
@ -197,10 +196,10 @@ enum string colRound(alias _x00, alias _x01, alias _x02, alias _x03,
mixin(colRound!(x00, x01, x02, x03, x04, x05, x06, x07, mixin(colRound!(x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15)); x08, x09, x10, x11, x12, x13, x14, x15));
immutable uint[] test0 = [y00, y01, y02, y03, y04, y05, y06, y07, immutable uint[16] test0 = [y00, y01, y02, y03, y04, y05, y06, y07,
y08, y09, y10, y11, y12, y13, y14, y15]; y08, y09, y10, y11, y12, y13, y14, y15];
immutable uint[] test1 = [x00, x01, x02, x03, x04, x05, x06, x07, immutable uint[16] test1 = [x00, x01, x02, x03, x04, x05, x06, x07,
x08, x09, x10, x11, x12, x13, x14, x15]; x08, x09, x10, x11, x12, x13, x14, x15];
assert(test0 == [0x10090288, 0x00000000, 0x00000000, 0x00000000, assert(test0 == [0x10090288, 0x00000000, 0x00000000, 0x00000000,
@ -281,7 +280,7 @@ ubyte[64] salsa20(in ubyte[64] input) pure nothrow @safe @nogc
75, 27, 0,216, 16,122, 7, 89,162,104,101,147,213, 21, 54, 95, 75, 27, 0,216, 16,122, 7, 89,162,104,101,147,213, 21, 54, 95,
225,253,139,176,105,132, 23,116, 76, 41,176,207,221, 34,157,108, 225,253,139,176,105,132, 23,116, 76, 41,176,207,221, 34,157,108,
94, 94, 99, 52, 90,117, 91,220,146,190,239,143,196,176,130,186]; 94, 94, 99, 52, 90,117, 91,220,146,190,239,143,196,176,130,186];
foreach (i; 0..1000000) foreach (i; 0..1_000_000)
test3 = salsa20(test3); test3 = salsa20(test3);
assert(test0 == [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, assert(test0 == [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -310,7 +309,7 @@ static immutable ubyte[4] sigma1 = [110, 100, 32, 51];
static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121];
static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107];
ubyte[64] salsa20Exp(in ubyte[32] key, in ubyte[16] n) @safe pure nothrow @nogc ubyte[64] salsa20Exp(in ref ubyte[32] key, in ubyte[16] n) @safe pure nothrow @nogc
{ {
return salsa20(concat!(ubyte[64])(sigma0, return salsa20(concat!(ubyte[64])(sigma0,
key[0..16], key[0..16],
@ -323,15 +322,13 @@ ubyte[64] salsa20Exp(in ubyte[32] key, in ubyte[16] n) @safe pure nothrow @nogc
@safe unittest @safe unittest
{ {
ubyte[32] key; immutable ubyte[32] key = [ 1, 2, 3, 4, 5, 6, 7, 8,
ubyte[16] n; 9, 10, 11, 12, 13, 14, 15, 16,
foreach (i; 0..16) 201,202,203,204,205,206,207,208,
key[i] = cast(ubyte)(i + 1); 209,210,211,212,213,214,215,216];
foreach (i; 16..32)
key[i] = cast(ubyte)(i + 200 - 15);
foreach (i; 0..16) immutable ubyte[16] n = [101,102,103,104,105,106,107,108,
n[i] = cast(ubyte)(i + 1 + 100); 109,110,111,112,113,114,115,116];
assert(salsa20Exp(key, n) == [ 69, 37, 68, 39, 41, 15,107,193,255,139,122, 6,170,233,217, 98, assert(salsa20Exp(key, n) == [ 69, 37, 68, 39, 41, 15,107,193,255,139,122, 6,170,233,217, 98,
89,144,182,106, 21, 51,200, 65,239, 49,222, 34,215,114, 40,126, 89,144,182,106, 21, 51,200, 65,239, 49,222, 34,215,114, 40,126,

View file

@ -12,3 +12,16 @@ auto concat(T : E[n], E, size_t n)(in E[][] args...) @nogc
return result; return result;
} }
@safe unittest
{
assert(concat!(int[0])() == []);
assert(concat!(int[0])([]) == []);
assert(concat!(int[0])([], []) == []);
assert(concat!(int[1])([1]) == [1]);
assert(concat!(int[1])([1], []) == [1]);
assert(concat!(int[1])([], [1]) == [1]);
assert(concat!(int[2])([1, 2]) == [1, 2]);
assert(concat!(int[2])([1], [2]) == [1, 2]);
assert(concat!(int[6])([1], [2, 3], [4, 5, 6]) == [1, 2, 3, 4, 5, 6]);
assert(concat!(char[12])("Hello", " ", "World!") == "Hello World!");
}