Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2023 Kim Shrier. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// streaming shake-128/256 xof per FIPS 202
|
||||
// https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
|
||||
|
||||
module sha3
|
||||
|
||||
@[noinit]
|
||||
pub struct Shake {
|
||||
rate int // bytes per permutation (168 for shake-128, 136 for shake-256)
|
||||
mut:
|
||||
s State
|
||||
input_buffer []u8
|
||||
finalized bool
|
||||
squeeze_buf []u8
|
||||
}
|
||||
|
||||
// new_shake128 returns a new Shake instance for SHAKE-128 extended output function.
|
||||
pub fn new_shake128() &Shake {
|
||||
return &Shake{
|
||||
rate: xof_rate_128
|
||||
}
|
||||
}
|
||||
|
||||
// new_shake256 returns a new Shake instance for SHAKE-256 extended output function.
|
||||
pub fn new_shake256() &Shake {
|
||||
return &Shake{
|
||||
rate: xof_rate_256
|
||||
}
|
||||
}
|
||||
|
||||
// write absorbs more data into the sponge state.
|
||||
// Panics if called after `read`.
|
||||
@[direct_array_access]
|
||||
pub fn (mut s Shake) write(data []u8) {
|
||||
if s.finalized {
|
||||
panic('sha3: write after read on Shake')
|
||||
}
|
||||
if data.len == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// avoid cloning on each iteration
|
||||
mut remaining := unsafe { data[..] }
|
||||
|
||||
if s.input_buffer.len != 0 {
|
||||
empty_space := s.rate - s.input_buffer.len
|
||||
|
||||
if remaining.len < empty_space {
|
||||
s.input_buffer << remaining
|
||||
return
|
||||
} else {
|
||||
s.input_buffer << remaining[..empty_space]
|
||||
remaining = unsafe { remaining[empty_space..] }
|
||||
|
||||
s.s.xor_bytes(s.input_buffer[..s.rate], s.rate)
|
||||
s.s.kaccak_p_1600_24()
|
||||
|
||||
s.input_buffer = []u8{}
|
||||
}
|
||||
}
|
||||
|
||||
for remaining.len >= s.rate {
|
||||
s.s.xor_bytes(remaining[..s.rate], s.rate)
|
||||
s.s.kaccak_p_1600_24()
|
||||
remaining = unsafe { remaining[s.rate..] }
|
||||
}
|
||||
|
||||
if remaining.len > 0 {
|
||||
s.input_buffer = remaining.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut s Shake) finalize() {
|
||||
if s.finalized {
|
||||
return
|
||||
}
|
||||
s.finalized = true
|
||||
|
||||
// pad10*1 with xof domain separator 0x1f (FIPS 202 sec B.2)
|
||||
mut padded := s.input_buffer.clone()
|
||||
if padded.len == s.rate - 1 {
|
||||
padded << u8(0x80 | 0x1f)
|
||||
} else {
|
||||
padded << u8(0x1f)
|
||||
for padded.len < s.rate - 1 {
|
||||
padded << u8(0x00)
|
||||
}
|
||||
padded << u8(0x80)
|
||||
}
|
||||
|
||||
s.s.xor_bytes(padded[..s.rate], s.rate)
|
||||
s.s.kaccak_p_1600_24()
|
||||
|
||||
state_bytes := s.s.to_bytes()
|
||||
s.squeeze_buf = state_bytes[..s.rate].clone()
|
||||
s.input_buffer = []u8{}
|
||||
}
|
||||
|
||||
// read squeezes `out_len` bytes from the sponge state.
|
||||
// Finalizes the sponge on first call; further calls to `write` will panic.
|
||||
@[direct_array_access]
|
||||
pub fn (mut s Shake) read(out_len int) []u8 {
|
||||
if !s.finalized {
|
||||
s.finalize()
|
||||
}
|
||||
|
||||
mut result := []u8{cap: out_len}
|
||||
mut remaining := out_len
|
||||
|
||||
for remaining > 0 {
|
||||
if s.squeeze_buf.len == 0 {
|
||||
s.s.kaccak_p_1600_24()
|
||||
state_bytes := s.s.to_bytes()
|
||||
s.squeeze_buf = state_bytes[..s.rate].clone()
|
||||
}
|
||||
|
||||
take := if remaining < s.squeeze_buf.len { remaining } else { s.squeeze_buf.len }
|
||||
result << s.squeeze_buf[..take]
|
||||
s.squeeze_buf = s.squeeze_buf[take..].clone()
|
||||
remaining -= take
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// reset clears the sponge state, allowing the Shake instance to be reused.
|
||||
pub fn (mut s Shake) reset() {
|
||||
s.s = State{}
|
||||
s.input_buffer = []u8{}
|
||||
s.finalized = false
|
||||
s.squeeze_buf = []u8{}
|
||||
}
|
||||
Reference in new issue
Block a user