v
Зеркало из https://github.com/vlang/v
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 sha3 implements the 512, 384, 256, and 224
5// bit hash algorithms and the 128 and 256 bit
6// extended output functions as defined in
7// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf.
8// Last updated: August 2015
9module sha3
10
11import math
12
13// size_224 is the size, in bytes, of a sha3 sum224 checksum.
14pub const size_224 = 28
15// size_256 is the size, in bytes, of a sha3 sum256 checksum.
16pub const size_256 = 32
17// size_384 is the size, in bytes, of a sha3 sum384 checksum.
18pub const size_384 = 48
19// size_512 is the size, in bytes, of a sha3 sum512 checksum.
20pub const size_512 = 64
21
22// rate_224 is the rate, in bytes, absorbed into the sponge on every permutation
23pub const rate_224 = 144
24// rate_256 is the rate, in bytes, absorbed into the sponge on every permutation
25pub const rate_256 = 136
26// rate_384 is the rate, in bytes, absorbed into the sponge on every permutation
27pub const rate_384 = 104
28// rate_512 is the rate, in bytes, absorbed into the sponge on every permutation
29pub const rate_512 = 72
30
31// xof_rate_128 is the capacity, in bytes, of a 128 bit extended output function sponge
32pub const xof_rate_128 = 168
33// xof_rate_256 is the capacity, in bytes, of a 256 bit extended output function sponge
34pub const xof_rate_256 = 136
35
36// the low order pad bits for a hash function
37const hash_pad = u8(0x06)
38
39// the low order pad bits for an extended output function
40const xof_pad = u8(0x1f)
41
42// new512 initializes the digest structure for a sha3 512 bit hash
43pub fn new512() !&Digest {
44return new_digest(rate_512, size_512)!
45}
46
47// new384 initializes the digest structure for a sha3 384 bit hash
48pub fn new384() !&Digest {
49return new_digest(rate_384, size_384)!
50}
51
52// new256 initializes the digest structure for a sha3 256 bit hash
53pub fn new256() !&Digest {
54return new_digest(rate_256, size_256)!
55}
56
57// new224 initializes the digest structure for a sha3 224 bit hash
58pub fn new224() !&Digest {
59return new_digest(rate_224, size_224)!
60}
61
62// new256_xof initializes the digest structure for a sha3 256 bit extended output function
63pub fn new256xof(output_len int) !&Digest {
64return new_xof_digest(xof_rate_256, output_len)!
65}
66
67// new128_xof initializes the digest structure for a sha3 128 bit extended output function
68pub fn new128xof(output_len int) !&Digest {
69return new_xof_digest(xof_rate_128, output_len)!
70}
71
72struct HashSizeError {
73Error
74size int
75}
76
77fn (err HashSizeError) msg() string {
78return 'Hash size ${err.size} must be ${size_224}, ${size_256}, ${size_384}, or ${size_512}'
79}
80
81struct AbsorptionRateError {
82Error
83size int
84rate int
85}
86
87fn (err AbsorptionRateError) msg() string {
88return 'Absorption rate ${err.rate} is not compatible with a hash size of ${err.size}'
89}
90
91struct XOFRateError {
92Error
93rate int
94}
95
96fn (err XOFRateError) msg() string {
97return 'Extended output rate ${err.rate} must be ${xof_rate_128} or ${xof_rate_256}'
98}
99
100struct XOFSizeError {
101Error
102size int
103}
104
105fn (err XOFSizeError) msg() string {
106return 'Extended output size ${err.size} must be > 0'
107}
108
109struct Digest {
110rate int // the number of bytes absorbed per permutation
111suffix u8 // the domain suffix, 0x06 for hash, 0x1f for extended output
112output_len int // the number of bytes to output
113mut:
114input_buffer []u8 // temporary holding buffer for input bytes
115s State // the state of a kaccak-p[1600, 24] sponge
116}
117
118// new_digest creates an initialized digest structure based on
119// the hash size and whether or not you specify a MAC key.
120//
121// absorption_rate is the number of bytes to be absorbed into the
122// sponge per permutation.
123//
124// hash_size - the number if bytes in the generated hash.
125// Legal values are 224, 256, 384, and 512.
126pub fn new_digest(absorption_rate int, hash_size int) !&Digest {
127match hash_size {
128size_224 {
129if absorption_rate != rate_224 {
130return AbsorptionRateError{
131rate: absorption_rate
132size: hash_size
133}
134}
135}
136size_256 {
137if absorption_rate != rate_256 {
138return AbsorptionRateError{
139rate: absorption_rate
140size: hash_size
141}
142}
143}
144size_384 {
145if absorption_rate != rate_384 {
146return AbsorptionRateError{
147rate: absorption_rate
148size: hash_size
149}
150}
151}
152size_512 {
153if absorption_rate != rate_512 {
154return AbsorptionRateError{
155rate: absorption_rate
156size: hash_size
157}
158}
159}
160else {
161return HashSizeError{
162size: hash_size
163}
164}
165}
166
167d := Digest{
168rate: absorption_rate
169suffix: hash_pad
170output_len: hash_size
171s: State{}
172}
173
174return &d
175}
176
177// new_xof_digest creates an initialized digest structure based on
178// the absorption rate and how many bytes of output you need
179//
180// absorption_rate is the number of bytes to be absorbed into the
181// sponge per permutation. Legal values are xof_rate_128 and
182// xof_rate_256.
183//
184// hash_size - the number if bytes in the generated hash.
185// Legal values are positive integers.
186pub fn new_xof_digest(absorption_rate int, hash_size int) !&Digest {
187match absorption_rate {
188xof_rate_128, xof_rate_256 {
189if hash_size < 1 {
190return XOFSizeError{
191size: hash_size
192}
193}
194}
195else {
196return XOFRateError{
197rate: absorption_rate
198}
199}
200}
201
202d := Digest{
203rate: absorption_rate
204suffix: xof_pad
205output_len: hash_size
206s: State{}
207}
208
209return &d
210}
211
212// write adds bytes to the sponge.
213//
214// This is the absorption phase of the computation.
215pub fn (mut d Digest) write(data []u8) ! {
216// if no data is being added to the hash,
217// just return
218if data.len == 0 {
219return
220}
221
222// absorb the input into the sponge
223mut bytes_remaining := unsafe { data[..] }
224
225if d.input_buffer.len != 0 {
226// see if we can accumulate rate bytes to be absorbed
227empty_space := d.rate - d.input_buffer.len
228
229if bytes_remaining.len < empty_space {
230d.input_buffer << bytes_remaining
231
232// we have not accumulated rate bytes yet.
233// just return.
234return
235} else {
236// we have enough bytes to add rate bytes to the
237// sponge.
238d.input_buffer << bytes_remaining[..empty_space]
239bytes_remaining = unsafe { bytes_remaining[empty_space..] }
240
241// absorb them
242d.s.xor_bytes(d.input_buffer[..d.rate], d.rate)
243d.s.kaccak_p_1600_24()
244
245d.input_buffer = ''.bytes()
246}
247}
248
249// absorb the remaining bytes
250for bytes_remaining.len >= d.rate {
251d.s.xor_bytes(bytes_remaining[..d.rate], d.rate)
252d.s.kaccak_p_1600_24()
253bytes_remaining = unsafe { bytes_remaining[d.rate..] }
254}
255
256if bytes_remaining.len > 0 {
257d.input_buffer = bytes_remaining
258}
259}
260
261// checksum finalizes the hash and returns the generated bytes.
262pub fn (mut d Digest) checksum() []u8 {
263return d.checksum_internal() or { panic(err) }
264}
265
266fn (mut d Digest) checksum_internal() ![]u8 {
267// pad the last input bytes to have rate bytes
268if d.input_buffer.len == d.rate - 1 {
269// a single byte pad needs to be handled specially
270d.input_buffer << u8(0x80 | d.suffix)
271} else {
272zero_pads := (d.rate - d.input_buffer.len) - 2
273
274// add the first byte of padding
275d.input_buffer << d.suffix
276
277// add intermediate zero pad bytes
278for _ in 0 .. zero_pads {
279d.input_buffer << u8(0x00)
280}
281
282// add the last pad byte
283d.input_buffer << u8(0x80)
284}
285
286d.s.xor_bytes(d.input_buffer[..d.rate], d.rate)
287d.s.kaccak_p_1600_24()
288
289// absorption is done. on to squeezing.
290
291// We know that we can extract rate bytes from the current
292// state. If the output_len is <= rate, we don't need to
293// iterate and can just return the bytes from the current
294// state.
295
296if d.output_len <= d.rate {
297return d.s.to_bytes()[..d.output_len]
298}
299
300// we need to squeeze the sponge a little harder to get
301// longer strings of bytes.
302
303mut output_bytes := []u8{cap: d.output_len}
304mut remaining_ouput_len := d.output_len
305
306for remaining_ouput_len > 0 {
307mut byte_len_this_round := math.min[int](remaining_ouput_len, d.rate)
308output_bytes << d.s.to_bytes()[..byte_len_this_round]
309
310remaining_ouput_len -= byte_len_this_round
311
312if remaining_ouput_len > 0 {
313d.s.kaccak_p_1600_24()
314}
315}
316
317return output_bytes
318}
319
320// sum512 returns the sha3 512 bit checksum of the data.
321pub fn sum512(data []u8) []u8 {
322mut d := new512() or { panic(err) }
323d.write(data) or { panic(err) }
324return d.checksum_internal() or { panic(err) }
325}
326
327// sum384 returns the sha3 384 bit checksum of the data.
328pub fn sum384(data []u8) []u8 {
329mut d := new384() or { panic(err) }
330d.write(data) or { panic(err) }
331return d.checksum_internal() or { panic(err) }
332}
333
334// sum256 returns the sha3 256 bit checksum of the data.
335pub fn sum256(data []u8) []u8 {
336mut d := new256() or { panic(err) }
337d.write(data) or { panic(err) }
338return d.checksum_internal() or { panic(err) }
339}
340
341// sum224 returns the sha3 224 bit checksum of the data.
342pub fn sum224(data []u8) []u8 {
343mut d := new224() or { panic(err) }
344d.write(data) or { panic(err) }
345return d.checksum_internal() or { panic(err) }
346}
347
348// shake256 returns the sha3 shake256 bit extended output
349pub fn shake256(data []u8, output_len int) []u8 {
350mut d := new256xof(output_len) or { panic(err) }
351d.write(data) or { panic(err) }
352return d.checksum_internal() or { panic(err) }
353}
354
355// shake128 returns the sha3 shake128 bit extended output
356pub fn shake128(data []u8, output_len int) []u8 {
357mut d := new128xof(output_len) or { panic(err) }
358d.write(data) or { panic(err) }
359return d.checksum_internal() or { panic(err) }
360}
361