mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-01 20:28:15 +00:00
core/crypto/shake: Support cSHAKE
This commit is contained in:
@@ -20,9 +20,7 @@ import "core:mem"
|
||||
|
||||
ROUNDS :: 24
|
||||
|
||||
RATE_SHAKE_128 :: 168
|
||||
RATE_SHAKE_256 :: 136
|
||||
|
||||
RATE_128 :: 1344 / 8 // ONLY for SHAKE128.
|
||||
RATE_224 :: 1152 / 8
|
||||
RATE_256 :: 1088 / 8
|
||||
RATE_384 :: 832 / 8
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package _sha3
|
||||
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
|
||||
init_cshake :: proc(ctx: ^Context, n, s: []byte, sec_strength: int) {
|
||||
rate: int
|
||||
switch sec_strength {
|
||||
case 128:
|
||||
rate = RATE_128
|
||||
case 256:
|
||||
rate = RATE_256
|
||||
case:
|
||||
panic("crypto/sha3: invalid security strength")
|
||||
}
|
||||
|
||||
ctx.mdlen = sec_strength / 8
|
||||
|
||||
// No domain separator is equivalent to vanilla SHAKE.
|
||||
if len(n) == 0 && len(s) == 0 {
|
||||
ctx.dsbyte = DS_SHAKE
|
||||
init(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.dsbyte = DS_CSHAKE
|
||||
init(ctx)
|
||||
bytepad(ctx, [][]byte{n, s}, rate)
|
||||
}
|
||||
|
||||
// right_encode and left_encode are defined to support 0 <= x < 2^2040
|
||||
// however, the largest value we will ever need to encode is `max(int) * 8`.
|
||||
//
|
||||
// This is unfortunate as the extreme upper edge is larger than
|
||||
// `max(u64)`. While such values are impractical at present,
|
||||
// they are possible (ie: https://arxiv.org/pdf/quant-ph/9908043.pdf).
|
||||
//
|
||||
// Thus we support 0 <= x < 2^128.
|
||||
|
||||
@(private)
|
||||
_PAD: [RATE_128]byte // Biggest possible value of w per spec.
|
||||
|
||||
bytepad :: proc(ctx: ^Context, x_strings: [][]byte, w: int) {
|
||||
// 1. z = left_encode(w) || X.
|
||||
z_hi: u64
|
||||
z_lo := left_right_encode(ctx, 0, u64(w), true)
|
||||
for x in x_strings {
|
||||
// All uses of bytepad in SP 800-185 use the output from
|
||||
// one or more encode_string values for `X`.
|
||||
hi, lo := encode_string(ctx, x)
|
||||
|
||||
carry: u64
|
||||
z_lo, carry = bits.add_u64(z_lo, lo, 0)
|
||||
z_hi, carry = bits.add_u64(z_hi, hi, carry)
|
||||
|
||||
// This isn't actually possible, at least with the currently
|
||||
// defined SP 800-185 routines.
|
||||
if carry != 0 {
|
||||
panic("crypto/sha3: bytepad input length overflow")
|
||||
}
|
||||
}
|
||||
|
||||
// We skip this step as we are doing a byte-oriented implementation
|
||||
// rather than a bit oriented one.
|
||||
//
|
||||
// 2. while len(z) mod 8 ≠ 0:
|
||||
// z = z || 0
|
||||
|
||||
// 3. while (len(z)/8) mod w ≠ 0:
|
||||
// z = z || 00000000
|
||||
z_len := u128(z_hi) << 64 | u128(z_lo)
|
||||
z_rem := int(z_len % u128(w))
|
||||
pad := _PAD[:w - z_rem]
|
||||
|
||||
// We just add the padding to the state, instead of returning z.
|
||||
//
|
||||
// 4. return z.
|
||||
update(ctx, pad)
|
||||
}
|
||||
|
||||
encode_string :: #force_inline proc(ctx: ^Context, s: []byte) -> (u64, u64) {
|
||||
l := encode_byte_len(ctx, len(s), true) // left_encode
|
||||
update(ctx, s)
|
||||
|
||||
lo, hi := bits.add_u64(l, u64(len(s)), 0)
|
||||
|
||||
return hi, lo
|
||||
}
|
||||
|
||||
encode_byte_len :: #force_inline proc(ctx: ^Context, l: int, is_left: bool) -> u64 {
|
||||
hi, lo := bits.mul_u64(u64(l), 8)
|
||||
return left_right_encode(ctx, hi, lo, is_left)
|
||||
}
|
||||
|
||||
@(private)
|
||||
left_right_encode :: proc(ctx: ^Context, hi, lo: u64, is_left: bool) -> u64 {
|
||||
HI_OFFSET :: 1
|
||||
LO_OFFSET :: HI_OFFSET + 8
|
||||
RIGHT_OFFSET :: LO_OFFSET + 8
|
||||
BUF_LEN :: RIGHT_OFFSET + 1
|
||||
|
||||
buf: [BUF_LEN]byte // prefix + largest uint + postfix
|
||||
|
||||
endian.unchecked_put_u64be(buf[HI_OFFSET:], hi)
|
||||
endian.unchecked_put_u64be(buf[LO_OFFSET:], lo)
|
||||
|
||||
// 2. Strip leading `0x00` bytes.
|
||||
off: int
|
||||
for off = HI_OFFSET; off < RIGHT_OFFSET - 1; off = off + 1 {// Note: Minimum size is 1, not 0.
|
||||
if buf[off] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
n := byte(RIGHT_OFFSET - off)
|
||||
|
||||
// 3. Prefix (left_encode) or postfix (right_encode) the length in bytes.
|
||||
b: []byte
|
||||
switch is_left {
|
||||
case true:
|
||||
buf[off - 1] = n // n | x
|
||||
b = buf[off - 1:RIGHT_OFFSET]
|
||||
case false:
|
||||
buf[RIGHT_OFFSET] = n // x | n
|
||||
b = buf[off:]
|
||||
}
|
||||
|
||||
update(ctx, b)
|
||||
|
||||
return u64(len(b))
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
package shake implements the SHAKE XOF algorithm family.
|
||||
package shake implements the SHAKE and cSHAKE XOF algorithm families.
|
||||
|
||||
The SHA3 hash algorithm can be found in the crypto/sha3.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
|
||||
- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
|
||||
*/
|
||||
package shake
|
||||
|
||||
@@ -18,25 +19,27 @@ package shake
|
||||
|
||||
import "../_sha3"
|
||||
|
||||
// Context is a SHAKE128 or SHAKE256 instance.
|
||||
// Context is a SHAKE128, SHAKE256, cSHAKE128, or cSHAKE256 instance.
|
||||
Context :: distinct _sha3.Context
|
||||
|
||||
// init_128 initializes a Context for SHAKE128.
|
||||
init_128 :: proc(ctx: ^Context) {
|
||||
ctx.mdlen = 128 / 8
|
||||
_init(ctx)
|
||||
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 128)
|
||||
}
|
||||
|
||||
// init_256 initializes a Context for SHAKE256.
|
||||
init_256 :: proc(ctx: ^Context) {
|
||||
ctx.mdlen = 256 / 8
|
||||
_init(ctx)
|
||||
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 256)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_init :: proc(ctx: ^Context) {
|
||||
ctx.dsbyte = _sha3.DS_SHAKE
|
||||
_sha3.init(transmute(^_sha3.Context)(ctx))
|
||||
// init_cshake_128 initializes a Context for cSHAKE128.
|
||||
init_cshake_128 :: proc(ctx: ^Context, domain_sep: []byte) {
|
||||
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 128)
|
||||
}
|
||||
|
||||
// init_cshake_256 initializes a Context for cSHAKE256.
|
||||
init_cshake_256 :: proc(ctx: ^Context, domain_sep: []byte) {
|
||||
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 256)
|
||||
}
|
||||
|
||||
// write writes more data into the SHAKE instance. This MUST not be called
|
||||
|
||||
Reference in New Issue
Block a user