Skip to content

Commit 9fc488e

Browse files
committed
Allow SHAKE to be used for XOFs
Let `update!` and `digest!` behave as `absorb` and `squeeze` in the updated SP 800-185.
1 parent 4451e13 commit 9fc488e

File tree

2 files changed

+88
-21
lines changed

2 files changed

+88
-21
lines changed

src/shake.jl

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,34 +72,47 @@ function transform!(context::T) where {T<:SHAKE}
7272
end
7373
function digest!(context::T,d::UInt,p::Ptr{UInt8}) where {T<:SHAKE}
7474
usedspace = context.bytecount % blocklen(T)
75-
# If we have anything in the buffer still, pad and transform that data
76-
if usedspace < blocklen(T) - 1
77-
# Begin padding with a 0x1f
78-
context.buffer[usedspace+1] = 0x1f
79-
# Fill with zeros up until the last byte
80-
context.buffer[usedspace+2:end-1] .= 0x00
81-
# Finish it off with a 0x80
82-
context.buffer[end] = 0x80
83-
else
84-
# Otherwise, we have to add on a whole new buffer
85-
context.buffer[end] = 0x9f
75+
if !context.used
76+
# If we have anything in the buffer still, pad and transform that data
77+
if usedspace < blocklen(T) - 1
78+
# Begin padding with a 0x1f
79+
context.buffer[usedspace+1] = 0x1f
80+
# Fill with zeros up until the last byte
81+
context.buffer[usedspace+2:end-1] .= 0x00
82+
# Finish it off with a 0x80
83+
context.buffer[end] = 0x80
84+
else
85+
# Otherwise, we have to add on a whole new buffer
86+
context.buffer[end] = 0x9f
87+
end
88+
# Final transform:
89+
transform!(context)
90+
end
91+
if !context.used
92+
context.used = true
93+
context.bytecount = 0
94+
usedspace = 0
8695
end
87-
# Final transform:
88-
transform!(context)
8996
# Return the digest:
9097
# fill the given memory via pointer, if d>blocklen, update pointer and digest again.
91-
if d <= blocklen(T)
98+
avail = blocklen(T) - usedspace
99+
if d <= avail
92100
for i = 1:d
93-
unsafe_store!(p,reinterpret(UInt8, context.state)[i],i)
94-
end
101+
unsafe_store!(p,reinterpret(UInt8, context.state)[usedspace+i],i)
102+
end
103+
context.bytecount += d
104+
if avail == d
105+
transform!(context)
106+
end
95107
return
96108
else
97-
for i = 1:blocklen(T)
98-
unsafe_store!(p,reinterpret(UInt8, context.state)[i],i)
109+
for i = 1:avail
110+
unsafe_store!(p,reinterpret(UInt8, context.state)[usedspace+i],i)
99111
end
100-
context.used = true
101-
p+=blocklen(T)
102-
next_d_len = UInt(d - blocklen(T))
112+
context.bytecount += avail
113+
p+=avail
114+
next_d_len = UInt(d - avail)
115+
transform!(context)
103116
digest!(context, next_d_len, p)
104117
return
105118
end

test/runtests.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,70 @@ end
170170
@testset "shake128" begin
171171
for (k,v) in SHA128test
172172
@test SHA.shake128(hex2bytes(k[1]),k[2]) == hex2bytes(v)
173+
ctx = SHAKE_128_CTX()
174+
in = hex2bytes(k[1])
175+
idx = 1
176+
while idx <= length(in)
177+
l = min(rand(1:length(in)), length(in) - idx + 1)
178+
update!(ctx, in[idx:idx+l-1])
179+
idx += l
180+
end
181+
out = Vector{UInt8}(undef, k[2])
182+
idx = 0
183+
while idx < k[2]
184+
l = min(rand(1:k[2]), k[2] - idx)
185+
digest!(ctx, l, pointer(out) + idx)
186+
idx += l
187+
end
188+
@test out == hex2bytes(v)
173189
end
174190
@test SHA.shake128(b"",UInt(16)) == hex2bytes("7f9c2ba4e88f827d616045507605853e")
175191
@test SHA.shake128(codeunits("0" ^ 167), UInt(32)) == hex2bytes("ff60b0516fb8a3d4032900976e98b5595f57e9d4a88a0e37f7cc5adfa3c47da2")
192+
193+
for chunksize in UInt[1, 2, 3, 200]
194+
ctx = SHAKE_128_CTX()
195+
out = Vector{UInt8}(undef, 10000)
196+
idx = 0
197+
while idx < length(out)
198+
digest!(ctx, chunksize, pointer(out) + idx)
199+
idx += chunksize
200+
end
201+
@test out == SHA.shake128(UInt8[], UInt(length(out)))
202+
end
176203
end
177204

178205
@testset "shake256" begin
179206
for (k,v) in SHA256test
180207
@test SHA.shake256(hex2bytes(k[1]),k[2]) == hex2bytes(v)
208+
ctx = SHAKE_256_CTX()
209+
in = hex2bytes(k[1])
210+
idx = 1
211+
while idx <= length(in)
212+
l = min(rand(1:length(in)), length(in) - idx + 1)
213+
update!(ctx, in[idx:idx+l-1])
214+
idx += l
215+
end
216+
out = Vector{UInt8}(undef, k[2])
217+
idx = 0
218+
while idx < k[2]
219+
l = min(rand(1:k[2]), k[2] - idx)
220+
digest!(ctx, l, pointer(out) + idx)
221+
idx += l
222+
end
223+
@test out == hex2bytes(v)
181224
end
182225
@test SHA.shake256(b"",UInt(32)) == hex2bytes("46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f")
183226
@test SHA.shake256(codeunits("0"^135),UInt(32)) == hex2bytes("ab11f61b5085a108a58670a66738ea7a8d8ce23b7c57d64de83eaafb10923cf8")
227+
228+
for chunksize in UInt[1, 2, 3, 200]
229+
ctx = SHAKE_256_CTX()
230+
out = Vector{UInt8}(undef, 10000)
231+
idx = 0
232+
while idx < length(out)
233+
digest!(ctx, chunksize, pointer(out) + idx)
234+
idx += chunksize
235+
end
236+
@test out == SHA.shake256(UInt8[], UInt(length(out)))
237+
end
184238
end
185239
end

0 commit comments

Comments
 (0)