1261287Sdes/*
2261287Sdeschacha-merged.c version 20080118
3261287SdesD. J. Bernstein
4261287SdesPublic domain.
5261287Sdes*/
6261287Sdes
7261287Sdes/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */
8261287Sdes
9261287Sdestypedef unsigned char u8;
10261287Sdestypedef unsigned int u32;
11261287Sdes
12261287Sdestypedef struct
13261287Sdes{
14261287Sdes  u32 input[16]; /* could be compressed */
15261287Sdes} chacha_ctx;
16261287Sdes
17261287Sdes#define U8C(v) (v##U)
18261287Sdes#define U32C(v) (v##U)
19261287Sdes
20261287Sdes#define U8V(v) ((u8)(v) & U8C(0xFF))
21261287Sdes#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
22261287Sdes
23261287Sdes#define ROTL32(v, n) \
24261287Sdes  (U32V((v) << (n)) | ((v) >> (32 - (n))))
25261287Sdes
26261287Sdes#define U8TO32_LITTLE(p) \
27261287Sdes  (((u32)((p)[0])      ) | \
28261287Sdes   ((u32)((p)[1]) <<  8) | \
29261287Sdes   ((u32)((p)[2]) << 16) | \
30261287Sdes   ((u32)((p)[3]) << 24))
31261287Sdes
32261287Sdes#define U32TO8_LITTLE(p, v) \
33261287Sdes  do { \
34261287Sdes    (p)[0] = U8V((v)      ); \
35261287Sdes    (p)[1] = U8V((v) >>  8); \
36261287Sdes    (p)[2] = U8V((v) >> 16); \
37261287Sdes    (p)[3] = U8V((v) >> 24); \
38261287Sdes  } while (0)
39261287Sdes
40261287Sdes#define ROTATE(v,c) (ROTL32(v,c))
41261287Sdes#define XOR(v,w) ((v) ^ (w))
42261287Sdes#define PLUS(v,w) (U32V((v) + (w)))
43261287Sdes#define PLUSONE(v) (PLUS((v),1))
44261287Sdes
45261287Sdes#define QUARTERROUND(a,b,c,d) \
46261287Sdes  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
47261287Sdes  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
48261287Sdes  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
49261287Sdes  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
50261287Sdes
51261287Sdesstatic const char sigma[16] = "expand 32-byte k";
52261287Sdesstatic const char tau[16] = "expand 16-byte k";
53261287Sdes
54261287Sdesstatic void
55261287Sdeschacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
56261287Sdes{
57261287Sdes  const char *constants;
58261287Sdes
59261287Sdes  x->input[4] = U8TO32_LITTLE(k + 0);
60261287Sdes  x->input[5] = U8TO32_LITTLE(k + 4);
61261287Sdes  x->input[6] = U8TO32_LITTLE(k + 8);
62261287Sdes  x->input[7] = U8TO32_LITTLE(k + 12);
63261287Sdes  if (kbits == 256) { /* recommended */
64261287Sdes    k += 16;
65261287Sdes    constants = sigma;
66261287Sdes  } else { /* kbits == 128 */
67261287Sdes    constants = tau;
68261287Sdes  }
69261287Sdes  x->input[8] = U8TO32_LITTLE(k + 0);
70261287Sdes  x->input[9] = U8TO32_LITTLE(k + 4);
71261287Sdes  x->input[10] = U8TO32_LITTLE(k + 8);
72261287Sdes  x->input[11] = U8TO32_LITTLE(k + 12);
73261287Sdes  x->input[0] = U8TO32_LITTLE(constants + 0);
74261287Sdes  x->input[1] = U8TO32_LITTLE(constants + 4);
75261287Sdes  x->input[2] = U8TO32_LITTLE(constants + 8);
76261287Sdes  x->input[3] = U8TO32_LITTLE(constants + 12);
77261287Sdes}
78261287Sdes
79261287Sdesstatic void
80261287Sdeschacha_ivsetup(chacha_ctx *x,const u8 *iv)
81261287Sdes{
82261287Sdes  x->input[12] = 0;
83261287Sdes  x->input[13] = 0;
84261287Sdes  x->input[14] = U8TO32_LITTLE(iv + 0);
85261287Sdes  x->input[15] = U8TO32_LITTLE(iv + 4);
86261287Sdes}
87261287Sdes
88261287Sdesstatic void
89261287Sdeschacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
90261287Sdes{
91261287Sdes  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
92261287Sdes  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
93261287Sdes  u8 *ctarget = NULL;
94261287Sdes  u8 tmp[64];
95261287Sdes  u_int i;
96261287Sdes
97261287Sdes  if (!bytes) return;
98261287Sdes
99261287Sdes  j0 = x->input[0];
100261287Sdes  j1 = x->input[1];
101261287Sdes  j2 = x->input[2];
102261287Sdes  j3 = x->input[3];
103261287Sdes  j4 = x->input[4];
104261287Sdes  j5 = x->input[5];
105261287Sdes  j6 = x->input[6];
106261287Sdes  j7 = x->input[7];
107261287Sdes  j8 = x->input[8];
108261287Sdes  j9 = x->input[9];
109261287Sdes  j10 = x->input[10];
110261287Sdes  j11 = x->input[11];
111261287Sdes  j12 = x->input[12];
112261287Sdes  j13 = x->input[13];
113261287Sdes  j14 = x->input[14];
114261287Sdes  j15 = x->input[15];
115261287Sdes
116261287Sdes  for (;;) {
117261287Sdes    if (bytes < 64) {
118261287Sdes      for (i = 0;i < bytes;++i) tmp[i] = m[i];
119261287Sdes      m = tmp;
120261287Sdes      ctarget = c;
121261287Sdes      c = tmp;
122261287Sdes    }
123261287Sdes    x0 = j0;
124261287Sdes    x1 = j1;
125261287Sdes    x2 = j2;
126261287Sdes    x3 = j3;
127261287Sdes    x4 = j4;
128261287Sdes    x5 = j5;
129261287Sdes    x6 = j6;
130261287Sdes    x7 = j7;
131261287Sdes    x8 = j8;
132261287Sdes    x9 = j9;
133261287Sdes    x10 = j10;
134261287Sdes    x11 = j11;
135261287Sdes    x12 = j12;
136261287Sdes    x13 = j13;
137261287Sdes    x14 = j14;
138261287Sdes    x15 = j15;
139261287Sdes    for (i = 20;i > 0;i -= 2) {
140261287Sdes      QUARTERROUND( x0, x4, x8,x12)
141261287Sdes      QUARTERROUND( x1, x5, x9,x13)
142261287Sdes      QUARTERROUND( x2, x6,x10,x14)
143261287Sdes      QUARTERROUND( x3, x7,x11,x15)
144261287Sdes      QUARTERROUND( x0, x5,x10,x15)
145261287Sdes      QUARTERROUND( x1, x6,x11,x12)
146261287Sdes      QUARTERROUND( x2, x7, x8,x13)
147261287Sdes      QUARTERROUND( x3, x4, x9,x14)
148261287Sdes    }
149261287Sdes    x0 = PLUS(x0,j0);
150261287Sdes    x1 = PLUS(x1,j1);
151261287Sdes    x2 = PLUS(x2,j2);
152261287Sdes    x3 = PLUS(x3,j3);
153261287Sdes    x4 = PLUS(x4,j4);
154261287Sdes    x5 = PLUS(x5,j5);
155261287Sdes    x6 = PLUS(x6,j6);
156261287Sdes    x7 = PLUS(x7,j7);
157261287Sdes    x8 = PLUS(x8,j8);
158261287Sdes    x9 = PLUS(x9,j9);
159261287Sdes    x10 = PLUS(x10,j10);
160261287Sdes    x11 = PLUS(x11,j11);
161261287Sdes    x12 = PLUS(x12,j12);
162261287Sdes    x13 = PLUS(x13,j13);
163261287Sdes    x14 = PLUS(x14,j14);
164261287Sdes    x15 = PLUS(x15,j15);
165261287Sdes
166261287Sdes#ifndef KEYSTREAM_ONLY
167261287Sdes    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
168261287Sdes    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
169261287Sdes    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
170261287Sdes    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
171261287Sdes    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
172261287Sdes    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
173261287Sdes    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
174261287Sdes    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
175261287Sdes    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
176261287Sdes    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
177261287Sdes    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
178261287Sdes    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
179261287Sdes    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
180261287Sdes    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
181261287Sdes    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
182261287Sdes    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
183261287Sdes#endif
184261287Sdes
185261287Sdes    j12 = PLUSONE(j12);
186261287Sdes    if (!j12) {
187261287Sdes      j13 = PLUSONE(j13);
188261287Sdes      /* stopping at 2^70 bytes per nonce is user's responsibility */
189261287Sdes    }
190261287Sdes
191261287Sdes    U32TO8_LITTLE(c + 0,x0);
192261287Sdes    U32TO8_LITTLE(c + 4,x1);
193261287Sdes    U32TO8_LITTLE(c + 8,x2);
194261287Sdes    U32TO8_LITTLE(c + 12,x3);
195261287Sdes    U32TO8_LITTLE(c + 16,x4);
196261287Sdes    U32TO8_LITTLE(c + 20,x5);
197261287Sdes    U32TO8_LITTLE(c + 24,x6);
198261287Sdes    U32TO8_LITTLE(c + 28,x7);
199261287Sdes    U32TO8_LITTLE(c + 32,x8);
200261287Sdes    U32TO8_LITTLE(c + 36,x9);
201261287Sdes    U32TO8_LITTLE(c + 40,x10);
202261287Sdes    U32TO8_LITTLE(c + 44,x11);
203261287Sdes    U32TO8_LITTLE(c + 48,x12);
204261287Sdes    U32TO8_LITTLE(c + 52,x13);
205261287Sdes    U32TO8_LITTLE(c + 56,x14);
206261287Sdes    U32TO8_LITTLE(c + 60,x15);
207261287Sdes
208261287Sdes    if (bytes <= 64) {
209261287Sdes      if (bytes < 64) {
210261287Sdes        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
211261287Sdes      }
212261287Sdes      x->input[12] = j12;
213261287Sdes      x->input[13] = j13;
214261287Sdes      return;
215261287Sdes    }
216261287Sdes    bytes -= 64;
217261287Sdes    c += 64;
218261287Sdes#ifndef KEYSTREAM_ONLY
219261287Sdes    m += 64;
220261287Sdes#endif
221261287Sdes  }
222261287Sdes}
223