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*/;
23 public struct Salsa20
{
24 // base stream cipher interface
25 mixin StreamCipherCore
;
30 enum IVSize
= 8; // in bytes
31 enum KeySize
= 32; // in bytes
32 enum SupportIV
= true;
35 enum sigma
= "expand 32-byte k";
36 enum tau
= "expand 16-byte k";
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;
46 while (!key
.empty
&& len
< kb
.length
) {
47 kb
.ptr
[len
++] = cast(ubyte)key
.front
;
50 if (len
!= 16 && len
!= 32) key
.popFront
; // this should throw exception
53 ubyte[IVSize
] ib
= void;
57 while (!iv
.empty
&& len
< ib
.length
) {
58 ib
.ptr
[len
++] = cast(ubyte)iv
.front
;
61 if (len
&& len
!= IVSize
) iv
.popFront
; // this should throw exception
62 ivbuf
= ib
[0..IVSize
];
67 if (keybuf
.length
== 32) {
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];
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];
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];
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];
103 void clearState () nothrow @trusted @nogc {
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
168 import iv
.stc.testing
;
169 writeln("testing Salsa20...");
170 processTVFile
!Salsa20(import("salsa-verified.test-vectors"));
171 writeln(count
, " tests passed.");