blobsets/src/blobsets/priv/nimcrypto/blake2.nim

459 lines
15 KiB
Nim

#
#
# NimCrypto
# (c) Copyright 2018 Eugene Kabanov
#
# See the file "LICENSE", included in this
# distribution, for details about the copyright.
#
## This module implements BLAKE2 set of cryptographic hash functions designed
## by Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.W. Phan.
##
## This module supports BLAKE2s-224/256 and BLAKE2b-384/512.
##
## Tests for SHA3-225/256/384/512 made according to
## [https://github.com/BLAKE2/BLAKE2/tree/master/testvectors].
import std/endians, hash, utils
{.deadCodeElim:on.}
type
Blake2bContext*[bits: static[int]] = object
b: array[128, byte]
h: array[8, uint64]
t: array[2, uint64]
c: int
Blake2sContext*[bits: static[int]] = object
b: array[64, byte]
h: array[8, uint32]
t: array[2, uint32]
c: int
Blake2Context* = Blake2sContext | Blake2bContext
blake2_224* = Blake2sContext[224]
blake2_256* = Blake2sContext[256]
blake2_384* = Blake2bContext[384]
blake2_512* = Blake2bContext[512]
blake2* = blake2_224 | blake2_256 | blake2_384 | blake2_512
const Sigma = [
[0'u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14'u8, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[11'u8, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[7'u8, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[9'u8, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[2'u8, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[12'u8, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[13'u8, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[6'u8, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10'u8, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
[0'u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14'u8, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]
]
const B2BIV = [
0x6A09E667F3BCC908'u64, 0xBB67AE8584CAA73B'u64,
0x3C6EF372FE94F82B'u64, 0xA54FF53A5F1D36F1'u64,
0x510E527FADE682D1'u64, 0x9B05688C2B3E6C1F'u64,
0x1F83D9ABFB41BD6B'u64, 0x5BE0CD19137E2179'u64
]
const B2SIV = [
0x6A09E667'u32, 0xBB67AE85'u32, 0x3C6EF372'u32, 0xA54FF53A'u32,
0x510E527F'u32, 0x9B05688C'u32, 0x1F83D9AB'u32, 0x5BE0CD19'u32
]
template B2B_G(v, a, b, c, d, x, y: untyped) =
(v)[(a)] = (v)[(a)] + (v)[(b)] + x
(v)[(d)] = ROR((v)[(d)] xor (v)[(a)], 32)
(v)[(c)] = (v)[(c)] + (v)[(d)]
(v)[(b)] = ROR((v)[(b)] xor (v)[(c)], 24)
(v)[(a)] = (v)[(a)] + (v)[(b)] + y
(v)[(d)] = ROR((v)[(d)] xor (v)[(a)], 16)
(v)[(c)] = (v)[(c)] + (v)[(d)]
(v)[(b)] = ROR((v)[(b)] xor (v)[(c)], 63)
template B2S_G(v, a, b, c, d, x, y: untyped) =
(v)[(a)] = (v)[(a)] + (v)[(b)] + x
(v)[(d)] = ROR((v)[(d)] xor (v)[(a)], 16)
(v)[(c)] = (v)[(c)] + (v)[(d)]
(v)[(b)] = ROR((v)[(b)] xor (v)[(c)], 12)
(v)[(a)] = (v)[(a)] + (v)[(b)] + y
(v)[(d)] = ROR((v)[(d)] xor (v)[(a)], 8)
(v)[(c)] = (v)[(c)] + (v)[(d)]
(v)[(b)] = ROR((v)[(b)] xor (v)[(c)], 7)
template B2BROUND(v, m, n: untyped) =
B2B_G(v, 0, 4, 8, 12, (m)[Sigma[(n)][ 0]], (m)[Sigma[(n)][ 1]])
B2B_G(v, 1, 5, 9, 13, (m)[Sigma[(n)][ 2]], (m)[Sigma[(n)][ 3]])
B2B_G(v, 2, 6, 10, 14, (m)[Sigma[(n)][ 4]], (m)[Sigma[(n)][ 5]])
B2B_G(v, 3, 7, 11, 15, (m)[Sigma[(n)][ 6]], (m)[Sigma[(n)][ 7]])
B2B_G(v, 0, 5, 10, 15, (m)[Sigma[(n)][ 8]], (m)[Sigma[(n)][ 9]])
B2B_G(v, 1, 6, 11, 12, (m)[Sigma[(n)][10]], (m)[Sigma[(n)][11]])
B2B_G(v, 2, 7, 8, 13, (m)[Sigma[(n)][12]], (m)[Sigma[(n)][13]])
B2B_G(v, 3, 4, 9, 14, (m)[Sigma[(n)][14]], (m)[Sigma[(n)][15]])
template B2SROUND(v, m, n: untyped) =
B2S_G(v, 0, 4, 8, 12, (m)[Sigma[(n)][ 0]], (m)[Sigma[(n)][ 1]])
B2S_G(v, 1, 5, 9, 13, (m)[Sigma[(n)][ 2]], (m)[Sigma[(n)][ 3]])
B2S_G(v, 2, 6, 10, 14, (m)[Sigma[(n)][ 4]], (m)[Sigma[(n)][ 5]])
B2S_G(v, 3, 7, 11, 15, (m)[Sigma[(n)][ 6]], (m)[Sigma[(n)][ 7]])
B2S_G(v, 0, 5, 10, 15, (m)[Sigma[(n)][ 8]], (m)[Sigma[(n)][ 9]])
B2S_G(v, 1, 6, 11, 12, (m)[Sigma[(n)][10]], (m)[Sigma[(n)][11]])
B2S_G(v, 2, 7, 8, 13, (m)[Sigma[(n)][12]], (m)[Sigma[(n)][13]])
B2S_G(v, 3, 4, 9, 14, (m)[Sigma[(n)][14]], (m)[Sigma[(n)][15]])
template BLGETU64*(p, o): uint64 =
(cast[uint64](cast[ptr byte](cast[uint](p) + o)[])) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 1))[]) shl 8) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 2))[]) shl 16) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 3))[]) shl 24) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 4))[]) shl 32) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 5))[]) shl 40) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 6))[]) shl 48) xor
(cast[uint64](cast[ptr byte](cast[uint](p) + (o + 7))[]) shl 56)
template BLGETU32*(p, o): uint32 =
(cast[uint32](cast[ptr byte](cast[uint](p) + o)[])) xor
(cast[uint32](cast[ptr byte](cast[uint](p) + (o + 1))[]) shl 8) xor
(cast[uint32](cast[ptr byte](cast[uint](p) + (o + 2))[]) shl 16) xor
(cast[uint32](cast[ptr byte](cast[uint](p) + (o + 3))[]) shl 24)
template B2BFILL(m, c: untyped) =
(m)[0] = BLGETU64(addr((c).b), 0); (m)[1] = BLGETU64(addr((c).b), 8)
(m)[2] = BLGETU64(addr((c).b), 16); (m)[3] = BLGETU64(addr((c).b), 24)
(m)[4] = BLGETU64(addr((c).b), 32); (m)[5] = BLGETU64(addr((c).b), 40)
(m)[6] = BLGETU64(addr((c).b), 48); (m)[7] = BLGETU64(addr((c).b), 56)
(m)[8] = BLGETU64(addr((c).b), 64); (m)[9] = BLGETU64(addr((c).b), 72)
(m)[10] = BLGETU64(addr((c).b), 80); (m)[11] = BLGETU64(addr((c).b), 88)
(m)[12] = BLGETU64(addr((c).b), 96); (m)[13] = BLGETU64(addr((c).b), 104)
(m)[14] = BLGETU64(addr((c).b), 112); (m)[15] = BLGETU64(addr((c).b), 120)
template B2SFILL(m, c: untyped) =
(m)[0] = BLGETU32(addr((c).b), 0); (m)[1] = BLGETU32(addr((c).b), 4)
(m)[2] = BLGETU32(addr((c).b), 8); (m)[3] = BLGETU32(addr((c).b), 12)
(m)[4] = BLGETU32(addr((c).b), 16); (m)[5] = BLGETU32(addr((c).b), 20)
(m)[6] = BLGETU32(addr((c).b), 24); (m)[7] = BLGETU32(addr((c).b), 28)
(m)[8] = BLGETU32(addr((c).b), 32); (m)[9] = BLGETU32(addr((c).b), 36)
(m)[10] = BLGETU32(addr((c).b), 40); (m)[11] = BLGETU32(addr((c).b), 44)
(m)[12] = BLGETU32(addr((c).b), 48); (m)[13] = BLGETU32(addr((c).b), 52)
(m)[14] = BLGETU32(addr((c).b), 56); (m)[15] = BLGETU32(addr((c).b), 60)
template B2BINIT(v, c: untyped) =
(v)[0] = (c).h[0]; (v)[1] = (c).h[1]
(v)[2] = (c).h[2]; (v)[3] = (c).h[3]
(v)[4] = (c).h[4]; (v)[5] = (c).h[5]
(v)[6] = (c).h[6]; (v)[7] = (c).h[7]
(v)[8] = B2BIV[0]; (v)[9] = B2BIV[1]
(v)[10] = B2BIV[2]; (v)[11] = B2BIV[3]
(v)[12] = B2BIV[4]; (v)[13] = B2BIV[5]
(v)[14] = B2BIV[6]; (v)[15] = B2BIV[7]
template B2SINIT(v, c: untyped) =
(v)[0] = (c).h[0]; (v)[1] = (c).h[1]
(v)[2] = (c).h[2]; (v)[3] = (c).h[3]
(v)[4] = (c).h[4]; (v)[5] = (c).h[5]
(v)[6] = (c).h[6]; (v)[7] = (c).h[7]
(v)[8] = B2SIV[0]; (v)[9] = B2SIV[1]
(v)[10] = B2SIV[2]; (v)[11] = B2SIV[3]
(v)[12] = B2SIV[4]; (v)[13] = B2SIV[5]
(v)[14] = B2SIV[6]; (v)[15] = B2SIV[7]
template B2STORE(v, c, n: untyped) =
(c).h[n] = (c).h[n] xor ((v)[(n)] xor (v)[(n) + 8])
proc blake2Transform(ctx: var Blake2bContext, last: bool) =
var v: array[16, uint64]
var m: array[16, uint64]
B2BINIT(v, ctx)
v[12] = v[12] xor ctx.t[0]
v[13] = v[13] xor ctx.t[1]
if last:
v[14] = not(v[14])
B2BFILL(m, ctx)
B2BROUND(v, m, 0)
B2BROUND(v, m, 1)
B2BROUND(v, m, 2)
B2BROUND(v, m, 3)
B2BROUND(v, m, 4)
B2BROUND(v, m, 5)
B2BROUND(v, m, 6)
B2BROUND(v, m, 7)
B2BROUND(v, m, 8)
B2BROUND(v, m, 9)
B2BROUND(v, m, 10)
B2BROUND(v, m, 11)
B2STORE(v, ctx, 0)
B2STORE(v, ctx, 1)
B2STORE(v, ctx, 2)
B2STORE(v, ctx, 3)
B2STORE(v, ctx, 4)
B2STORE(v, ctx, 5)
B2STORE(v, ctx, 6)
B2STORE(v, ctx, 7)
proc blake2Transform(ctx: var Blake2sContext, last: bool) =
var v: array[16, uint32]
var m: array[16, uint32]
B2SINIT(v, ctx)
v[12] = v[12] xor ctx.t[0]
v[13] = v[13] xor ctx.t[1]
if last:
v[14] = not(v[14])
B2SFILL(m, ctx)
B2SROUND(v, m, 0)
B2SROUND(v, m, 1)
B2SROUND(v, m, 2)
B2SROUND(v, m, 3)
B2SROUND(v, m, 4)
B2SROUND(v, m, 5)
B2SROUND(v, m, 6)
B2SROUND(v, m, 7)
B2SROUND(v, m, 8)
B2SROUND(v, m, 9)
B2STORE(v, ctx, 0)
B2STORE(v, ctx, 1)
B2STORE(v, ctx, 2)
B2STORE(v, ctx, 3)
B2STORE(v, ctx, 4)
B2STORE(v, ctx, 5)
B2STORE(v, ctx, 6)
B2STORE(v, ctx, 7)
template sizeDigest*(ctx: Blake2Context): uint =
(ctx.bits div 8)
template sizeBlock*(ctx: Blake2Context): uint =
when ctx is Blake2sContext:
(64)
else:
(128)
template sizeDigest*(r: typedesc[blake2]): int =
when r is blake2_224:
(28)
elif r is blake2_256:
(32)
elif r is blake2_384:
(48)
elif r is blake2_512:
(64)
template sizeBlock*(r: typedesc[blake2]): int =
when (r is blake2_224) or (r is blake2_256):
(64)
else:
(128)
proc update*(ctx: var Blake2Context, data: pointer, ulen: Natural) =
let ulen = ulen.uint
var i = 0'u
while i < ulen:
if ctx.c == int(ctx.sizeBlock):
when ctx is Blake2sContext:
ctx.t[0] = ctx.t[0] + cast[uint32](ctx.c)
if ctx.t[0] < cast[uint32](ctx.c):
ctx.t[1] = ctx.t[1] + 1
else:
ctx.t[0] = ctx.t[0] + cast[uint64](ctx.c)
if ctx.t[0] < cast[uint64](ctx.c):
ctx.t[1] = ctx.t[1] + 1
ctx.blake2Transform(false)
ctx.c = 0
var p = cast[ptr byte](cast[uint](data) + i)
ctx.b[ctx.c] = p[]
inc(ctx.c)
inc(i)
proc update*[T: bchar](ctx: var Blake2Context, data: openarray[T]) {.inline.} =
if len(data) == 0:
ctx.update(nil, 0)
else:
ctx.update(cast[ptr byte](unsafeAddr data[0]), cast[uint](len(data)))
proc finish*(ctx: var Blake2sContext, data: pointer, ulen: Natural): uint =
ctx.t[0] = ctx.t[0] + cast[uint32](ctx.c)
if ctx.t[0] < cast[uint32](ctx.c):
ctx.t[1] = ctx.t[1] + 1
while ctx.c < int(ctx.sizeBlock):
ctx.b[ctx.c] = 0
inc(ctx.c)
ctx.blake2Transform(true)
var length = int(ctx.sizeDigest)
var p = cast[ptr UncheckedArray[byte]](data)
if ulen >= ctx.sizeDigest:
for i in 0..<length:
p[i] = cast[byte]((ctx.h[i shr 2] shr (8 * (i and 3))) and 0xFF)
proc finish*(ctx: var Blake2bContext, data: pointer, ulen: Natural): uint =
let ulen = ulen.uint
ctx.t[0] = ctx.t[0] + cast[uint64](ctx.c)
if ctx.t[0] < cast[uint64](ctx.c):
ctx.t[1] = ctx.t[1] + 1
while ctx.c < int(ctx.sizeBlock):
ctx.b[ctx.c] = 0
inc(ctx.c)
ctx.blake2Transform(true)
var length = int(ctx.sizeDigest)
var p = cast[ptr UncheckedArray[byte]](data)
if ulen >= ctx.sizeDigest:
for i in 0..<length:
p[i] = cast[byte]((ctx.h[i shr 3] shr (8 * (i and 7))) and 0xFF)
proc finish*(ctx: var Blake2sContext): MDigest[ctx.bits] =
discard finish(ctx, cast[ptr byte](addr result.data[0]),
cast[uint](len(result.data)))
proc finish*(ctx: var Blake2bContext): MDigest[ctx.bits] =
discard finish(ctx, cast[ptr byte](addr result.data[0]),
cast[uint](len(result.data)))
proc finish*[T: bchar](ctx: var Blake2Context, data: var openarray[T]) =
assert(cast[uint](len(data)) >= ctx.sizeDigest)
discard ctx.finish(cast[ptr byte](addr data[0]), cast[uint](len(data)))
proc init*(ctx: var Blake2Context, key: ptr byte = nil, keylen: uint = 0'u) =
when ctx is Blake2sContext:
zeroMem(addr ctx.b[0], sizeof(byte) * 64)
ctx.h[0] = B2SIV[0]; ctx.h[1] = B2SIV[1]
ctx.h[2] = B2SIV[2]; ctx.h[3] = B2SIV[3]
ctx.h[4] = B2SIV[4]; ctx.h[5] = B2SIV[5]
ctx.h[6] = B2SIV[6]; ctx.h[7] = B2SIV[7]
let value = 0x01010000'u32 xor (cast[uint32](keylen) shl 8) xor
cast[uint32](ctx.sizeDigest)
else:
zeroMem(addr ctx.b[0], sizeof(byte) * 128)
ctx.h[0] = B2BIV[0]; ctx.h[1] = B2BIV[1]
ctx.h[2] = B2BIV[2]; ctx.h[3] = B2BIV[3]
ctx.h[4] = B2BIV[4]; ctx.h[5] = B2BIV[5]
ctx.h[6] = B2BIV[6]; ctx.h[7] = B2BIV[7]
let value = 0x01010000'u64 xor
(cast[uint64](keylen) shl 8) xor ctx.sizeDigest
ctx.h[0] = ctx.h[0] xor value
ctx.t[0] = 0
ctx.t[1] = 0
ctx.c = 0
if not isNil(key) and keylen > 0'u:
ctx.update(key, keylen)
ctx.c = int(ctx.sizeBlock)
proc init*[T: bchar](ctx: var Blake2Context, key: openarray[T]) {.inline.} =
if len(key) == 0:
ctx.init()
else:
ctx.init(cast[ptr byte](unsafeAddr key[0]), cast[uint](len(key)))
proc clear*(ctx: var Blake2Context) {.inline.} =
burnMem(ctx)
type
Blake2bParams* = object
b: array[64, byte]
Blake2sParams* = object
b: array[32, byte]
Blake2Params* = Blake2bParams | Blake2sParams
proc `digestLen=`*(p: var Blake2bParams; x: range[1..64]) =
p.b[0] = (uint8)x
proc `digestLen=`*(p: var Blake2sParams; x: range[1..32]) =
p.b[0] = (uint8)x
proc `keyLen=`*(p: var Blake2bParams; x: range[0..64]) =
p.b[1] = (uint8)x
proc `keyLen=`*(p: var Blake2sParams; x: range[0..32]) =
p.b[1] = (uint8)x
proc `fanout=`*(p: var Blake2Params; x: Natural) =
p.b[2] = (uint8)x
proc `depth=`*(p: var Blake2Params; x: Natural) =
p.b[3] = (uint8)x
proc `leafLength=`*(p: var Blake2Params; x: Natural) =
var x = x; littleEndian32(p.b[4].addr, x.addr)
proc `nodeOffset=`*(p: var Blake2bParams; x: Natural) =
var x = x; littleEndian64(p.b[8].addr, x.addr)
proc `nodeOffset=`*(p: var Blake2sParams; x: Natural) =
var tmp: int64
littleEndian64(tmp.addr, p.b[8].addr)
tmp = (tmp and 0xffffffff) or (x shl 32)
littleEndian64(p.b[8].addr, tmp.addr)
proc `nodeDepth=`*(p: var Blake2bParams; x: Natural) =
p.b[16] = (uint8)x
proc `nodeDepth=`*(p: var Blake2sParams; x: Natural) =
p.b[14] = (uint8)x
proc `innerLength=`*(p: var Blake2bParams; x: Natural) =
p.b[17] = (uint8)x
proc `innerLength=`*(p: var Blake2sParams; x: Natural) =
p.b[15] = (uint8)x
proc `salt=`*(p: var Blake2bParams; salt: pointer; len: Natural) =
copyMem(p.b[32].addr, salt, min(len, 16))
proc `salt=`*(p: var Blake2sParams; salt: pointer; len: Natural) =
copyMem(p.b[16].addr, salt, min(len, 8))
proc `personal=`*(p: var Blake2bParams; salt: pointer; len: Natural) =
copyMem(p.b[48].addr, salt, min(len, 16))
proc `personal=`*(p: var Blake2sParams; salt: pointer; len: Natural) =
copyMem(p.b[24].addr, salt, min(len, 8))
proc init*(ctx: var Blake2Context;
customize: proc(params: var Blake2Params);
key: pointer = nil, keylen = Natural(0)) =
## Initialize a BLAKE2 context with a custom parameter block.
## The `keyLen` and `digestLen` parameters are overriden after
## customization, setting them in the callback has no effect.
##
## .. code-block:: nim
##
## var ctx: blake2_512
## ctx.init do (params: var Blake2bParams):
## params.fanout = 4
## params.depth = 3
## params.salt = mySalt
##
reset(ctx.b)
reset(ctx.t)
reset(ctx.c)
when ctx is Blake2bContext:
var params: Blake2bParams
else:
var params: Blake2sParams
params.fanout = 1
params.depth = 1
# default parameters
customize(params)
# custom parameters
params.keyLen = keylen
params.digestLen = ctx.sizeDigest
# implicit parameters
for i in 0..7:
when ctx is Blake2bContext:
ctx.h[i] = cast[array[8, uint64]](params.b)[i] xor B2BIV[i]
else:
ctx.h[i] = cast[array[8, uint32]](params.b)[i] xor B2SIV[i]
if not isNil(key) and keylen > 0:
ctx.update(key, keylen)
ctx.c = int(ctx.sizeBlock)