mirror of
https://github.com/odin-lang/Odin.git
synced 2026-05-04 03:54:41 +00:00
core/crypto/shake: SHAKE is an XOF, not a hash
This commit is contained in:
@@ -4,7 +4,6 @@ import "core:crypto/blake2b"
|
||||
import "core:crypto/blake2s"
|
||||
import "core:crypto/sha2"
|
||||
import "core:crypto/sha3"
|
||||
import "core:crypto/shake"
|
||||
import "core:crypto/sm3"
|
||||
import "core:crypto/legacy/keccak"
|
||||
import "core:crypto/legacy/md5"
|
||||
@@ -26,8 +25,6 @@ Algorithm :: enum {
|
||||
SHA3_256,
|
||||
SHA3_384,
|
||||
SHA3_512,
|
||||
SHAKE_128,
|
||||
SHAKE_256,
|
||||
SM3,
|
||||
Legacy_KECCAK_224,
|
||||
Legacy_KECCAK_256,
|
||||
@@ -51,8 +48,6 @@ ALGORITHM_NAMES := [Algorithm]string {
|
||||
.SHA3_256 = "SHA3-256",
|
||||
.SHA3_384 = "SHA3-384",
|
||||
.SHA3_512 = "SHA3-512",
|
||||
.SHAKE_128 = "SHAKE-128",
|
||||
.SHAKE_256 = "SHAKE-256",
|
||||
.SM3 = "SM3",
|
||||
.Legacy_KECCAK_224 = "Keccak-224",
|
||||
.Legacy_KECCAK_256 = "Keccak-256",
|
||||
@@ -76,8 +71,6 @@ DIGEST_SIZES := [Algorithm]int {
|
||||
.SHA3_256 = sha3.DIGEST_SIZE_256,
|
||||
.SHA3_384 = sha3.DIGEST_SIZE_384,
|
||||
.SHA3_512 = sha3.DIGEST_SIZE_512,
|
||||
.SHAKE_128 = shake.DIGEST_SIZE_128,
|
||||
.SHAKE_256 = shake.DIGEST_SIZE_256,
|
||||
.SM3 = sm3.DIGEST_SIZE,
|
||||
.Legacy_KECCAK_224 = keccak.DIGEST_SIZE_224,
|
||||
.Legacy_KECCAK_256 = keccak.DIGEST_SIZE_256,
|
||||
@@ -96,7 +89,6 @@ Context :: struct {
|
||||
^sha2.Context_256,
|
||||
^sha2.Context_512,
|
||||
^sha3.Context,
|
||||
^shake.Context,
|
||||
^sm3.Context,
|
||||
^keccak.Context,
|
||||
^md5.Context,
|
||||
@@ -159,14 +151,6 @@ init :: proc(ctx: ^Context, algorithm: Algorithm, allocator := context.allocator
|
||||
impl := new(sha3.Context, allocator)
|
||||
sha3.init_512(impl)
|
||||
ctx._impl = impl
|
||||
case .SHAKE_128:
|
||||
impl := new(shake.Context, allocator)
|
||||
shake.init_128(impl)
|
||||
ctx._impl = impl
|
||||
case .SHAKE_256:
|
||||
impl := new(shake.Context, allocator)
|
||||
shake.init_256(impl)
|
||||
ctx._impl = impl
|
||||
case .SM3:
|
||||
impl := new(sm3.Context, allocator)
|
||||
sm3.init(impl)
|
||||
@@ -218,8 +202,6 @@ update :: proc(ctx: ^Context, data: []byte) {
|
||||
sha2.update(impl, data)
|
||||
case ^sha3.Context:
|
||||
sha3.update(impl, data)
|
||||
case ^shake.Context:
|
||||
shake.update(impl, data)
|
||||
case ^sm3.Context:
|
||||
sm3.update(impl, data)
|
||||
case ^keccak.Context:
|
||||
@@ -250,8 +232,6 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
|
||||
sha2.final(impl, hash, finalize_clone)
|
||||
case ^sha3.Context:
|
||||
sha3.final(impl, hash, finalize_clone)
|
||||
case ^shake.Context:
|
||||
shake.final(impl, hash, finalize_clone)
|
||||
case ^sm3.Context:
|
||||
sm3.final(impl, hash, finalize_clone)
|
||||
case ^keccak.Context:
|
||||
@@ -304,10 +284,6 @@ clone :: proc(ctx, other: ^Context, allocator := context.allocator) {
|
||||
impl := new(sha3.Context, allocator)
|
||||
sha3.clone(impl, src_impl)
|
||||
ctx._impl = impl
|
||||
case ^shake.Context:
|
||||
impl := new(shake.Context, allocator)
|
||||
shake.clone(impl, src_impl)
|
||||
ctx._impl = impl
|
||||
case ^sm3.Context:
|
||||
impl := new(sm3.Context, allocator)
|
||||
sm3.clone(impl, src_impl)
|
||||
@@ -348,9 +324,6 @@ reset :: proc(ctx: ^Context) {
|
||||
case ^sha3.Context:
|
||||
sha3.reset(impl)
|
||||
free(impl, ctx._allocator)
|
||||
case ^shake.Context:
|
||||
shake.reset(impl)
|
||||
free(impl, ctx._allocator)
|
||||
case ^sm3.Context:
|
||||
sm3.reset(impl)
|
||||
free(impl, ctx._allocator)
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/*
|
||||
package shake implements the SHAKE XOF algorithm family.
|
||||
|
||||
The SHA3 hash algorithm can be found in the crypto/sha3.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
|
||||
*/
|
||||
package shake
|
||||
|
||||
/*
|
||||
@@ -6,30 +14,22 @@ package shake
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the SHAKE XOF. The SHA3 hashing algorithm can be found
|
||||
in package sha3.
|
||||
|
||||
TODO:
|
||||
- This should provide an incremental squeeze interface.
|
||||
- DIGEST_SIZE is inaccurate, SHAKE-128 and SHAKE-256 are security
|
||||
strengths.
|
||||
*/
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
DIGEST_SIZE_128 :: 16
|
||||
DIGEST_SIZE_256 :: 32
|
||||
|
||||
// Context is a SHAKE128 or SHAKE256 instance.
|
||||
Context :: distinct _sha3.Context
|
||||
|
||||
// init_128 initializes a Context for SHAKE128.
|
||||
init_128 :: proc(ctx: ^Context) {
|
||||
ctx.mdlen = DIGEST_SIZE_128
|
||||
ctx.mdlen = 128 / 8
|
||||
_init(ctx)
|
||||
}
|
||||
|
||||
// init_256 initializes a Context for SHAKE256.
|
||||
init_256 :: proc(ctx: ^Context) {
|
||||
ctx.mdlen = DIGEST_SIZE_256
|
||||
ctx.mdlen = 256 / 8
|
||||
_init(ctx)
|
||||
}
|
||||
|
||||
@@ -38,36 +38,31 @@ _init :: proc(ctx: ^Context) {
|
||||
_sha3.init(transmute(^_sha3.Context)(ctx))
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
// write writes more data into the SHAKE instance. This MUST not be called
|
||||
// after any reads have been done, and attempts to do so will panic.
|
||||
write :: proc(ctx: ^Context, data: []byte) {
|
||||
_sha3.update(transmute(^_sha3.Context)(ctx), data)
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
|
||||
// Rolling digest support is handled here instead of in the generic
|
||||
// _sha3 package as SHAKE is more of an XOF than a hash, so the
|
||||
// standard notion of "final", doesn't really exist when you can
|
||||
// squeeze an unlimited amount of data.
|
||||
//
|
||||
// TODO/yawning: Strongly consider getting rid of this and rigidly
|
||||
// defining SHAKE as an XOF.
|
||||
|
||||
ctx := ctx
|
||||
if finalize_clone {
|
||||
tmp_ctx: Context
|
||||
clone(&tmp_ctx, ctx)
|
||||
ctx = &tmp_ctx
|
||||
}
|
||||
defer(reset(ctx))
|
||||
|
||||
// read reads output from the SHAKE instance. There is no practical upper
|
||||
// limit to the amount of data that can be read from SHAKE. After read has
|
||||
// been called one or more times, further calls to write will panic.
|
||||
read :: proc(ctx: ^Context, dst: []byte) {
|
||||
ctx_ := transmute(^_sha3.Context)(ctx)
|
||||
_sha3.shake_xof(ctx_)
|
||||
_sha3.shake_out(ctx_, hash[:])
|
||||
if !ctx.is_finalized {
|
||||
_sha3.shake_xof(ctx_)
|
||||
}
|
||||
|
||||
_sha3.shake_out(ctx_, dst)
|
||||
}
|
||||
|
||||
// clone clones the Context other into ctx.
|
||||
clone :: proc(ctx, other: ^Context) {
|
||||
_sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other))
|
||||
}
|
||||
|
||||
// reset sanitizes the Context. The Context must be re-initialized to
|
||||
// be used again.
|
||||
reset :: proc(ctx: ^Context) {
|
||||
_sha3.reset(transmute(^_sha3.Context)(ctx))
|
||||
}
|
||||
|
||||
@@ -12,11 +12,13 @@ package test_core_crypto
|
||||
Where possible, the official test vectors are used to validate the implementation.
|
||||
*/
|
||||
|
||||
import "core:encoding/hex"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:testing"
|
||||
|
||||
import "core:crypto/siphash"
|
||||
import "core:os"
|
||||
import "core:crypto/shake"
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
@@ -43,6 +45,7 @@ main :: proc() {
|
||||
t := testing.T{}
|
||||
test_hash(&t)
|
||||
|
||||
test_shake(&t)
|
||||
test_siphash_2_4(&t)
|
||||
|
||||
// "modern" crypto tests
|
||||
@@ -60,6 +63,81 @@ main :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
TestXOF :: struct {
|
||||
sec_strength: int,
|
||||
output: string,
|
||||
str: string,
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_shake :: proc(t: ^testing.T) {
|
||||
test_vectors := [?]TestXOF {
|
||||
// SHAKE128
|
||||
{
|
||||
128,
|
||||
"7f9c2ba4e88f827d616045507605853e",
|
||||
"",
|
||||
},
|
||||
{
|
||||
128,
|
||||
"f4202e3c5852f9182a0430fd8144f0a7",
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
},
|
||||
{
|
||||
128,
|
||||
"853f4538be0db9621a6cea659a06c110",
|
||||
"The quick brown fox jumps over the lazy dof",
|
||||
},
|
||||
|
||||
// SHAKE256
|
||||
{
|
||||
256,
|
||||
"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f",
|
||||
"",
|
||||
},
|
||||
{
|
||||
256,
|
||||
"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca",
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
},
|
||||
{
|
||||
256,
|
||||
"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401",
|
||||
"The quick brown fox jumps over the lazy dof",
|
||||
},
|
||||
}
|
||||
for v in test_vectors {
|
||||
dst := make([]byte, len(v.output)/2, context.temp_allocator)
|
||||
|
||||
data := transmute([]byte)(v.str)
|
||||
|
||||
ctx: shake.Context
|
||||
switch v.sec_strength {
|
||||
case 128:
|
||||
shake.init_128(&ctx)
|
||||
case 256:
|
||||
shake.init_256(&ctx)
|
||||
}
|
||||
|
||||
shake.write(&ctx, data)
|
||||
shake.read(&ctx, dst)
|
||||
|
||||
dst_str := string(hex.encode(dst, context.temp_allocator))
|
||||
|
||||
expect(
|
||||
t,
|
||||
dst_str == v.output,
|
||||
fmt.tprintf(
|
||||
"SHAKE%d: Expected: %s for input of %s, but got %s instead",
|
||||
v.sec_strength,
|
||||
v.output,
|
||||
v.str,
|
||||
dst_str,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_siphash_2_4 :: proc(t: ^testing.T) {
|
||||
// Test vectors from
|
||||
|
||||
@@ -339,36 +339,6 @@ test_hash :: proc(t: ^testing.T) {
|
||||
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
|
||||
},
|
||||
|
||||
// SHAKE-128
|
||||
TestHash{hash.Algorithm.SHAKE_128, "7f9c2ba4e88f827d616045507605853e", ""},
|
||||
TestHash {
|
||||
hash.Algorithm.SHAKE_128,
|
||||
"f4202e3c5852f9182a0430fd8144f0a7",
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
},
|
||||
TestHash {
|
||||
hash.Algorithm.SHAKE_128,
|
||||
"853f4538be0db9621a6cea659a06c110",
|
||||
"The quick brown fox jumps over the lazy dof",
|
||||
},
|
||||
|
||||
// SHAKE-256
|
||||
TestHash {
|
||||
hash.Algorithm.SHAKE_256,
|
||||
"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f",
|
||||
"",
|
||||
},
|
||||
TestHash {
|
||||
hash.Algorithm.SHAKE_256,
|
||||
"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca",
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
},
|
||||
TestHash {
|
||||
hash.Algorithm.SHAKE_256,
|
||||
"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401",
|
||||
"The quick brown fox jumps over the lazy dof",
|
||||
},
|
||||
|
||||
// SM3
|
||||
{
|
||||
hash.Algorithm.SM3,
|
||||
|
||||
Reference in New Issue
Block a user