code / tomo-random

Lines568 Tomo238 C174 Markdown156
(192 lines)
1 // The ChaCha stream cipher used for pseudorandom number generation
3 #pragma once
4 /*
5 chacha-merged.c version 20080118
6 D. J. Bernstein
7 Public domain.
8 */
10 /* $OpenBSD: chacha_private.h,v 1.3 2022/02/28 21:56:29 dtucker Exp $ */
11 /* Tomo: chacha.h,v 1.0 2024/11/03 Bruce Hill */
13 typedef unsigned char u8;
14 typedef unsigned int u32;
16 typedef struct {
17 u32 input[16]; /* could be compressed */
18 } chacha_ctx;
20 #define KEYSZ 32
21 #define IVSZ 8
23 #define U8C(v) (v##U)
24 #define U32C(v) (v##U)
26 #define U8V(v) ((u8)(v) & U8C(0xFF))
27 #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
29 #define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n))))
31 #define U8TO32_LITTLE(p) (((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24))
33 #define U32TO8_LITTLE(p, v) \
34 do { \
35 (p)[0] = U8V((v)); \
36 (p)[1] = U8V((v) >> 8); \
37 (p)[2] = U8V((v) >> 16); \
38 (p)[3] = U8V((v) >> 24); \
39 } while (0)
41 #define ROTATE(v, c) (ROTL32(v, c))
42 #define XOR(v, w) ((v) ^ (w))
43 #define PLUS(v, w) (U32V((v) + (w)))
44 #define PLUSONE(v) (PLUS((v), 1))
46 #define QUARTERROUND(a, b, c, d) \
47 a = PLUS(a, b); \
48 d = ROTATE(XOR(d, a), 16); \
49 c = PLUS(c, d); \
50 b = ROTATE(XOR(b, c), 12); \
51 a = PLUS(a, b); \
52 d = ROTATE(XOR(d, a), 8); \
53 c = PLUS(c, d); \
54 b = ROTATE(XOR(b, c), 7);
56 static const char sigma[16] = "expand 32-byte k";
58 static void chacha_keysetup(chacha_ctx *chacha, const u8 *k) {
59 chacha->input[0] = U8TO32_LITTLE(sigma + 0);
60 chacha->input[1] = U8TO32_LITTLE(sigma + 4);
61 chacha->input[2] = U8TO32_LITTLE(sigma + 8);
62 chacha->input[3] = U8TO32_LITTLE(sigma + 12);
63 chacha->input[4] = U8TO32_LITTLE(k + 0);
64 chacha->input[5] = U8TO32_LITTLE(k + 4);
65 chacha->input[6] = U8TO32_LITTLE(k + 8);
66 chacha->input[7] = U8TO32_LITTLE(k + 12);
67 chacha->input[8] = U8TO32_LITTLE(k + 16);
68 chacha->input[9] = U8TO32_LITTLE(k + 20);
69 chacha->input[10] = U8TO32_LITTLE(k + 24);
70 chacha->input[11] = U8TO32_LITTLE(k + 28);
73 static void chacha_ivsetup(chacha_ctx *chacha, const u8 *iv) {
74 chacha->input[12] = 0;
75 chacha->input[13] = 0;
76 chacha->input[14] = U8TO32_LITTLE(iv + 0);
77 chacha->input[15] = U8TO32_LITTLE(iv + 4);
80 static void chacha_encrypt_bytes(chacha_ctx *chacha, const u8 *m, u8 *c, u32 bytes) {
81 u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
82 u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
83 u8 *ctarget = (u8 *)0;
84 u8 tmp[64];
85 unsigned int i;
87 if (!bytes) return;
89 j0 = chacha->input[0];
90 j1 = chacha->input[1];
91 j2 = chacha->input[2];
92 j3 = chacha->input[3];
93 j4 = chacha->input[4];
94 j5 = chacha->input[5];
95 j6 = chacha->input[6];
96 j7 = chacha->input[7];
97 j8 = chacha->input[8];
98 j9 = chacha->input[9];
99 j10 = chacha->input[10];
100 j11 = chacha->input[11];
101 j12 = chacha->input[12];
102 j13 = chacha->input[13];
103 j14 = chacha->input[14];
104 j15 = chacha->input[15];
106 for (;;) {
107 if (bytes < 64) {
108 for (i = 0; i < bytes; ++i)
109 tmp[i] = m[i];
110 m = tmp;
111 ctarget = c;
112 c = tmp;
114 x0 = j0;
115 x1 = j1;
116 x2 = j2;
117 x3 = j3;
118 x4 = j4;
119 x5 = j5;
120 x6 = j6;
121 x7 = j7;
122 x8 = j8;
123 x9 = j9;
124 x10 = j10;
125 x11 = j11;
126 x12 = j12;
127 x13 = j13;
128 x14 = j14;
129 x15 = j15;
130 for (i = 20; i > 0; i -= 2) {
131 QUARTERROUND(x0, x4, x8, x12)
132 QUARTERROUND(x1, x5, x9, x13)
133 QUARTERROUND(x2, x6, x10, x14)
134 QUARTERROUND(x3, x7, x11, x15)
135 QUARTERROUND(x0, x5, x10, x15)
136 QUARTERROUND(x1, x6, x11, x12)
137 QUARTERROUND(x2, x7, x8, x13)
138 QUARTERROUND(x3, x4, x9, x14)
140 x0 = PLUS(x0, j0);
141 x1 = PLUS(x1, j1);
142 x2 = PLUS(x2, j2);
143 x3 = PLUS(x3, j3);
144 x4 = PLUS(x4, j4);
145 x5 = PLUS(x5, j5);
146 x6 = PLUS(x6, j6);
147 x7 = PLUS(x7, j7);
148 x8 = PLUS(x8, j8);
149 x9 = PLUS(x9, j9);
150 x10 = PLUS(x10, j10);
151 x11 = PLUS(x11, j11);
152 x12 = PLUS(x12, j12);
153 x13 = PLUS(x13, j13);
154 x14 = PLUS(x14, j14);
155 x15 = PLUS(x15, j15);
157 j12 = PLUSONE(j12);
158 if (!j12) {
159 j13 = PLUSONE(j13);
160 /* stopping at 2^70 bytes per nonce is user's responsibility */
163 U32TO8_LITTLE(c + 0, x0);
164 U32TO8_LITTLE(c + 4, x1);
165 U32TO8_LITTLE(c + 8, x2);
166 U32TO8_LITTLE(c + 12, x3);
167 U32TO8_LITTLE(c + 16, x4);
168 U32TO8_LITTLE(c + 20, x5);
169 U32TO8_LITTLE(c + 24, x6);
170 U32TO8_LITTLE(c + 28, x7);
171 U32TO8_LITTLE(c + 32, x8);
172 U32TO8_LITTLE(c + 36, x9);
173 U32TO8_LITTLE(c + 40, x10);
174 U32TO8_LITTLE(c + 44, x11);
175 U32TO8_LITTLE(c + 48, x12);
176 U32TO8_LITTLE(c + 52, x13);
177 U32TO8_LITTLE(c + 56, x14);
178 U32TO8_LITTLE(c + 60, x15);
180 if (bytes <= 64) {
181 if (bytes < 64) {
182 for (i = 0; i < bytes; ++i)
183 ctarget[i] = c[i];
185 chacha->input[12] = j12;
186 chacha->input[13] = j13;
187 return;
189 bytes -= 64;
190 c += 64;