mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-19 20:32:21 -07:00
core/crypto/siphash: Fix the low-level API
The `update` and `final` routines were written with the assumption that update will only be called once, and that the underlying data does not change between the calls.
This commit is contained in:
@@ -243,43 +243,45 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
|
||||
ctx.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||
|
||||
ctx.last_block = 0
|
||||
ctx.total_length = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
assert(ctx.is_initialized, "crypto/siphash: Context is not initialized")
|
||||
ctx.last_block = len(data) / 8 * 8
|
||||
ctx.buf = data
|
||||
i := 0
|
||||
m: u64
|
||||
for i < ctx.last_block {
|
||||
m = endian.unchecked_get_u64le(ctx.buf[i:])
|
||||
i += 8
|
||||
assert(ctx.is_initialized, "crypto/siphash: context is not initialized")
|
||||
|
||||
ctx.v3 ~= m
|
||||
for _ in 0 ..< ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
data := data
|
||||
ctx.total_length += len(data)
|
||||
if ctx.last_block > 0 {
|
||||
n := copy(ctx.buf[ctx.last_block:], data)
|
||||
ctx.last_block += n
|
||||
if ctx.last_block == BLOCK_SIZE {
|
||||
block(ctx, ctx.buf[:])
|
||||
ctx.last_block = 0
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCK_SIZE {
|
||||
n := len(data) &~ (BLOCK_SIZE - 1)
|
||||
block(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.last_block = copy(ctx.buf[:], data)
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Context, dst: ^u64) {
|
||||
m: u64
|
||||
for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 {
|
||||
m <<= 8
|
||||
m |= u64(ctx.buf[i] & 0xff)
|
||||
}
|
||||
m |= u64(len(ctx.buf) << 56)
|
||||
assert(ctx.is_initialized, "crypto/siphash: context is not initialized")
|
||||
|
||||
ctx.v3 ~= m
|
||||
tmp: [BLOCK_SIZE]byte
|
||||
copy(tmp[:], ctx.buf[:ctx.last_block])
|
||||
tmp[7] = byte(ctx.total_length & 0xff)
|
||||
block(ctx, tmp[:])
|
||||
|
||||
for _ in 0 ..< ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
ctx.v2 ~= 0xff
|
||||
|
||||
for _ in 0 ..< ctx.d_rounds {
|
||||
@@ -296,21 +298,43 @@ reset :: proc(ctx: ^Context) {
|
||||
ctx.v0, ctx.v1 = 0, 0
|
||||
ctx.v2, ctx.v3 = 0, 0
|
||||
ctx.last_block = 0
|
||||
ctx.total_length = 0
|
||||
ctx.c_rounds = 0
|
||||
ctx.d_rounds = 0
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
BLOCK_SIZE :: 8
|
||||
|
||||
Context :: struct {
|
||||
v0, v1, v2, v3: u64, // State values
|
||||
k0, k1: u64, // Split key
|
||||
c_rounds: int, // Number of message rounds
|
||||
d_rounds: int, // Number of finalization rounds
|
||||
buf: []byte, // Provided data
|
||||
buf: [BLOCK_SIZE]byte, // Provided data
|
||||
last_block: int, // Offset from the last block
|
||||
total_length: int,
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
@(private)
|
||||
block :: proc "contextless" (ctx: ^Context, buf: []byte) {
|
||||
buf := buf
|
||||
|
||||
for len(buf) >= BLOCK_SIZE {
|
||||
m := endian.unchecked_get_u64le(buf)
|
||||
|
||||
ctx.v3 ~= m
|
||||
for _ in 0 ..< ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
|
||||
buf = buf[BLOCK_SIZE:]
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||
|
||||
Reference in New Issue
Block a user