|
@@ -1,726 +0,0 @@
|
|
|
-package blake
|
|
|
-
|
|
|
-/*
|
|
|
- Copyright 2021 zhibog
|
|
|
- Made available under the BSD-3 license.
|
|
|
-
|
|
|
- List of contributors:
|
|
|
- zhibog, dotbmp: Initial implementation.
|
|
|
-
|
|
|
- Implementation of the BLAKE hashing algorithm, as defined in <https://web.archive.org/web/20190915215948/https://131002.net/blake>
|
|
|
-*/
|
|
|
-
|
|
|
-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 "contextless" (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 "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte {
|
|
|
- hash: [DIGEST_SIZE_224]byte
|
|
|
- ctx: Blake256_Context
|
|
|
- ctx.is224 = true
|
|
|
- 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: Blake256_Context
|
|
|
- ctx.is224 = true
|
|
|
- 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: Blake256_Context
|
|
|
- ctx.is224 = true
|
|
|
- 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 "contextless" (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 "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte {
|
|
|
- hash: [DIGEST_SIZE_256]byte
|
|
|
- ctx: Blake256_Context
|
|
|
- ctx.is224 = false
|
|
|
- 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: Blake256_Context
|
|
|
- ctx.is224 = false
|
|
|
- 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: Blake256_Context
|
|
|
- ctx.is224 = false
|
|
|
- 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 "contextless" (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 "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte {
|
|
|
- hash: [DIGEST_SIZE_384]byte
|
|
|
- ctx: Blake512_Context
|
|
|
- ctx.is384 = true
|
|
|
- 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: Blake512_Context
|
|
|
- ctx.is384 = true
|
|
|
- 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: Blake512_Context
|
|
|
- ctx.is384 = true
|
|
|
- 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 "contextless" (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 "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte {
|
|
|
- hash: [DIGEST_SIZE_512]byte
|
|
|
- ctx: Blake512_Context
|
|
|
- ctx.is384 = false
|
|
|
- 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: Blake512_Context
|
|
|
- ctx.is384 = false
|
|
|
- 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: Blake512_Context
|
|
|
- ctx.is384 = false
|
|
|
- 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 "contextless" (ctx: ^$T) {
|
|
|
- when T == Blake256_Context {
|
|
|
- if ctx.is224 {
|
|
|
- ctx.h[0] = 0xc1059ed8
|
|
|
- ctx.h[1] = 0x367cd507
|
|
|
- ctx.h[2] = 0x3070dd17
|
|
|
- ctx.h[3] = 0xf70e5939
|
|
|
- ctx.h[4] = 0xffc00b31
|
|
|
- ctx.h[5] = 0x68581511
|
|
|
- ctx.h[6] = 0x64f98fa7
|
|
|
- ctx.h[7] = 0xbefa4fa4
|
|
|
- } else {
|
|
|
- ctx.h[0] = 0x6a09e667
|
|
|
- ctx.h[1] = 0xbb67ae85
|
|
|
- ctx.h[2] = 0x3c6ef372
|
|
|
- ctx.h[3] = 0xa54ff53a
|
|
|
- ctx.h[4] = 0x510e527f
|
|
|
- ctx.h[5] = 0x9b05688c
|
|
|
- ctx.h[6] = 0x1f83d9ab
|
|
|
- ctx.h[7] = 0x5be0cd19
|
|
|
- }
|
|
|
- } else when T == Blake512_Context {
|
|
|
- if ctx.is384 {
|
|
|
- ctx.h[0] = 0xcbbb9d5dc1059ed8
|
|
|
- ctx.h[1] = 0x629a292a367cd507
|
|
|
- ctx.h[2] = 0x9159015a3070dd17
|
|
|
- ctx.h[3] = 0x152fecd8f70e5939
|
|
|
- ctx.h[4] = 0x67332667ffc00b31
|
|
|
- ctx.h[5] = 0x8eb44a8768581511
|
|
|
- ctx.h[6] = 0xdb0c2e0d64f98fa7
|
|
|
- ctx.h[7] = 0x47b5481dbefa4fa4
|
|
|
- } else {
|
|
|
- ctx.h[0] = 0x6a09e667f3bcc908
|
|
|
- ctx.h[1] = 0xbb67ae8584caa73b
|
|
|
- ctx.h[2] = 0x3c6ef372fe94f82b
|
|
|
- ctx.h[3] = 0xa54ff53a5f1d36f1
|
|
|
- ctx.h[4] = 0x510e527fade682d1
|
|
|
- ctx.h[5] = 0x9b05688c2b3e6c1f
|
|
|
- ctx.h[6] = 0x1f83d9abfb41bd6b
|
|
|
- ctx.h[7] = 0x5be0cd19137e2179
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-update :: proc "contextless" (ctx: ^$T, data: []byte) {
|
|
|
- data := data
|
|
|
- when T == Blake256_Context {
|
|
|
- if ctx.nx > 0 {
|
|
|
- n := copy(ctx.x[ctx.nx:], data)
|
|
|
- ctx.nx += n
|
|
|
- if ctx.nx == BLOCKSIZE_256 {
|
|
|
- block256(ctx, ctx.x[:])
|
|
|
- ctx.nx = 0
|
|
|
- }
|
|
|
- data = data[n:]
|
|
|
- }
|
|
|
- if len(data) >= BLOCKSIZE_256 {
|
|
|
- n := len(data) &~ (BLOCKSIZE_256 - 1)
|
|
|
- block256(ctx, data[:n])
|
|
|
- data = data[n:]
|
|
|
- }
|
|
|
- if len(data) > 0 {
|
|
|
- ctx.nx = copy(ctx.x[:], data)
|
|
|
- }
|
|
|
- } else when T == Blake512_Context {
|
|
|
- if ctx.nx > 0 {
|
|
|
- n := copy(ctx.x[ctx.nx:], data)
|
|
|
- ctx.nx += n
|
|
|
- if ctx.nx == BLOCKSIZE_512 {
|
|
|
- block512(ctx, ctx.x[:])
|
|
|
- ctx.nx = 0
|
|
|
- }
|
|
|
- data = data[n:]
|
|
|
- }
|
|
|
- if len(data) >= BLOCKSIZE_512 {
|
|
|
- n := len(data) &~ (BLOCKSIZE_512 - 1)
|
|
|
- block512(ctx, data[:n])
|
|
|
- data = data[n:]
|
|
|
- }
|
|
|
- if len(data) > 0 {
|
|
|
- ctx.nx = copy(ctx.x[:], data)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-final :: proc "contextless" (ctx: ^$T, hash: []byte) {
|
|
|
- when T == Blake256_Context {
|
|
|
- tmp: [65]byte
|
|
|
- } else when T == Blake512_Context {
|
|
|
- tmp: [129]byte
|
|
|
- }
|
|
|
- nx := u64(ctx.nx)
|
|
|
- tmp[0] = 0x80
|
|
|
- length := (ctx.t + nx) << 3
|
|
|
-
|
|
|
- when T == Blake256_Context {
|
|
|
- if nx == 55 {
|
|
|
- if ctx.is224 {
|
|
|
- write_additional(ctx, {0x80})
|
|
|
- } else {
|
|
|
- write_additional(ctx, {0x81})
|
|
|
- }
|
|
|
- } else {
|
|
|
- if nx < 55 {
|
|
|
- if nx == 0 {
|
|
|
- ctx.nullt = true
|
|
|
- }
|
|
|
- write_additional(ctx, tmp[0 : 55 - nx])
|
|
|
- } else {
|
|
|
- write_additional(ctx, tmp[0 : 64 - nx])
|
|
|
- write_additional(ctx, tmp[1:56])
|
|
|
- ctx.nullt = true
|
|
|
- }
|
|
|
- if ctx.is224 {
|
|
|
- write_additional(ctx, {0x00})
|
|
|
- } else {
|
|
|
- write_additional(ctx, {0x01})
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for i : uint = 0; i < 8; i += 1 {
|
|
|
- tmp[i] = byte(length >> (56 - 8 * i))
|
|
|
- }
|
|
|
- write_additional(ctx, tmp[0:8])
|
|
|
-
|
|
|
- h := ctx.h[:]
|
|
|
- if ctx.is224 {
|
|
|
- h = h[0:7]
|
|
|
- }
|
|
|
- for s, i in h {
|
|
|
- hash[i * 4] = byte(s >> 24)
|
|
|
- hash[i * 4 + 1] = byte(s >> 16)
|
|
|
- hash[i * 4 + 2] = byte(s >> 8)
|
|
|
- hash[i * 4 + 3] = byte(s)
|
|
|
- }
|
|
|
- } else when T == Blake512_Context {
|
|
|
- if nx == 111 {
|
|
|
- if ctx.is384 {
|
|
|
- write_additional(ctx, {0x80})
|
|
|
- } else {
|
|
|
- write_additional(ctx, {0x81})
|
|
|
- }
|
|
|
- } else {
|
|
|
- if nx < 111 {
|
|
|
- if nx == 0 {
|
|
|
- ctx.nullt = true
|
|
|
- }
|
|
|
- write_additional(ctx, tmp[0 : 111 - nx])
|
|
|
- } else {
|
|
|
- write_additional(ctx, tmp[0 : 128 - nx])
|
|
|
- write_additional(ctx, tmp[1:112])
|
|
|
- ctx.nullt = true
|
|
|
- }
|
|
|
- if ctx.is384 {
|
|
|
- write_additional(ctx, {0x00})
|
|
|
- } else {
|
|
|
- write_additional(ctx, {0x01})
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for i : uint = 0; i < 16; i += 1 {
|
|
|
- tmp[i] = byte(length >> (120 - 8 * i))
|
|
|
- }
|
|
|
- write_additional(ctx, tmp[0:16])
|
|
|
-
|
|
|
- h := ctx.h[:]
|
|
|
- if ctx.is384 {
|
|
|
- h = h[0:6]
|
|
|
- }
|
|
|
- for s, i in h {
|
|
|
- hash[i * 8] = byte(s >> 56)
|
|
|
- hash[i * 8 + 1] = byte(s >> 48)
|
|
|
- hash[i * 8 + 2] = byte(s >> 40)
|
|
|
- hash[i * 8 + 3] = byte(s >> 32)
|
|
|
- hash[i * 8 + 4] = byte(s >> 24)
|
|
|
- hash[i * 8 + 5] = byte(s >> 16)
|
|
|
- hash[i * 8 + 6] = byte(s >> 8)
|
|
|
- hash[i * 8 + 7] = byte(s)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-SIZE_224 :: 28
|
|
|
-SIZE_256 :: 32
|
|
|
-SIZE_384 :: 48
|
|
|
-SIZE_512 :: 64
|
|
|
-BLOCKSIZE_256 :: 64
|
|
|
-BLOCKSIZE_512 :: 128
|
|
|
-
|
|
|
-Blake256_Context :: struct {
|
|
|
- h: [8]u32,
|
|
|
- s: [4]u32,
|
|
|
- t: u64,
|
|
|
- x: [64]byte,
|
|
|
- nx: int,
|
|
|
- is224: bool,
|
|
|
- nullt: bool,
|
|
|
-}
|
|
|
-
|
|
|
-Blake512_Context :: struct {
|
|
|
- h: [8]u64,
|
|
|
- s: [4]u64,
|
|
|
- t: u64,
|
|
|
- x: [128]byte,
|
|
|
- nx: int,
|
|
|
- is384: bool,
|
|
|
- nullt: bool,
|
|
|
-}
|
|
|
-
|
|
|
-SIGMA := [?]int {
|
|
|
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
|
- 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
|
|
- 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
|
|
|
- 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
|
|
|
- 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
|
|
|
- 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
|
|
|
- 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
|
|
|
- 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
|
|
|
- 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
|
|
|
- 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
|
|
|
-}
|
|
|
-
|
|
|
-U256 := [16]u32 {
|
|
|
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
|
|
- 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
|
|
- 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
|
|
- 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
|
|
-}
|
|
|
-
|
|
|
-U512 := [16]u64 {
|
|
|
- 0x243f6a8885a308d3, 0x13198a2e03707344, 0xa4093822299f31d0, 0x082efa98ec4e6c89,
|
|
|
- 0x452821e638d01377, 0xbe5466cf34e90c6c, 0xc0ac29b7c97c50dd, 0x3f84d5b5b5470917,
|
|
|
- 0x9216d5d98979fb1b, 0xd1310ba698dfb5ac, 0x2ffd72dbd01adfb7, 0xb8e1afed6a267e96,
|
|
|
- 0xba7c9045f12c7f99, 0x24a19947b3916cf7, 0x0801f2e2858efc16, 0x636920d871574e69,
|
|
|
-}
|
|
|
-
|
|
|
-G256 :: #force_inline proc "contextless" (a, b, c, d: u32, m: [16]u32, i, j: int) -> (u32, u32, u32, u32) {
|
|
|
- a, b, c, d := a, b, c, d
|
|
|
- a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
|
|
|
- a += b
|
|
|
- d ~= a
|
|
|
- d = d << (32 - 16) | d >> 16
|
|
|
- c += d
|
|
|
- b ~= c
|
|
|
- b = b << (32 - 12) | b >> 12
|
|
|
- a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j)]]
|
|
|
- a += b
|
|
|
- d ~= a
|
|
|
- d = d << (32 - 8) | d >> 8
|
|
|
- c += d
|
|
|
- b ~= c
|
|
|
- b = b << (32 - 7) | b >> 7
|
|
|
- return a, b, c, d
|
|
|
-}
|
|
|
-
|
|
|
-G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int) -> (u64, u64, u64, u64) {
|
|
|
- a, b, c, d := a, b, c, d
|
|
|
- a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
|
|
|
- a += b
|
|
|
- d ~= a
|
|
|
- d = d << (64 - 32) | d >> 32
|
|
|
- c += d
|
|
|
- b ~= c
|
|
|
- b = b << (64 - 25) | b >> 25
|
|
|
- a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j)]]
|
|
|
- a += b
|
|
|
- d ~= a
|
|
|
- d = d << (64 - 16) | d >> 16
|
|
|
- c += d
|
|
|
- b ~= c
|
|
|
- b = b << (64 - 11) | b >> 11
|
|
|
- return a, b, c, d
|
|
|
-}
|
|
|
-
|
|
|
-block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check {
|
|
|
- i, j: int = ---, ---
|
|
|
- v, m: [16]u32 = ---, ---
|
|
|
- p := p
|
|
|
- for len(p) >= BLOCKSIZE_256 {
|
|
|
- v[0] = ctx.h[0]
|
|
|
- v[1] = ctx.h[1]
|
|
|
- v[2] = ctx.h[2]
|
|
|
- v[3] = ctx.h[3]
|
|
|
- v[4] = ctx.h[4]
|
|
|
- v[5] = ctx.h[5]
|
|
|
- v[6] = ctx.h[6]
|
|
|
- v[7] = ctx.h[7]
|
|
|
- v[8] = ctx.s[0] ~ U256[0]
|
|
|
- v[9] = ctx.s[1] ~ U256[1]
|
|
|
- v[10] = ctx.s[2] ~ U256[2]
|
|
|
- v[11] = ctx.s[3] ~ U256[3]
|
|
|
- v[12] = U256[4]
|
|
|
- v[13] = U256[5]
|
|
|
- v[14] = U256[6]
|
|
|
- v[15] = U256[7]
|
|
|
-
|
|
|
- ctx.t += 512
|
|
|
- if !ctx.nullt {
|
|
|
- v[12] ~= u32(ctx.t)
|
|
|
- v[13] ~= u32(ctx.t)
|
|
|
- v[14] ~= u32(ctx.t >> 32)
|
|
|
- v[15] ~= u32(ctx.t >> 32)
|
|
|
- }
|
|
|
-
|
|
|
- for i, j = 0, 0; i < 16; i, j = i+1, j+4 {
|
|
|
- m[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3])
|
|
|
- }
|
|
|
-
|
|
|
- for i = 0; i < 14; i += 1 {
|
|
|
- v[0], v[4], v[8], v[12] = G256(v[0], v[4], v[8], v[12], m, i, 0)
|
|
|
- v[1], v[5], v[9], v[13] = G256(v[1], v[5], v[9], v[13], m, i, 1)
|
|
|
- v[2], v[6], v[10], v[14] = G256(v[2], v[6], v[10], v[14], m, i, 2)
|
|
|
- v[3], v[7], v[11], v[15] = G256(v[3], v[7], v[11], v[15], m, i, 3)
|
|
|
- v[0], v[5], v[10], v[15] = G256(v[0], v[5], v[10], v[15], m, i, 4)
|
|
|
- v[1], v[6], v[11], v[12] = G256(v[1], v[6], v[11], v[12], m, i, 5)
|
|
|
- v[2], v[7], v[8], v[13] = G256(v[2], v[7], v[8], v[13], m, i, 6)
|
|
|
- v[3], v[4], v[9], v[14] = G256(v[3], v[4], v[9], v[14], m, i, 7)
|
|
|
- }
|
|
|
-
|
|
|
- for i = 0; i < 8; i += 1 {
|
|
|
- ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
|
|
|
- }
|
|
|
- p = p[BLOCKSIZE_256:]
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check {
|
|
|
- i, j: int = ---, ---
|
|
|
- v, m: [16]u64 = ---, ---
|
|
|
- p := p
|
|
|
- for len(p) >= BLOCKSIZE_512 {
|
|
|
- v[0] = ctx.h[0]
|
|
|
- v[1] = ctx.h[1]
|
|
|
- v[2] = ctx.h[2]
|
|
|
- v[3] = ctx.h[3]
|
|
|
- v[4] = ctx.h[4]
|
|
|
- v[5] = ctx.h[5]
|
|
|
- v[6] = ctx.h[6]
|
|
|
- v[7] = ctx.h[7]
|
|
|
- v[8] = ctx.s[0] ~ U512[0]
|
|
|
- v[9] = ctx.s[1] ~ U512[1]
|
|
|
- v[10] = ctx.s[2] ~ U512[2]
|
|
|
- v[11] = ctx.s[3] ~ U512[3]
|
|
|
- v[12] = U512[4]
|
|
|
- v[13] = U512[5]
|
|
|
- v[14] = U512[6]
|
|
|
- v[15] = U512[7]
|
|
|
-
|
|
|
- ctx.t += 1024
|
|
|
- if !ctx.nullt {
|
|
|
- v[12] ~= ctx.t
|
|
|
- v[13] ~= ctx.t
|
|
|
- v[14] ~= 0
|
|
|
- v[15] ~= 0
|
|
|
- }
|
|
|
-
|
|
|
- for i, j = 0, 0; i < 16; i, j = i + 1, j + 8 {
|
|
|
- m[i] = u64(p[j]) << 56 | u64(p[j + 1]) << 48 | u64(p[j + 2]) << 40 | u64(p[j + 3]) << 32 |
|
|
|
- u64(p[j + 4]) << 24 | u64(p[j + 5]) << 16 | u64(p[j + 6]) << 8 | u64(p[j + 7])
|
|
|
- }
|
|
|
- for i = 0; i < 16; i += 1 {
|
|
|
- v[0], v[4], v[8], v[12] = G512(v[0], v[4], v[8], v[12], m, i, 0)
|
|
|
- v[1], v[5], v[9], v[13] = G512(v[1], v[5], v[9], v[13], m, i, 1)
|
|
|
- v[2], v[6], v[10], v[14] = G512(v[2], v[6], v[10], v[14], m, i, 2)
|
|
|
- v[3], v[7], v[11], v[15] = G512(v[3], v[7], v[11], v[15], m, i, 3)
|
|
|
- v[0], v[5], v[10], v[15] = G512(v[0], v[5], v[10], v[15], m, i, 4)
|
|
|
- v[1], v[6], v[11], v[12] = G512(v[1], v[6], v[11], v[12], m, i, 5)
|
|
|
- v[2], v[7], v[8], v[13] = G512(v[2], v[7], v[8], v[13], m, i, 6)
|
|
|
- v[3], v[4], v[9], v[14] = G512(v[3], v[4], v[9], v[14], m, i, 7)
|
|
|
- }
|
|
|
-
|
|
|
- for i = 0; i < 8; i += 1 {
|
|
|
- ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
|
|
|
- }
|
|
|
- p = p[BLOCKSIZE_512:]
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-write_additional :: proc "contextless" (ctx: ^$T, data: []byte) {
|
|
|
- ctx.t -= u64(len(data)) << 3
|
|
|
- update(ctx, data)
|
|
|
-}
|