|
@@ -1,584 +0,0 @@
|
|
|
-package jh
|
|
|
-
|
|
|
-/*
|
|
|
- Copyright 2021 zhibog
|
|
|
- Made available under the BSD-3 license.
|
|
|
-
|
|
|
- List of contributors:
|
|
|
- zhibog, dotbmp: Initial implementation.
|
|
|
-
|
|
|
- Implementation of the JH hashing algorithm, as defined in <https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html>
|
|
|
-*/
|
|
|
-
|
|
|
-import "core:os"
|
|
|
-import "core:io"
|
|
|
-
|
|
|
-/*
|
|
|
- High level API
|
|
|
-*/
|
|
|
-
|
|
|
-DIGEST_SIZE_224 :: 28
|
|
|
-DIGEST_SIZE_256 :: 32
|
|
|
-DIGEST_SIZE_384 :: 48
|
|
|
-DIGEST_SIZE_512 :: 64
|
|
|
-
|
|
|
-// hash_string_224 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
|
|
|
- return hash_bytes_224(transmute([]byte)(data))
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_224 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|
|
- hash: [DIGEST_SIZE_224]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 224
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_to_buffer_224 will hash the given input and assign the
|
|
|
-// computed hash to the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
|
|
- hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_to_buffer_224 will hash the given input and write the
|
|
|
-// computed hash into the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
|
|
- assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 224
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_stream_224 will read the stream in chunks and compute a
|
|
|
-// hash from its contents
|
|
|
-hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
|
|
- hash: [DIGEST_SIZE_224]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 224
|
|
|
- init(&ctx)
|
|
|
- buf := make([]byte, 512)
|
|
|
- defer delete(buf)
|
|
|
- read := 1
|
|
|
- for read > 0 {
|
|
|
- read, _ = io.read(s, buf)
|
|
|
- if read > 0 {
|
|
|
- update(&ctx, buf[:read])
|
|
|
- }
|
|
|
- }
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash, true
|
|
|
-}
|
|
|
-
|
|
|
-// hash_file_224 will read the file provided by the given handle
|
|
|
-// and compute a hash
|
|
|
-hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
|
|
- if !load_at_once {
|
|
|
- return hash_stream_224(os.stream_from_handle(hd))
|
|
|
- } else {
|
|
|
- if buf, ok := os.read_entire_file(hd); ok {
|
|
|
- return hash_bytes_224(buf[:]), ok
|
|
|
- }
|
|
|
- }
|
|
|
- return [DIGEST_SIZE_224]byte{}, false
|
|
|
-}
|
|
|
-
|
|
|
-hash_224 :: proc {
|
|
|
- hash_stream_224,
|
|
|
- hash_file_224,
|
|
|
- hash_bytes_224,
|
|
|
- hash_string_224,
|
|
|
- hash_bytes_to_buffer_224,
|
|
|
- hash_string_to_buffer_224,
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_256 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
|
|
|
- return hash_bytes_256(transmute([]byte)(data))
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_256 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|
|
- hash: [DIGEST_SIZE_256]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 256
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_to_buffer_256 will hash the given input and assign the
|
|
|
-// computed hash to the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
|
|
- hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_to_buffer_256 will hash the given input and write the
|
|
|
-// computed hash into the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
|
|
- assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 256
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_stream_256 will read the stream in chunks and compute a
|
|
|
-// hash from its contents
|
|
|
-hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
|
|
- hash: [DIGEST_SIZE_256]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 256
|
|
|
- init(&ctx)
|
|
|
- buf := make([]byte, 512)
|
|
|
- defer delete(buf)
|
|
|
- read := 1
|
|
|
- for read > 0 {
|
|
|
- read, _ = io.read(s, buf)
|
|
|
- if read > 0 {
|
|
|
- update(&ctx, buf[:read])
|
|
|
- }
|
|
|
- }
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash, true
|
|
|
-}
|
|
|
-
|
|
|
-// hash_file_256 will read the file provided by the given handle
|
|
|
-// and compute a hash
|
|
|
-hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
|
|
- if !load_at_once {
|
|
|
- return hash_stream_256(os.stream_from_handle(hd))
|
|
|
- } else {
|
|
|
- if buf, ok := os.read_entire_file(hd); ok {
|
|
|
- return hash_bytes_256(buf[:]), ok
|
|
|
- }
|
|
|
- }
|
|
|
- return [DIGEST_SIZE_256]byte{}, false
|
|
|
-}
|
|
|
-
|
|
|
-hash_256 :: proc {
|
|
|
- hash_stream_256,
|
|
|
- hash_file_256,
|
|
|
- hash_bytes_256,
|
|
|
- hash_string_256,
|
|
|
- hash_bytes_to_buffer_256,
|
|
|
- hash_string_to_buffer_256,
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_384 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
|
|
|
- return hash_bytes_384(transmute([]byte)(data))
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_384 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
|
|
- hash: [DIGEST_SIZE_384]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 384
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_to_buffer_384 will hash the given input and assign the
|
|
|
-// computed hash to the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
|
|
- hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_to_buffer_384 will hash the given input and write the
|
|
|
-// computed hash into the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
|
|
- assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 384
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_stream_384 will read the stream in chunks and compute a
|
|
|
-// hash from its contents
|
|
|
-hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
|
|
- hash: [DIGEST_SIZE_384]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 384
|
|
|
- init(&ctx)
|
|
|
- buf := make([]byte, 512)
|
|
|
- defer delete(buf)
|
|
|
- read := 1
|
|
|
- for read > 0 {
|
|
|
- read, _ = io.read(s, buf)
|
|
|
- if read > 0 {
|
|
|
- update(&ctx, buf[:read])
|
|
|
- }
|
|
|
- }
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash, true
|
|
|
-}
|
|
|
-
|
|
|
-// hash_file_384 will read the file provided by the given handle
|
|
|
-// and compute a hash
|
|
|
-hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
|
|
- if !load_at_once {
|
|
|
- return hash_stream_384(os.stream_from_handle(hd))
|
|
|
- } else {
|
|
|
- if buf, ok := os.read_entire_file(hd); ok {
|
|
|
- return hash_bytes_384(buf[:]), ok
|
|
|
- }
|
|
|
- }
|
|
|
- return [DIGEST_SIZE_384]byte{}, false
|
|
|
-}
|
|
|
-
|
|
|
-hash_384 :: proc {
|
|
|
- hash_stream_384,
|
|
|
- hash_file_384,
|
|
|
- hash_bytes_384,
|
|
|
- hash_string_384,
|
|
|
- hash_bytes_to_buffer_384,
|
|
|
- hash_string_to_buffer_384,
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_512 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
|
|
|
- return hash_bytes_512(transmute([]byte)(data))
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_512 will hash the given input and return the
|
|
|
-// computed hash
|
|
|
-hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|
|
- hash: [DIGEST_SIZE_512]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 512
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash
|
|
|
-}
|
|
|
-
|
|
|
-// hash_string_to_buffer_512 will hash the given input and assign the
|
|
|
-// computed hash to the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
|
|
- hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_bytes_to_buffer_512 will hash the given input and write the
|
|
|
-// computed hash into the second parameter.
|
|
|
-// It requires that the destination buffer is at least as big as the digest size
|
|
|
-hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
|
|
- assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 512
|
|
|
- init(&ctx)
|
|
|
- update(&ctx, data)
|
|
|
- final(&ctx, hash)
|
|
|
-}
|
|
|
-
|
|
|
-// hash_stream_512 will read the stream in chunks and compute a
|
|
|
-// hash from its contents
|
|
|
-hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
|
|
- hash: [DIGEST_SIZE_512]byte
|
|
|
- ctx: Jh_Context
|
|
|
- ctx.hashbitlen = 512
|
|
|
- init(&ctx)
|
|
|
- buf := make([]byte, 512)
|
|
|
- defer delete(buf)
|
|
|
- read := 1
|
|
|
- for read > 0 {
|
|
|
- read, _ = io.read(s, buf)
|
|
|
- if read > 0 {
|
|
|
- update(&ctx, buf[:read])
|
|
|
- }
|
|
|
- }
|
|
|
- final(&ctx, hash[:])
|
|
|
- return hash, true
|
|
|
-}
|
|
|
-
|
|
|
-// hash_file_512 will read the file provided by the given handle
|
|
|
-// and compute a hash
|
|
|
-hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
|
|
- if !load_at_once {
|
|
|
- return hash_stream_512(os.stream_from_handle(hd))
|
|
|
- } else {
|
|
|
- if buf, ok := os.read_entire_file(hd); ok {
|
|
|
- return hash_bytes_512(buf[:]), ok
|
|
|
- }
|
|
|
- }
|
|
|
- return [DIGEST_SIZE_512]byte{}, false
|
|
|
-}
|
|
|
-
|
|
|
-hash_512 :: proc {
|
|
|
- hash_stream_512,
|
|
|
- hash_file_512,
|
|
|
- hash_bytes_512,
|
|
|
- hash_string_512,
|
|
|
- hash_bytes_to_buffer_512,
|
|
|
- hash_string_to_buffer_512,
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- Low level API
|
|
|
-*/
|
|
|
-
|
|
|
-init :: proc(ctx: ^Jh_Context) {
|
|
|
- assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
|
|
|
- ctx.H[1] = byte(ctx.hashbitlen) & 0xff
|
|
|
- ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff
|
|
|
- F8(ctx)
|
|
|
-}
|
|
|
-
|
|
|
-update :: proc(ctx: ^Jh_Context, data: []byte) {
|
|
|
- databitlen := u64(len(data)) * 8
|
|
|
- ctx.databitlen += databitlen
|
|
|
- i := u64(0)
|
|
|
-
|
|
|
- if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) {
|
|
|
- if (databitlen & 7) == 0 {
|
|
|
- copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)])
|
|
|
- } else {
|
|
|
- copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1])
|
|
|
- }
|
|
|
- ctx.buffer_size += databitlen
|
|
|
- databitlen = 0
|
|
|
- }
|
|
|
-
|
|
|
- if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) {
|
|
|
- copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)])
|
|
|
- i = 64 - (ctx.buffer_size >> 3)
|
|
|
- databitlen = databitlen - (512 - ctx.buffer_size)
|
|
|
- F8(ctx)
|
|
|
- ctx.buffer_size = 0
|
|
|
- }
|
|
|
-
|
|
|
- for databitlen >= 512 {
|
|
|
- copy(ctx.buffer[:], data[i:i + 64])
|
|
|
- F8(ctx)
|
|
|
- i += 64
|
|
|
- databitlen -= 512
|
|
|
- }
|
|
|
-
|
|
|
- if databitlen > 0 {
|
|
|
- if (databitlen & 7) == 0 {
|
|
|
- copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)])
|
|
|
- } else {
|
|
|
- copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1])
|
|
|
- }
|
|
|
- ctx.buffer_size = databitlen
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-final :: proc(ctx: ^Jh_Context, hash: []byte) {
|
|
|
- if ctx.databitlen & 0x1ff == 0 {
|
|
|
- for i := 0; i < 64; i += 1 {
|
|
|
- ctx.buffer[i] = 0
|
|
|
- }
|
|
|
- ctx.buffer[0] = 0x80
|
|
|
- ctx.buffer[63] = byte(ctx.databitlen) & 0xff
|
|
|
- ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff
|
|
|
- ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff
|
|
|
- ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff
|
|
|
- ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff
|
|
|
- ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff
|
|
|
- ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff
|
|
|
- ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff
|
|
|
- F8(ctx)
|
|
|
- } else {
|
|
|
- if ctx.buffer_size & 7 == 0 {
|
|
|
- for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 {
|
|
|
- ctx.buffer[i] = 0
|
|
|
- }
|
|
|
- } else {
|
|
|
- for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 {
|
|
|
- ctx.buffer[i] = 0
|
|
|
- }
|
|
|
- }
|
|
|
- ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7))
|
|
|
- F8(ctx)
|
|
|
- for i := 0; i < 64; i += 1 {
|
|
|
- ctx.buffer[i] = 0
|
|
|
- }
|
|
|
- ctx.buffer[63] = byte(ctx.databitlen) & 0xff
|
|
|
- ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff
|
|
|
- ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff
|
|
|
- ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff
|
|
|
- ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff
|
|
|
- ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff
|
|
|
- ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff
|
|
|
- ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff
|
|
|
- F8(ctx)
|
|
|
- }
|
|
|
- switch ctx.hashbitlen {
|
|
|
- case 224: copy(hash[:], ctx.H[100:128])
|
|
|
- case 256: copy(hash[:], ctx.H[96:128])
|
|
|
- case 384: copy(hash[:], ctx.H[80:128])
|
|
|
- case 512: copy(hash[:], ctx.H[64:128])
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- JH implementation
|
|
|
-*/
|
|
|
-
|
|
|
-ROUNDCONSTANT_ZERO := [64]byte {
|
|
|
- 0x6, 0xa, 0x0, 0x9, 0xe, 0x6, 0x6, 0x7,
|
|
|
- 0xf, 0x3, 0xb, 0xc, 0xc, 0x9, 0x0, 0x8,
|
|
|
- 0xb, 0x2, 0xf, 0xb, 0x1, 0x3, 0x6, 0x6,
|
|
|
- 0xe, 0xa, 0x9, 0x5, 0x7, 0xd, 0x3, 0xe,
|
|
|
- 0x3, 0xa, 0xd, 0xe, 0xc, 0x1, 0x7, 0x5,
|
|
|
- 0x1, 0x2, 0x7, 0x7, 0x5, 0x0, 0x9, 0x9,
|
|
|
- 0xd, 0xa, 0x2, 0xf, 0x5, 0x9, 0x0, 0xb,
|
|
|
- 0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa,
|
|
|
-}
|
|
|
-
|
|
|
-SBOX := [2][16]byte {
|
|
|
- {9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14},
|
|
|
- {3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8},
|
|
|
-}
|
|
|
-
|
|
|
-Jh_Context :: struct {
|
|
|
- hashbitlen: int,
|
|
|
- databitlen: u64,
|
|
|
- buffer_size: u64,
|
|
|
- H: [128]byte,
|
|
|
- A: [256]byte,
|
|
|
- roundconstant: [64]byte,
|
|
|
- buffer: [64]byte,
|
|
|
-}
|
|
|
-
|
|
|
-E8_finaldegroup :: proc(ctx: ^Jh_Context) {
|
|
|
- t0,t1,t2,t3: byte
|
|
|
- tem: [256]byte
|
|
|
- for i := 0; i < 128; i += 1 {
|
|
|
- tem[i] = ctx.A[i << 1]
|
|
|
- tem[i + 128] = ctx.A[(i << 1) + 1]
|
|
|
- }
|
|
|
- for i := 0; i < 128; i += 1 {
|
|
|
- ctx.H[i] = 0
|
|
|
- }
|
|
|
- for i := 0; i < 256; i += 1 {
|
|
|
- t0 = (tem[i] >> 3) & 1
|
|
|
- t1 = (tem[i] >> 2) & 1
|
|
|
- t2 = (tem[i] >> 1) & 1
|
|
|
- t3 = (tem[i] >> 0) & 1
|
|
|
-
|
|
|
- ctx.H[uint(i) >> 3] |= t0 << (7 - (uint(i) & 7))
|
|
|
- ctx.H[(uint(i) + 256) >> 3] |= t1 << (7 - (uint(i) & 7))
|
|
|
- ctx.H[(uint(i) + 512) >> 3] |= t2 << (7 - (uint(i) & 7))
|
|
|
- ctx.H[(uint(i) + 768) >> 3] |= t3 << (7 - (uint(i) & 7))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-update_roundconstant :: proc(ctx: ^Jh_Context) {
|
|
|
- tem: [64]byte
|
|
|
- t: byte
|
|
|
- for i := 0; i < 64; i += 1 {
|
|
|
- tem[i] = SBOX[0][ctx.roundconstant[i]]
|
|
|
- }
|
|
|
- for i := 0; i < 64; i += 2 {
|
|
|
- tem[i + 1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf
|
|
|
- tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf
|
|
|
- }
|
|
|
- for i := 0; i < 64; i += 4 {
|
|
|
- t = tem[i + 2]
|
|
|
- tem[i + 2] = tem[i + 3]
|
|
|
- tem[i + 3] = t
|
|
|
- }
|
|
|
- for i := 0; i < 32; i += 1 {
|
|
|
- ctx.roundconstant[i] = tem[i << 1]
|
|
|
- ctx.roundconstant[i + 32] = tem[(i << 1) + 1]
|
|
|
- }
|
|
|
- for i := 32; i < 64; i += 2 {
|
|
|
- t = ctx.roundconstant[i]
|
|
|
- ctx.roundconstant[i] = ctx.roundconstant[i + 1]
|
|
|
- ctx.roundconstant[i + 1] = t
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-R8 :: proc(ctx: ^Jh_Context) {
|
|
|
- t: byte
|
|
|
- tem, roundconstant_expanded: [256]byte
|
|
|
- for i := u32(0); i < 256; i += 1 {
|
|
|
- roundconstant_expanded[i] = (ctx.roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1
|
|
|
- }
|
|
|
- for i := 0; i < 256; i += 1 {
|
|
|
- tem[i] = SBOX[roundconstant_expanded[i]][ctx.A[i]]
|
|
|
- }
|
|
|
- for i := 0; i < 256; i += 2 {
|
|
|
- tem[i+1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf
|
|
|
- tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf
|
|
|
- }
|
|
|
- for i := 0; i < 256; i += 4 {
|
|
|
- t = tem[i + 2]
|
|
|
- tem[i+2] = tem[i + 3]
|
|
|
- tem[i+3] = t
|
|
|
- }
|
|
|
- for i := 0; i < 128; i += 1 {
|
|
|
- ctx.A[i] = tem[i << 1]
|
|
|
- ctx.A[i + 128] = tem[(i << 1) + 1]
|
|
|
- }
|
|
|
- for i := 128; i < 256; i += 2 {
|
|
|
- t = ctx.A[i]
|
|
|
- ctx.A[i] = ctx.A[i + 1]
|
|
|
- ctx.A[i + 1] = t
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-E8_initialgroup :: proc(ctx: ^Jh_Context) {
|
|
|
- t0, t1, t2, t3: byte
|
|
|
- tem: [256]byte
|
|
|
- for i := u32(0); i < 256; i += 1 {
|
|
|
- t0 = (ctx.H[i >> 3] >> (7 - (i & 7))) & 1
|
|
|
- t1 = (ctx.H[(i + 256) >> 3] >> (7 - (i & 7))) & 1
|
|
|
- t2 = (ctx.H[(i + 512) >> 3] >> (7 - (i & 7))) & 1
|
|
|
- t3 = (ctx.H[(i + 768) >> 3] >> (7 - (i & 7))) & 1
|
|
|
- tem[i] = (t0 << 3) | (t1 << 2) | (t2 << 1) | (t3 << 0)
|
|
|
- }
|
|
|
- for i := 0; i < 128; i += 1 {
|
|
|
- ctx.A[i << 1] = tem[i]
|
|
|
- ctx.A[(i << 1) + 1] = tem[i + 128]
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-E8 :: proc(ctx: ^Jh_Context) {
|
|
|
- for i := 0; i < 64; i += 1 {
|
|
|
- ctx.roundconstant[i] = ROUNDCONSTANT_ZERO[i]
|
|
|
- }
|
|
|
- E8_initialgroup(ctx)
|
|
|
- for i := 0; i < 42; i += 1 {
|
|
|
- R8(ctx)
|
|
|
- update_roundconstant(ctx)
|
|
|
- }
|
|
|
- E8_finaldegroup(ctx)
|
|
|
-}
|
|
|
-
|
|
|
-F8 :: proc(ctx: ^Jh_Context) {
|
|
|
- for i := 0; i < 64; i += 1 {
|
|
|
- ctx.H[i] ~= ctx.buffer[i]
|
|
|
- }
|
|
|
- E8(ctx)
|
|
|
- for i := 0; i < 64; i += 1 {
|
|
|
- ctx.H[i + 64] ~= ctx.buffer[i]
|
|
|
- }
|
|
|
-}
|