mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00: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.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||||
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||||
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||||
|
|
||||||
|
ctx.last_block = 0
|
||||||
|
ctx.total_length = 0
|
||||||
|
|
||||||
ctx.is_initialized = true
|
ctx.is_initialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
update :: proc(ctx: ^Context, data: []byte) {
|
update :: proc(ctx: ^Context, data: []byte) {
|
||||||
assert(ctx.is_initialized, "crypto/siphash: Context is not initialized")
|
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
|
|
||||||
|
|
||||||
ctx.v3 ~= m
|
data := data
|
||||||
for _ in 0 ..< ctx.c_rounds {
|
ctx.total_length += len(data)
|
||||||
_compress(ctx)
|
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
|
||||||
}
|
}
|
||||||
|
data = data[n:]
|
||||||
ctx.v0 ~= m
|
}
|
||||||
|
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) {
|
final :: proc(ctx: ^Context, dst: ^u64) {
|
||||||
m: u64
|
assert(ctx.is_initialized, "crypto/siphash: context is not initialized")
|
||||||
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)
|
|
||||||
|
|
||||||
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
|
ctx.v2 ~= 0xff
|
||||||
|
|
||||||
for _ in 0 ..< ctx.d_rounds {
|
for _ in 0 ..< ctx.d_rounds {
|
||||||
@@ -296,21 +298,43 @@ reset :: proc(ctx: ^Context) {
|
|||||||
ctx.v0, ctx.v1 = 0, 0
|
ctx.v0, ctx.v1 = 0, 0
|
||||||
ctx.v2, ctx.v3 = 0, 0
|
ctx.v2, ctx.v3 = 0, 0
|
||||||
ctx.last_block = 0
|
ctx.last_block = 0
|
||||||
|
ctx.total_length = 0
|
||||||
ctx.c_rounds = 0
|
ctx.c_rounds = 0
|
||||||
ctx.d_rounds = 0
|
ctx.d_rounds = 0
|
||||||
ctx.is_initialized = false
|
ctx.is_initialized = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLOCK_SIZE :: 8
|
||||||
|
|
||||||
Context :: struct {
|
Context :: struct {
|
||||||
v0, v1, v2, v3: u64, // State values
|
v0, v1, v2, v3: u64, // State values
|
||||||
k0, k1: u64, // Split key
|
k0, k1: u64, // Split key
|
||||||
c_rounds: int, // Number of message rounds
|
c_rounds: int, // Number of message rounds
|
||||||
d_rounds: int, // Number of finalization 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
|
last_block: int, // Offset from the last block
|
||||||
|
total_length: int,
|
||||||
is_initialized: bool,
|
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)
|
@(private)
|
||||||
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||||
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||||
|
|||||||
Reference in New Issue
Block a user