egra: even more comments
[iv.d.git] / stc / chacha8.d
blobe29f88e4afd9dcd1e7c812931d52fcefbcdee310
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.chacha8 /*is aliced*/;
18 import std.range;
19 import iv.alice;
20 import iv.stc.core;
23 public struct ChaCha8 {
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 assert(IVSize == 8);
41 static if (hasLength!KR) assert(key.length == 16 || key.length == 32); else assert(!key.empty);
42 static if (hasLength!IR) assert(iv.length == 0 || iv.length == 8);
43 ubyte[KeySize] kb = 0;
44 ubyte[] keybuf;
46 usize len = 0;
47 while (!key.empty && len < kb.length) {
48 kb.ptr[len++] = cast(ubyte)key.front;
49 key.popFront;
51 if (len != 16 && len != 32) key.popFront; // this should throw exception
52 keybuf = kb[0..len];
54 ubyte[IVSize] ib = 0;
55 ubyte[] ivbuf;
57 usize len = 0;
58 while (!iv.empty && len < ib.length) {
59 ib.ptr[len++] = cast(ubyte)iv.front;
60 iv.popFront;
62 if (len && len != IVSize) iv.popFront; // this should throw exception
63 ivbuf = ib[0..len];
66 static uint U8TO32_LITTLE (const(ubyte)* n) nothrow @trusted @nogc {
67 uint res = 0;
68 res |= cast(uint)n[0];
69 res |= cast(uint)n[1]<<8;
70 res |= cast(uint)n[2]<<16;
71 res |= cast(uint)n[3]<<24;
72 return res;
75 // setup key
76 state.ptr[4] = U8TO32_LITTLE(kb.ptr+0);
77 state.ptr[5] = U8TO32_LITTLE(kb.ptr+4);
78 state.ptr[6] = U8TO32_LITTLE(kb.ptr+8);
79 state.ptr[7] = U8TO32_LITTLE(kb.ptr+12);
80 uint ofs = 0;
81 string constants;
82 if (keybuf.length == 32) {
83 /* recommended */
84 ofs = 16;
85 constants = sigma;
86 } else {
87 /* kbits == 128 */
88 constants = tau;
90 state.ptr[8] = U8TO32_LITTLE(kb.ptr+ofs+0);
91 state.ptr[9] = U8TO32_LITTLE(kb.ptr+ofs+4);
92 state.ptr[10] = U8TO32_LITTLE(kb.ptr+ofs+8);
93 state.ptr[11] = U8TO32_LITTLE(kb.ptr+ofs+12);
94 state.ptr[0] = U8TO32_LITTLE(cast(immutable(ubyte*))constants.ptr+0);
95 state.ptr[1] = U8TO32_LITTLE(cast(immutable(ubyte*))constants.ptr+4);
96 state.ptr[2] = U8TO32_LITTLE(cast(immutable(ubyte*))constants.ptr+8);
97 state.ptr[3] = U8TO32_LITTLE(cast(immutable(ubyte*))constants.ptr+12);
99 // setup iv
100 state.ptr[12] = 0;
101 state.ptr[13] = 0;
102 if (ivbuf.length >= 4) state.ptr[14] = U8TO32_LITTLE(ivbuf.ptr+0);
103 if (ivbuf.length >= 8) state.ptr[15] = U8TO32_LITTLE(ivbuf.ptr+4);
106 void clearState () nothrow @trusted @nogc {
107 state[] = 0;
110 // output: 64 bytes
111 // input: 16 uints
112 static void nextState (ubyte[] output, const(uint)[] input) nothrow @trusted @nogc {
113 assert(output.length == 64);
114 assert(input.length == 16);
116 enum QUARTERROUND(int a, int b, int c, int d) =
117 "x.ptr["~a.stringof~"] = cast(uint)x.ptr["~a.stringof~"]+x.ptr["~b.stringof~"]; x.ptr["~d.stringof~"] = bitRotLeft(x.ptr["~d.stringof~"]^x.ptr["~a.stringof~"],16);\n"~
118 "x.ptr["~c.stringof~"] = cast(uint)x.ptr["~c.stringof~"]+x.ptr["~d.stringof~"]; x.ptr["~b.stringof~"] = bitRotLeft(x.ptr["~b.stringof~"]^x.ptr["~c.stringof~"],12);\n"~
119 "x.ptr["~a.stringof~"] = cast(uint)x.ptr["~a.stringof~"]+x.ptr["~b.stringof~"]; x.ptr["~d.stringof~"] = bitRotLeft(x.ptr["~d.stringof~"]^x.ptr["~a.stringof~"], 8);\n"~
120 "x.ptr["~c.stringof~"] = cast(uint)x.ptr["~c.stringof~"]+x.ptr["~d.stringof~"]; x.ptr["~b.stringof~"] = bitRotLeft(x.ptr["~b.stringof~"]^x.ptr["~c.stringof~"], 7);\n";
122 uint[16] x = input[0..16];
124 for (int i = 8; i > 0; i -= 2) {
125 mixin(QUARTERROUND!( 0, 4, 8,12));
126 mixin(QUARTERROUND!( 1, 5, 9,13));
127 mixin(QUARTERROUND!( 2, 6,10,14));
128 mixin(QUARTERROUND!( 3, 7,11,15));
129 mixin(QUARTERROUND!( 0, 5,10,15));
130 mixin(QUARTERROUND!( 1, 6,11,12));
131 mixin(QUARTERROUND!( 2, 7, 8,13));
132 mixin(QUARTERROUND!( 3, 4, 9,14));
135 foreach (immutable i, ref n; x) n += input.ptr[i];
136 foreach (immutable i, uint n; x) {
137 output.ptr[i*4] = n&0xff;
138 output.ptr[i*4+1] = (n>>8)&0xff;
139 output.ptr[i*4+2] = (n>>16)&0xff;
140 output.ptr[i*4+3] = (n>>24)&0xff;
144 void getBuf () nothrow @trusted @nogc {
145 nextState(buf, state);
146 if (++state.ptr[12] == 0) ++state.ptr[13]; // stopping at 2^70 bytes per nonce is user's responsibility
149 public @property uint[16] getState () nothrow @trusted @nogc { return state[]; }
151 private:
152 uint[16] state;