egra: cosmetix, added brief comments for most interesting widget methods
[iv.d.git] / stc / salsa.d
blobaa85a9ea192e63a093942a51bb34e9a921189572
1 /*
2 * Salsa20 engine by D. J. Bernstein.
3 * Copyright (C) 2014 Ketmar Dark // Invisible Vector (ketmar@ketmar.no-ip.org)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * Get a copy of the GNU GPL from <http://www.gnu.org/licenses/>.
16 module iv.stc.salsa /*is aliced*/;
18 import std.range;
19 import iv.alice;
20 import iv.stc.core;
23 public struct Salsa20 {
24 // base stream cipher interface
25 mixin StreamCipherCore;
27 public:
28 // cipher parameters
29 enum BlockSize = 64;
30 enum IVSize = 8; // in bytes
31 enum KeySize = 32; // in bytes
32 enum SupportIV = true;
34 private:
35 enum sigma = "expand 32-byte k";
36 enum tau = "expand 16-byte k";
38 private:
39 void resetState(KR, IR) (KR key, IR iv) @trusted {
40 static if (hasLength!KR) assert(key.length == 16 || key.length == 32); else assert(!key.empty);
41 static if (hasLength!IR) assert(iv.length == 0 || iv.length == 8);
42 ubyte[KeySize] kb = void;
43 ubyte[] keybuf;
45 usize len = 0;
46 while (!key.empty && len < kb.length) {
47 kb.ptr[len++] = cast(ubyte)key.front;
48 key.popFront;
50 if (len != 16 && len != 32) key.popFront; // this should throw exception
51 keybuf = kb[0..len];
53 ubyte[IVSize] ib = void;
54 ubyte[] ivbuf;
56 usize len = 0;
57 while (!iv.empty && len < ib.length) {
58 ib.ptr[len++] = cast(ubyte)iv.front;
59 iv.popFront;
61 if (len && len != IVSize) iv.popFront; // this should throw exception
62 ivbuf = ib[0..IVSize];
64 // setup key
65 uint offset, n;
66 string constants;
67 if (keybuf.length == 32) {
68 constants = sigma;
69 offset = 16;
70 } else {
71 offset = 0;
72 constants = tau;
74 foreach (immutable i; 0..4) {
75 n = cast(ubyte)keybuf.ptr[i*4+3];
76 n = (n<<8)|cast(ubyte)keybuf.ptr[i*4+2];
77 n = (n<<8)|cast(ubyte)keybuf.ptr[i*4+1];
78 n = (n<<8)|cast(ubyte)keybuf.ptr[i*4];
79 state.ptr[i+1] = n;
80 n = cast(ubyte)keybuf.ptr[offset+i*4+3];
81 n = (n<<8)|cast(ubyte)keybuf.ptr[offset+i*4+2];
82 n = (n<<8)|cast(ubyte)keybuf.ptr[offset+i*4+1];
83 n = (n<<8)|cast(ubyte)keybuf.ptr[offset+i*4];
84 state.ptr[i+11] = n;
85 n = cast(ubyte)constants.ptr[i*4+3];
86 n = (n<<8)|cast(ubyte)constants.ptr[i*4+2];
87 n = (n<<8)|cast(ubyte)constants.ptr[i*4+1];
88 n = (n<<8)|cast(ubyte)constants.ptr[i*4];
89 state.ptr[i*5] = n;
90 // setup IV
91 if (ivbuf.length >= i*4+4) {
92 n = cast(ubyte)ivbuf.ptr[i*4+3];
93 n = (n<<8)|cast(ubyte)ivbuf.ptr[i*4+2];
94 n = (n<<8)|cast(ubyte)ivbuf.ptr[i*4+1];
95 n = (n<<8)|cast(ubyte)ivbuf.ptr[i*4];
96 } else {
97 n = 0;
99 state.ptr[i+6] = n;
103 void clearState () nothrow @trusted @nogc {
104 state[] = 0;
107 // output: 64 bytes
108 // input: 16 uints
109 static void nextState (ubyte[] output, const(uint)[] input) nothrow @trusted @nogc {
110 assert(output.length == 64);
111 assert(input.length == 16);
112 uint[16] x = input[0..16];
113 foreach (immutable i; 0..10) {
114 x.ptr[ 4] ^= bitRotLeft(x.ptr[ 0]+x.ptr[12], 7);
115 x.ptr[ 8] ^= bitRotLeft(x.ptr[ 4]+x.ptr[ 0], 9);
116 x.ptr[12] ^= bitRotLeft(x.ptr[ 8]+x.ptr[ 4],13);
117 x.ptr[ 0] ^= bitRotLeft(x.ptr[12]+x.ptr[ 8],18);
118 x.ptr[ 9] ^= bitRotLeft(x.ptr[ 5]+x.ptr[ 1], 7);
119 x.ptr[13] ^= bitRotLeft(x.ptr[ 9]+x.ptr[ 5], 9);
120 x.ptr[ 1] ^= bitRotLeft(x.ptr[13]+x.ptr[ 9],13);
121 x.ptr[ 5] ^= bitRotLeft(x.ptr[ 1]+x.ptr[13],18);
122 x.ptr[14] ^= bitRotLeft(x.ptr[10]+x.ptr[ 6], 7);
123 x.ptr[ 2] ^= bitRotLeft(x.ptr[14]+x.ptr[10], 9);
124 x.ptr[ 6] ^= bitRotLeft(x.ptr[ 2]+x.ptr[14],13);
125 x.ptr[10] ^= bitRotLeft(x.ptr[ 6]+x.ptr[ 2],18);
126 x.ptr[ 3] ^= bitRotLeft(x.ptr[15]+x.ptr[11], 7);
127 x.ptr[ 7] ^= bitRotLeft(x.ptr[ 3]+x.ptr[15], 9);
128 x.ptr[11] ^= bitRotLeft(x.ptr[ 7]+x.ptr[ 3],13);
129 x.ptr[15] ^= bitRotLeft(x.ptr[11]+x.ptr[ 7],18);
130 x.ptr[ 1] ^= bitRotLeft(x.ptr[ 0]+x.ptr[ 3], 7);
131 x.ptr[ 2] ^= bitRotLeft(x.ptr[ 1]+x.ptr[ 0], 9);
132 x.ptr[ 3] ^= bitRotLeft(x.ptr[ 2]+x.ptr[ 1],13);
133 x.ptr[ 0] ^= bitRotLeft(x.ptr[ 3]+x.ptr[ 2],18);
134 x.ptr[ 6] ^= bitRotLeft(x.ptr[ 5]+x.ptr[ 4], 7);
135 x.ptr[ 7] ^= bitRotLeft(x.ptr[ 6]+x.ptr[ 5], 9);
136 x.ptr[ 4] ^= bitRotLeft(x.ptr[ 7]+x.ptr[ 6],13);
137 x.ptr[ 5] ^= bitRotLeft(x.ptr[ 4]+x.ptr[ 7],18);
138 x.ptr[11] ^= bitRotLeft(x.ptr[10]+x.ptr[ 9], 7);
139 x.ptr[ 8] ^= bitRotLeft(x.ptr[11]+x.ptr[10], 9);
140 x.ptr[ 9] ^= bitRotLeft(x.ptr[ 8]+x.ptr[11],13);
141 x.ptr[10] ^= bitRotLeft(x.ptr[ 9]+x.ptr[ 8],18);
142 x.ptr[12] ^= bitRotLeft(x.ptr[15]+x.ptr[14], 7);
143 x.ptr[13] ^= bitRotLeft(x.ptr[12]+x.ptr[15], 9);
144 x.ptr[14] ^= bitRotLeft(x.ptr[13]+x.ptr[12],13);
145 x.ptr[15] ^= bitRotLeft(x.ptr[14]+x.ptr[13],18);
147 foreach (immutable i, ref n; x) n += input.ptr[i];
148 foreach (immutable i, uint n; x) {
149 output.ptr[i*4] = n&0xff;
150 output.ptr[i*4+1] = (n>>8)&0xff;
151 output.ptr[i*4+2] = (n>>16)&0xff;
152 output.ptr[i*4+3] = (n>>24)&0xff;
156 void getBuf () nothrow @trusted @nogc {
157 nextState(buf, state);
158 if (++state.ptr[8] == 0) ++state.ptr[9]; // stopping at 2^70 bytes per nonce is user's responsibility
161 private:
162 uint[16] state;
166 unittest {
167 import std.stdio;
168 import iv.stc.testing;
169 writeln("testing Salsa20...");
170 processTVFile!Salsa20(import("salsa-verified.test-vectors"));
171 writeln(count, " tests passed.");