1276541Sdes/*
2276541Sdeschacha-merged.c version 20080118
3276541SdesD. J. Bernstein
4276541SdesPublic domain.
5276541Sdes*/
6276541Sdes
7276541Sdes/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */
8276541Sdes
9276541Sdestypedef unsigned char u8;
10276541Sdestypedef unsigned int u32;
11276541Sdes
12276541Sdestypedef struct
13276541Sdes{
14276541Sdes  u32 input[16]; /* could be compressed */
15276541Sdes} chacha_ctx;
16276541Sdes
17276541Sdes#define U8C(v) (v##U)
18276541Sdes#define U32C(v) (v##U)
19276541Sdes
20276541Sdes#define U8V(v) ((u8)(v) & U8C(0xFF))
21276541Sdes#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
22276541Sdes
23276541Sdes#define ROTL32(v, n) \
24276541Sdes  (U32V((v) << (n)) | ((v) >> (32 - (n))))
25276541Sdes
26276541Sdes#define U8TO32_LITTLE(p) \
27276541Sdes  (((u32)((p)[0])      ) | \
28276541Sdes   ((u32)((p)[1]) <<  8) | \
29276541Sdes   ((u32)((p)[2]) << 16) | \
30276541Sdes   ((u32)((p)[3]) << 24))
31276541Sdes
32276541Sdes#define U32TO8_LITTLE(p, v) \
33276541Sdes  do { \
34276541Sdes    (p)[0] = U8V((v)      ); \
35276541Sdes    (p)[1] = U8V((v) >>  8); \
36276541Sdes    (p)[2] = U8V((v) >> 16); \
37276541Sdes    (p)[3] = U8V((v) >> 24); \
38276541Sdes  } while (0)
39276541Sdes
40276541Sdes#define ROTATE(v,c) (ROTL32(v,c))
41276541Sdes#define XOR(v,w) ((v) ^ (w))
42276541Sdes#define PLUS(v,w) (U32V((v) + (w)))
43276541Sdes#define PLUSONE(v) (PLUS((v),1))
44276541Sdes
45276541Sdes#define QUARTERROUND(a,b,c,d) \
46276541Sdes  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
47276541Sdes  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
48276541Sdes  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
49276541Sdes  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
50276541Sdes
51276541Sdesstatic const char sigma[16] = "expand 32-byte k";
52276541Sdesstatic const char tau[16] = "expand 16-byte k";
53276541Sdes
54276541Sdesstatic void
55276541Sdeschacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits))
56276541Sdes{
57276541Sdes  const char *constants;
58276541Sdes
59276541Sdes  x->input[4] = U8TO32_LITTLE(k + 0);
60276541Sdes  x->input[5] = U8TO32_LITTLE(k + 4);
61276541Sdes  x->input[6] = U8TO32_LITTLE(k + 8);
62276541Sdes  x->input[7] = U8TO32_LITTLE(k + 12);
63276541Sdes  if (kbits == 256) { /* recommended */
64276541Sdes    k += 16;
65276541Sdes    constants = sigma;
66276541Sdes  } else { /* kbits == 128 */
67276541Sdes    constants = tau;
68276541Sdes  }
69276541Sdes  x->input[8] = U8TO32_LITTLE(k + 0);
70276541Sdes  x->input[9] = U8TO32_LITTLE(k + 4);
71276541Sdes  x->input[10] = U8TO32_LITTLE(k + 8);
72276541Sdes  x->input[11] = U8TO32_LITTLE(k + 12);
73276541Sdes  x->input[0] = U8TO32_LITTLE(constants + 0);
74276541Sdes  x->input[1] = U8TO32_LITTLE(constants + 4);
75276541Sdes  x->input[2] = U8TO32_LITTLE(constants + 8);
76276541Sdes  x->input[3] = U8TO32_LITTLE(constants + 12);
77276541Sdes}
78276541Sdes
79276541Sdesstatic void
80276541Sdeschacha_ivsetup(chacha_ctx *x,const u8 *iv)
81276541Sdes{
82276541Sdes  x->input[12] = 0;
83276541Sdes  x->input[13] = 0;
84276541Sdes  x->input[14] = U8TO32_LITTLE(iv + 0);
85276541Sdes  x->input[15] = U8TO32_LITTLE(iv + 4);
86276541Sdes}
87276541Sdes
88276541Sdesstatic void
89276541Sdeschacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
90276541Sdes{
91276541Sdes  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
92276541Sdes  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
93276541Sdes  u8 *ctarget = NULL;
94276541Sdes  u8 tmp[64];
95276541Sdes  u_int i;
96276541Sdes
97276541Sdes  if (!bytes) return;
98276541Sdes
99276541Sdes  j0 = x->input[0];
100276541Sdes  j1 = x->input[1];
101276541Sdes  j2 = x->input[2];
102276541Sdes  j3 = x->input[3];
103276541Sdes  j4 = x->input[4];
104276541Sdes  j5 = x->input[5];
105276541Sdes  j6 = x->input[6];
106276541Sdes  j7 = x->input[7];
107276541Sdes  j8 = x->input[8];
108276541Sdes  j9 = x->input[9];
109276541Sdes  j10 = x->input[10];
110276541Sdes  j11 = x->input[11];
111276541Sdes  j12 = x->input[12];
112276541Sdes  j13 = x->input[13];
113276541Sdes  j14 = x->input[14];
114276541Sdes  j15 = x->input[15];
115276541Sdes
116276541Sdes  for (;;) {
117276541Sdes    if (bytes < 64) {
118276541Sdes      for (i = 0;i < bytes;++i) tmp[i] = m[i];
119276541Sdes      m = tmp;
120276541Sdes      ctarget = c;
121276541Sdes      c = tmp;
122276541Sdes    }
123276541Sdes    x0 = j0;
124276541Sdes    x1 = j1;
125276541Sdes    x2 = j2;
126276541Sdes    x3 = j3;
127276541Sdes    x4 = j4;
128276541Sdes    x5 = j5;
129276541Sdes    x6 = j6;
130276541Sdes    x7 = j7;
131276541Sdes    x8 = j8;
132276541Sdes    x9 = j9;
133276541Sdes    x10 = j10;
134276541Sdes    x11 = j11;
135276541Sdes    x12 = j12;
136276541Sdes    x13 = j13;
137276541Sdes    x14 = j14;
138276541Sdes    x15 = j15;
139276541Sdes    for (i = 20;i > 0;i -= 2) {
140276541Sdes      QUARTERROUND( x0, x4, x8,x12)
141276541Sdes      QUARTERROUND( x1, x5, x9,x13)
142276541Sdes      QUARTERROUND( x2, x6,x10,x14)
143276541Sdes      QUARTERROUND( x3, x7,x11,x15)
144276541Sdes      QUARTERROUND( x0, x5,x10,x15)
145276541Sdes      QUARTERROUND( x1, x6,x11,x12)
146276541Sdes      QUARTERROUND( x2, x7, x8,x13)
147276541Sdes      QUARTERROUND( x3, x4, x9,x14)
148276541Sdes    }
149276541Sdes    x0 = PLUS(x0,j0);
150276541Sdes    x1 = PLUS(x1,j1);
151276541Sdes    x2 = PLUS(x2,j2);
152276541Sdes    x3 = PLUS(x3,j3);
153276541Sdes    x4 = PLUS(x4,j4);
154276541Sdes    x5 = PLUS(x5,j5);
155276541Sdes    x6 = PLUS(x6,j6);
156276541Sdes    x7 = PLUS(x7,j7);
157276541Sdes    x8 = PLUS(x8,j8);
158276541Sdes    x9 = PLUS(x9,j9);
159276541Sdes    x10 = PLUS(x10,j10);
160276541Sdes    x11 = PLUS(x11,j11);
161276541Sdes    x12 = PLUS(x12,j12);
162276541Sdes    x13 = PLUS(x13,j13);
163276541Sdes    x14 = PLUS(x14,j14);
164276541Sdes    x15 = PLUS(x15,j15);
165276541Sdes
166276541Sdes#ifndef KEYSTREAM_ONLY
167276541Sdes    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
168276541Sdes    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
169276541Sdes    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
170276541Sdes    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
171276541Sdes    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
172276541Sdes    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
173276541Sdes    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
174276541Sdes    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
175276541Sdes    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
176276541Sdes    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
177276541Sdes    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
178276541Sdes    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
179276541Sdes    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
180276541Sdes    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
181276541Sdes    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
182276541Sdes    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
183276541Sdes#endif
184276541Sdes
185276541Sdes    j12 = PLUSONE(j12);
186276541Sdes    if (!j12) {
187276541Sdes      j13 = PLUSONE(j13);
188276541Sdes      /* stopping at 2^70 bytes per nonce is user's responsibility */
189276541Sdes    }
190276541Sdes
191276541Sdes    U32TO8_LITTLE(c + 0,x0);
192276541Sdes    U32TO8_LITTLE(c + 4,x1);
193276541Sdes    U32TO8_LITTLE(c + 8,x2);
194276541Sdes    U32TO8_LITTLE(c + 12,x3);
195276541Sdes    U32TO8_LITTLE(c + 16,x4);
196276541Sdes    U32TO8_LITTLE(c + 20,x5);
197276541Sdes    U32TO8_LITTLE(c + 24,x6);
198276541Sdes    U32TO8_LITTLE(c + 28,x7);
199276541Sdes    U32TO8_LITTLE(c + 32,x8);
200276541Sdes    U32TO8_LITTLE(c + 36,x9);
201276541Sdes    U32TO8_LITTLE(c + 40,x10);
202276541Sdes    U32TO8_LITTLE(c + 44,x11);
203276541Sdes    U32TO8_LITTLE(c + 48,x12);
204276541Sdes    U32TO8_LITTLE(c + 52,x13);
205276541Sdes    U32TO8_LITTLE(c + 56,x14);
206276541Sdes    U32TO8_LITTLE(c + 60,x15);
207276541Sdes
208276541Sdes    if (bytes <= 64) {
209276541Sdes      if (bytes < 64) {
210276541Sdes        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
211276541Sdes      }
212276541Sdes      x->input[12] = j12;
213276541Sdes      x->input[13] = j13;
214276541Sdes      return;
215276541Sdes    }
216276541Sdes    bytes -= 64;
217276541Sdes    c += 64;
218276541Sdes#ifndef KEYSTREAM_ONLY
219276541Sdes    m += 64;
220276541Sdes#endif
221276541Sdes  }
222276541Sdes}
223