Skip to content

Commit

Permalink
Add docstrings for SHA module (JuliaLang#36777)
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-b1 authored and simeonschaub committed Aug 11, 2020
1 parent da784f9 commit 24e0c5d
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 6 deletions.
32 changes: 30 additions & 2 deletions stdlib/SHA/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,38 @@ julia> open("/tmp/test.txt") do f
0x08
```

Note the lack of a newline at the end of `/tmp/text.txt`. Julia automatically inserts a newline before the `julia>` prompt.

Due to the colloquial usage of `sha256` to refer to `sha2_256`, convenience functions are provided, mapping `shaxxx()` function calls to `sha2_xxx()`. For SHA-3, no such colloquialisms exist and the user must use the full `sha3_xxx()` names.

`shaxxx()` takes `AbstractString` and array-like objects (`NTuple` and `Array`) with elements of type `UInt8`.

To create a hash from multiple items the `SHAX_XXX_CTX()` types can be used to create a stateful hash object that
is updated with `update!` and finalized with `digest!`

```julia
julia> ctx = SHA2_256_CTX()
SHA2 256-bit hash state

julia> update!(ctx, b"some data")
0x0000000000000009

julia> update!(ctx, b"some more data")
0x0000000000000017

julia> digest!(ctx)
32-element Vector{UInt8}:
0xbe
0xcf
0x23
0xda
0xaf
0x02
0x25
0x52
0x19
0xa0
0x8b
0xc5
```

Note that, at the time of this writing, the SHA3 code is not optimized, and as such is roughly an order of magnitude slower than SHA2.
55 changes: 51 additions & 4 deletions stdlib/SHA/src/SHA.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

"""
SHA
The SHA module provides hashing functionality for SHA1, SHA2 and SHA3 algorithms.
They are implemented as both pure functions for hashing single pieces of data,
or a stateful context which can be updated with the `update!` function and
finalized with `digest!`.
```julia-repl
julia> sha1(b"some data")
20-element Vector{UInt8}:
0xba
0xf3
0xe3
0x56
julia> ctx = SHA1_CTX()
SHA1 hash state
julia> update!(ctx, b"some data")
0x0000000000000009
julia> digest!(ctx)
20-element Vector{UInt8}:
0xba
0xf3
0xe3
0x56
"""
module SHA

# Export convenience functions, context types, update!() and digest!() functions
Expand Down Expand Up @@ -45,10 +78,23 @@ for (f, ctx) in [(:sha1, :SHA1_CTX),

@eval begin
# Our basic function is to process arrays of bytes
"""
$($f)(data)
Hash data using the $($f) algorithm and return the resulting digest.
See also [`$($ctx)`](@ref).
"""
function $f(data::AbstractBytes)
ctx = $ctx()
update!(ctx, data)
return digest!(ctx)

"""
$($g)(key, data)
Hash data using the $($f) algorithm using the passed key
See also [`HMAC_CTX`](@ref).
"""
end
function $g(key::Vector{UInt8}, data::AbstractBytes)
ctx = HMAC_CTX($ctx(), key)
Expand All @@ -62,10 +108,11 @@ for (f, ctx) in [(:sha1, :SHA1_CTX),
$g(key::Vector{UInt8}, str::AbstractString) = $g(key, String(str))
$g(key::Vector{UInt8}, str::String) = $g(key, codeunits(str))

# Convenience function for IO devices, allows for things like:
# open("test.txt") do f
# sha256(f)
# done
"""
$($f)(io::IO)
Hash data from io using $($f) algorithm from io.
"""
function $f(io::IO, chunk_size=4*1024)
ctx = $ctx()
buff = Vector{UInt8}(undef, chunk_size)
Expand Down
35 changes: 35 additions & 0 deletions stdlib/SHA/src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@

# update! takes in variable-length data, buffering it into blocklen()-sized pieces,
# calling transform!() when necessary to update the internal hash state.
"""
update!(context, data[, datalen])
Update the SHA context with the bytes in data. See also [`digest!`](@ref) for
finalizing the hash.
# Examples
```julia-repl
julia> ctx = SHA1_CTX()
SHA1 hash state
julia> update!(ctx, b"data to to be hashed")
```
"""
function update!(context::T, data::U, datalen=length(data)) where {T<:SHA_CTX, U<:AbstractBytes}
# We need to do all our arithmetic in the proper bitwidth
UIntXXX = typeof(context.bytecount)
Expand Down Expand Up @@ -66,6 +80,27 @@ end

# Clear out any saved data in the buffer, append total bitlength, and return our precious hash!
# Note: SHA3_CTX has a more specialised method
"""
digest!(context)
Finalize the SHA context and return the hash as array of bytes (Array{Uint8, 1}).
# Examples
```julia-repl
julia> ctx = SHA1_CTX()
SHA1 hash state
julia> update!(ctx, b"data to to be hashed")
julia> digest!(ctx)
20-element Array{UInt8,1}:
0x83
0xe4
0x89
0xf5
```
"""
function digest!(context::T) where T<:SHA_CTX
pad_remainder!(context)
# Store the length of the input data (in bits) at the end of the padding
Expand Down
46 changes: 46 additions & 0 deletions stdlib/SHA/src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,55 @@ blocklen(::Type{SHA3_512_CTX}) = UInt64(25*8 - 2*digestlen(SHA3_512_CTX))
short_blocklen(::Type{T}) where {T<:SHA_CTX} = blocklen(T) - 2*sizeof(state_type(T))

# Once the "blocklen" methods are defined, we can define our outer constructors for SHA types:

"""
SHA2_224_CTX()
Construct an empty SHA2_224 context.
"""
SHA2_224_CTX() = SHA2_224_CTX(copy(SHA2_224_initial_hash_value), 0, zeros(UInt8, blocklen(SHA2_224_CTX)))
"""
SHA2_256_CTX()
Construct an empty SHA2_256 context.
"""
SHA2_256_CTX() = SHA2_256_CTX(copy(SHA2_256_initial_hash_value), 0, zeros(UInt8, blocklen(SHA2_256_CTX)))
"""
SHA2_384()
Construct an empty SHA2_384 context.
"""
SHA2_384_CTX() = SHA2_384_CTX(copy(SHA2_384_initial_hash_value), 0, zeros(UInt8, blocklen(SHA2_384_CTX)))
"""
SHA2_512_CTX()
Construct an empty SHA2_512 context.
"""
SHA2_512_CTX() = SHA2_512_CTX(copy(SHA2_512_initial_hash_value), 0, zeros(UInt8, blocklen(SHA2_512_CTX)))

"""
SHA3_224_CTX()
Construct an empty SHA3_224 context.
"""
SHA3_224_CTX() = SHA3_224_CTX(zeros(UInt64, 25), 0, zeros(UInt8, blocklen(SHA3_224_CTX)), Vector{UInt64}(undef, 5))
"""
SHA3_256_CTX()
Construct an empty SHA3_256 context.
"""
SHA3_256_CTX() = SHA3_256_CTX(zeros(UInt64, 25), 0, zeros(UInt8, blocklen(SHA3_256_CTX)), Vector{UInt64}(undef, 5))
"""
SHA3_384_CTX()
Construct an empty SHA3_384 context.
"""
SHA3_384_CTX() = SHA3_384_CTX(zeros(UInt64, 25), 0, zeros(UInt8, blocklen(SHA3_384_CTX)), Vector{UInt64}(undef, 5))
"""
SHA3_512_CTX()
Construct an empty SHA3_512 context.
"""
SHA3_512_CTX() = SHA3_512_CTX(zeros(UInt64, 25), 0, zeros(UInt8, blocklen(SHA3_512_CTX)), Vector{UInt64}(undef, 5))

# Nickname'd outer constructor methods for SHA2
Expand All @@ -129,6 +170,11 @@ const SHA384_CTX = SHA2_384_CTX
const SHA512_CTX = SHA2_512_CTX

# SHA1 is special; he needs extra workspace
"""
SHA1_CTX()
Construct an empty SHA1 context.
"""
SHA1_CTX() = SHA1_CTX(copy(SHA1_initial_hash_value), 0, zeros(UInt8, blocklen(SHA1_CTX)), Vector{UInt32}(undef, 80))


Expand Down

0 comments on commit 24e0c5d

Please sign in to comment.