v2 / vlib / crypto / blake2s / blake2s.v
376 lines · 315 sloc · 10.32 KB · d05bbedab0e002f8da0a6881128b6c38e3852074
Raw
1// Copyright (c) 2023 Kim Shrier. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4// Package blake2s implements the Blake2s 256, 224, 160, and
5// 128 bit hash algorithms
6// as defined in IETF RFC 7693.
7// Based off: https://datatracker.ietf.org/doc/html/rfc7693
8// Last updated: November 2015
9module blake2s
10
11import encoding.binary
12
13// size128 is the size, in bytes, of a Blake2s 128 checksum.
14pub const size128 = 16
15// size160 is the size, in bytes, of a Blake2s 160 checksum.
16pub const size160 = 20
17// size224 is the size, in bytes, of a Blake2s 224 checksum.
18pub const size224 = 28
19// size256 is the size, in bytes, of a Blake2s 256 checksum.
20pub const size256 = 32
21
22// block_size is the block size, in bytes, of the Blake2s hash functions.
23pub const block_size = 64
24
25// G rotation constants
26const r1 = 16
27const r2 = 12
28const r3 = 8
29const r4 = 7
30
31// negative G rotation constants so we can rotate right.
32const nr1 = -1 * r1
33const nr2 = -1 * r2
34const nr3 = -1 * r3
35const nr4 = -1 * r4
36
37// initialization vector
38const iv = [
39 u32(0x6a09e667),
40 u32(0xbb67ae85),
41 u32(0x3c6ef372),
42 u32(0xa54ff53a),
43 u32(0x510e527f),
44 u32(0x9b05688c),
45 u32(0x1f83d9ab),
46 u32(0x5be0cd19),
47]
48
49// message word schedule permutations
50const sigma = [
51 [u8(0), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]!,
52 [u8(14), 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]!,
53 [u8(11), 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4]!,
54 [u8(7), 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8]!,
55 [u8(9), 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13]!,
56 [u8(2), 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9]!,
57 [u8(12), 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11]!,
58 [u8(13), 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10]!,
59 [u8(6), 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5]!,
60 [u8(10), 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]!,
61]!
62
63struct Digest {
64 hash_size u8
65mut:
66 input_buffer []u8
67 h []u32
68 m [16]u32
69 t u64
70}
71
72// string makes a formatted string representation of a Digest structure
73pub fn (d Digest) str() string {
74 return 'blake2s.Digest{\n hash_size: ${d.hash_size}\n input_buffer: ${d.input_buffer}\n input_buffer.len: ${d.input_buffer.len}\n h: [0x${d.h[0]:016x}, 0x${d.h[1]:016x}, 0x${d.h[2]:016x}, 0x${d.h[3]:016x},\n 0x${d.h[4]:016x}, 0x${d.h[5]:016x}, 0x${d.h[6]:016x}, 0x${d.h[7]:016x}]\n m: [0x${d.m[0]:016x}, 0x${d.m[1]:016x}, 0x${d.m[2]:016x}, 0x${d.m[3]:016x},\n 0x${d.m[4]:016x}, 0x${d.m[5]:016x}, 0x${d.m[6]:016x}, 0x${d.m[7]:016x},\n 0x${d.m[8]:016x}, 0x${d.m[9]:016x}, 0x${d.m[10]:016x}, 0x${d.m[11]:016x},\n 0x${d.m[12]:016x}, 0x${d.m[13]:016x}, 0x${d.m[14]:016x}, 0x${d.m[15]:016x}]\n t: ${d.t}\n}'
75}
76
77// new256 initializes the digest structure for a Blake2s 256 bit hash
78pub fn new256() !&Digest {
79 return new_digest(size256, []u8{})!
80}
81
82// new_pmac256 initializes the digest structure for a Blake2s 256 bit prefix MAC
83pub fn new_pmac256(key []u8) !&Digest {
84 return new_digest(size256, key)!
85}
86
87// new224 initializes the digest structure for a Blake2s 224 bit hash
88pub fn new224() !&Digest {
89 return new_digest(size224, []u8{})!
90}
91
92// new_pmac224 initializes the digest structure for a Blake2s 224 bit prefix MAC
93pub fn new_pmac224(key []u8) !&Digest {
94 return new_digest(size224, key)!
95}
96
97// new160 initializes the digest structure for a Blake2s 160 bit hash
98pub fn new160() !&Digest {
99 return new_digest(size160, []u8{})!
100}
101
102// new_pmac160 initializes the digest structure for a Blake2s 160 bit prefix MAC
103pub fn new_pmac160(key []u8) !&Digest {
104 return new_digest(size160, key)!
105}
106
107// new126 initializes the digest structure for a Blake2s 128 bit hash
108pub fn new128() !&Digest {
109 return new_digest(size128, []u8{})!
110}
111
112// new_pmac128 initializes the digest structure for a Blake2s 128 bit prefix MAC
113pub fn new_pmac128(key []u8) !&Digest {
114 return new_digest(size128, key)!
115}
116
117struct HashSizeError {
118 Error
119 size u8
120}
121
122fn (err HashSizeError) msg() string {
123 return 'Hash size ${err.size} must be between 1 and ${size256}'
124}
125
126struct KeySizeError {
127 Error
128 size i32
129}
130
131fn (err KeySizeError) msg() string {
132 return 'Key size ${err.size} must be between 0 and ${size256}'
133}
134
135struct InputBufferSizeError {
136 Error
137 size i32
138}
139
140fn (err InputBufferSizeError) msg() string {
141 return 'The input buffer size ${err.size} .must be between 0 and ${block_size}'
142}
143
144// new_digest creates an initialized digest structure based on
145// the hash size and whether or not you specify a MAC key.
146//
147// hash_size - the number of bytes in the generated hash.
148// Legal values are between 1 and 32.
149//
150// key - key used for generating a prefix MAC. A zero length
151// key is used for just generating a hash. A key of 1 to
152// 32 bytes can be used for generating a prefix MAC.
153pub fn new_digest(hash_size u8, key []u8) !&Digest {
154 if hash_size < 1 || hash_size > size256 {
155 return HashSizeError{
156 size: hash_size
157 }
158 }
159
160 if key.len < 0 || key.len > size256 {
161 return KeySizeError{
162 size: i32(key.len)
163 }
164 }
165
166 mut d := Digest{
167 h: iv.clone()
168 t: 0
169 hash_size: hash_size
170 }
171
172 if key.len > 0 {
173 p0 := 0x01010000 ^ u32(key.len) << 8 ^ u32(hash_size)
174
175 d.h[0] ^= p0
176
177 d.input_buffer.clear()
178 d.input_buffer << key
179
180 pad_length := block_size - key.len
181 for _ in 0 .. pad_length {
182 d.input_buffer << 0
183 }
184 } else {
185 p0 := 0x01010000 ^ u32(hash_size)
186
187 d.h[0] ^= p0
188 }
189
190 return &d
191}
192
193// The intent is to only use this method
194// when the input buffer is full or when
195// the last data to be hashed is in the
196// input buffer.
197//
198// If the input buffer does not contain enough
199// data to fill all the message blocks, the
200// input buffer is padded with 0 bytes until
201// it is full prior to moving the data into
202// the message blocks.
203//
204// The input buffer is emptied.
205//
206// The total byte count is incremented by the
207// number of bytes in the input buffer.
208fn (mut d Digest) move_input_to_message_blocks() ! {
209 // the number of bytes in the input buffer
210 // should never exceed the block size.
211 if d.input_buffer.len < 0 || d.input_buffer.len > block_size {
212 return InputBufferSizeError{
213 size: i32(d.input_buffer.len)
214 }
215 }
216
217 // keep the hashed data length up to date
218 d.t += u64(d.input_buffer.len)
219
220 // pad the input buffer if necessary
221 if d.input_buffer.len < block_size {
222 pad_length := block_size - d.input_buffer.len
223
224 for _ in 0 .. pad_length {
225 d.input_buffer << 0
226 }
227 }
228
229 // treat the input bytes as little endian u32 values
230 for i in 0 .. 16 {
231 d.m[i] = binary.little_endian_u32_at(d.input_buffer, i * 4)
232 }
233
234 // empty the input buffer
235 d.input_buffer.clear()
236
237 return
238}
239
240// write adds bytes to the hash
241pub fn (mut d Digest) write(data []u8) ! {
242 // if no data is being added to the hash,
243 // just return
244 if data.len == 0 {
245 return
246 }
247
248 // if the input buffer is already full,
249 // process the existing input bytes first.
250 // this is not the final input.
251 if d.input_buffer.len >= block_size {
252 d.move_input_to_message_blocks()!
253 d.f(false)
254 }
255
256 // add data to the input buffer until you
257 // run out of space in the input buffer or
258 // run out of data, whichever comes first.
259 empty_space := block_size - d.input_buffer.len
260 mut remaining_data := unsafe { data[..] }
261
262 if empty_space >= data.len {
263 // ran out of data first
264 // just add it to the input buffer and return
265 d.input_buffer << data
266 return
267 } else {
268 // ran out of input buffer space first
269 // fill it up and process it.
270 d.input_buffer << data[..empty_space]
271 remaining_data = unsafe { remaining_data[empty_space..] }
272
273 d.move_input_to_message_blocks()!
274 d.f(false)
275 }
276
277 // process the data in block size amounts until
278 // all the data has been processed
279 for remaining_data.len > 0 {
280 if block_size >= remaining_data.len {
281 // running out of data
282 // just add it to the input buffer and return
283 d.input_buffer << remaining_data
284 return
285 }
286
287 // add block size bytes to the input buffer
288 // and process it
289 d.input_buffer << remaining_data[..block_size]
290 remaining_data = unsafe { remaining_data[block_size..] }
291
292 d.move_input_to_message_blocks()!
293 d.f(false)
294 }
295
296 return
297}
298
299fn (mut d Digest) checksum_internal() ![]u8 {
300 // process the last input bytes
301 d.move_input_to_message_blocks()!
302 d.f(true)
303
304 // get the hash into the proper byte order
305 mut hash_bytes := []u8{}
306
307 for hash in d.h {
308 mut h_bytes := []u8{len: 4, cap: 4}
309 binary.little_endian_put_u32(mut h_bytes, hash)
310 hash_bytes << h_bytes
311 }
312
313 // return the appropriate number of hash bytes
314 return hash_bytes[..d.hash_size]
315}
316
317// checksum finalizes the hash and returns the generated bytes.
318pub fn (mut d Digest) checksum() []u8 {
319 return d.checksum_internal() or { panic(err) }
320}
321
322// sum256 returns the Blake2s 256 bit checksum of the data.
323pub fn sum256(data []u8) []u8 {
324 mut d := new256() or { panic(err) }
325 d.write(data) or { panic(err) }
326 return d.checksum_internal() or { panic(err) }
327}
328
329// sum224 returns the Blake2s 224 bit checksum of the data.
330pub fn sum224(data []u8) []u8 {
331 mut d := new224() or { panic(err) }
332 d.write(data) or { panic(err) }
333 return d.checksum_internal() or { panic(err) }
334}
335
336// sum160 returns the Blake2s 160 bit checksum of the data.
337pub fn sum160(data []u8) []u8 {
338 mut d := new160() or { panic(err) }
339 d.write(data) or { panic(err) }
340 return d.checksum_internal() or { panic(err) }
341}
342
343// sum128 returns the Blake2s 128 bit checksum of the data.
344pub fn sum128(data []u8) []u8 {
345 mut d := new128() or { panic(err) }
346 d.write(data) or { panic(err) }
347 return d.checksum_internal() or { panic(err) }
348}
349
350// pmac256 returns the Blake2s 256 bit prefix MAC of the data.
351pub fn pmac256(data []u8, key []u8) []u8 {
352 mut d := new_pmac256(key) or { panic(err) }
353 d.write(data) or { panic(err) }
354 return d.checksum_internal() or { panic(err) }
355}
356
357// pmac224 returns the Blake2s 224 bit prefix MAC of the data.
358pub fn pmac224(data []u8, key []u8) []u8 {
359 mut d := new_pmac224(key) or { panic(err) }
360 d.write(data) or { panic(err) }
361 return d.checksum_internal() or { panic(err) }
362}
363
364// pmac160 returns the Blake2s 160 bit prefix MAC of the data.
365pub fn pmac160(data []u8, key []u8) []u8 {
366 mut d := new_pmac160(key) or { panic(err) }
367 d.write(data) or { panic(err) }
368 return d.checksum_internal() or { panic(err) }
369}
370
371// pmac128 returns the Blake2s 128 bit prefix MAC of the data.
372pub fn pmac128(data []u8, key []u8) []u8 {
373 mut d := new_pmac128(key) or { panic(err) }
374 d.write(data) or { panic(err) }
375 return d.checksum_internal() or { panic(err) }
376}
377