From 0a9ade9f67ecb8ce27d08206c73ce1bf8682aca3 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 19 Mar 2019 15:04:58 +0100 Subject: [PATCH] Bundle Nimcrypto TODO: create a dedicated, high-performance BLAKE2 library. --- blobsets.nimble | 2 +- src/blobsets.nim | 5 +- src/blobsets/filestores.nim | 2 +- src/blobsets/priv/nimcrypto.nim | 19 + src/blobsets/priv/nimcrypto/LICENSE | 21 + src/blobsets/priv/nimcrypto/bcmode.nim | 1245 ++++++++++++++++++++++ src/blobsets/priv/nimcrypto/blake2.nim | 458 ++++++++ src/blobsets/priv/nimcrypto/blowfish.nim | 481 +++++++++ src/blobsets/priv/nimcrypto/hash.nim | 150 +++ src/blobsets/priv/nimcrypto/hmac.nim | 289 +++++ src/blobsets/priv/nimcrypto/keccak.nim | 324 ++++++ src/blobsets/priv/nimcrypto/pbkdf2.nim | 67 ++ src/blobsets/priv/nimcrypto/rijndael.nim | 1040 ++++++++++++++++++ src/blobsets/priv/nimcrypto/ripemd.nim | 750 +++++++++++++ src/blobsets/priv/nimcrypto/sha2.nim | 572 ++++++++++ src/blobsets/priv/nimcrypto/sysrand.nim | 289 +++++ src/blobsets/priv/nimcrypto/twofish.nim | 449 ++++++++ src/blobsets/priv/nimcrypto/utils.nim | 227 ++++ 18 files changed, 6385 insertions(+), 5 deletions(-) create mode 100644 src/blobsets/priv/nimcrypto.nim create mode 100644 src/blobsets/priv/nimcrypto/LICENSE create mode 100644 src/blobsets/priv/nimcrypto/bcmode.nim create mode 100644 src/blobsets/priv/nimcrypto/blake2.nim create mode 100644 src/blobsets/priv/nimcrypto/blowfish.nim create mode 100644 src/blobsets/priv/nimcrypto/hash.nim create mode 100644 src/blobsets/priv/nimcrypto/hmac.nim create mode 100644 src/blobsets/priv/nimcrypto/keccak.nim create mode 100644 src/blobsets/priv/nimcrypto/pbkdf2.nim create mode 100644 src/blobsets/priv/nimcrypto/rijndael.nim create mode 100644 src/blobsets/priv/nimcrypto/ripemd.nim create mode 100644 src/blobsets/priv/nimcrypto/sha2.nim create mode 100644 src/blobsets/priv/nimcrypto/sysrand.nim create mode 100644 src/blobsets/priv/nimcrypto/twofish.nim create mode 100644 src/blobsets/priv/nimcrypto/utils.nim diff --git a/blobsets.nimble b/blobsets.nimble index befbd50..c1d2464 100644 --- a/blobsets.nimble +++ b/blobsets.nimble @@ -6,7 +6,7 @@ description = "Sets of named blobs" license = "AGPLv3" srcDir = "src" -requires "nim >= 0.18.0", "cbor >= 0.5.1", "siphash", "nimcrypto", "spryvm" +requires "nim >= 0.18.0", "cbor >= 0.5.1", "siphash", "spryvm" bin = @["blobset"] skipFiles = @["blobset.nim"] diff --git a/src/blobsets.nim b/src/blobsets.nim index ee318a1..f57c797 100644 --- a/src/blobsets.nim +++ b/src/blobsets.nim @@ -1,10 +1,9 @@ import std/asyncdispatch, std/asyncstreams import std/hashes, std/streams, std/strutils, std/bitops, std/unicode, std/endians -import cbor, siphash -import ./blobsets/priv/hex import std/streams, std/strutils, std/random +import cbor, siphash -import nimcrypto, nimcrypto/blake2 +import ./blobsets/priv/hex, ./blobsets/priv/nimcrypto, ./blobsets/priv/nimcrypto/blake2 const digestLen* = 32 diff --git a/src/blobsets/filestores.nim b/src/blobsets/filestores.nim index 0b35b82..e711528 100644 --- a/src/blobsets/filestores.nim +++ b/src/blobsets/filestores.nim @@ -2,7 +2,7 @@ import ../blobsets import std/asyncfile, std/asyncdispatch, std/os -import nimcrypto/blake2 +import ./priv/nimcrypto/blake2 proc ingestFile*(store: BlobStore; path: string): Future[tuple[id: BlobId, size: BiggestInt]] {.async.} = ## Ingest a file and return blob metadata. diff --git a/src/blobsets/priv/nimcrypto.nim b/src/blobsets/priv/nimcrypto.nim new file mode 100644 index 0000000..71a5596 --- /dev/null +++ b/src/blobsets/priv/nimcrypto.nim @@ -0,0 +1,19 @@ +# +# +# NimCrypto +# (c) Copyright 2018 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +import nimcrypto/[hash, sha2, ripemd, keccak, blake2, hmac] +import nimcrypto/[rijndael, blowfish, twofish, bcmode] +import nimcrypto/[utils, sysrand] + +## Nimcrypto is the Nim language's cryptographic library. +## It implements several popular cryptographic algorithms and their tests, +## with some examples in the official repo: https://github.com/cheatfate/nimcrypto/tree/master/examples + +export hash, sha2, ripemd, keccak, blake2, hmac, rijndael, twofish, blowfish, + bcmode, utils, sysrand diff --git a/src/blobsets/priv/nimcrypto/LICENSE b/src/blobsets/priv/nimcrypto/LICENSE new file mode 100644 index 0000000..968a425 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Eugene Kabanov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/blobsets/priv/nimcrypto/bcmode.nim b/src/blobsets/priv/nimcrypto/bcmode.nim new file mode 100644 index 0000000..d5ccbbe --- /dev/null +++ b/src/blobsets/priv/nimcrypto/bcmode.nim @@ -0,0 +1,1245 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements various Block Cipher Modes. +## +## The five modes currently supported: +## * ECB (Electronic Code Book) +## * CBC (Cipher Block Chaining) +## * CFB (Cipher FeedBack) +## * OFB (Output FeedBack) +## * CTR (Counter) +## * GCM (Galois/Counter Mode) +## +## You can use any of this modes with all the block ciphers of nimcrypto library +## +## GHASH implementation is Nim version of `ghash_ctmul64.c` which is part +## of decent BearSSL project . +## Copyright (c) 2016 Thomas Pornin +## +## Tests made according to official test vectors (Appendix F) +## http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf +## GCM tests made according official test vectors (Appendix B) +## https://pdfs.semanticscholar.org/114a/4222c53f1a6879f1a77f1bae2fc0f8f55348.pdf +## and OpenSSL vectors +## https://github.com/majek/openssl/blob/master/crypto/evp/evptests.txt +import utils + +{.deadCodeElim:on.} + +const + MaxBlockSize = 256 + MaxBlockBytesSize = MaxBlockSize shr 3 + +type + ECB*[T] = object + ## ECB (Electronic Code Book) context object + cipher: T + tmp: array[MaxBlockBytesSize, byte] + + CBC*[T] = object + ## CBC (Cipher Block Chaining) context object + cipher: T + iv: array[MaxBlockBytesSize, byte] + tmp: array[MaxBlockBytesSize, byte] + + OFB*[T] = object + ## OFB (Output FeedBack) context object + cipher: T + iv: array[MaxBlockBytesSize, byte] + + CFB*[T] = object + ## CFB (Cipher FeedBack) context object + cipher: T + iv: array[MaxBlockBytesSize, byte] + + CTR*[T] = object + ## CTR (Counter) context object + cipher: T + iv: array[MaxBlockBytesSize, byte] + ecount: array[MaxBlockBytesSize, byte] + num: uint + + GCM*[T] = object + ## GCM (Galois/Counter Mode) context object + cipher: T + h: array[16, byte] + y: array[16, byte] + basectr: array[16, byte] + buf: array[16, byte] + aadlen: uint64 + datalen: uint64 + +## ECB (Electronic Code Book) Mode + +template sizeBlock*[T](ctx: ECB[T]): int = + ## Size of ``ECB[T]`` block in octets (bytes). This value is equal + ## to cipher ``T`` block size. + mixin sizeBlock + sizeBlock(ctx.cipher) + +template sizeKey*[T](ctx: ECB[T]): int = + ## Size of ``ECB[T]`` key in octets (bytes). This value is equal + ## to cipher ``T`` key size. + mixin sizeKey + sizeKey(ctx.cipher) + +proc init*[T](ctx: var ECB[T], key: ptr byte) = + ## Initialize ``ECB[T]`` with encryption key ``key``. + ## + ## Note! Size of data pointed by ``key`` must be at least ``ctx.sizeKey`` + ## octets (bytes). + mixin init + assert(not isNil(key)) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, key) + +proc init*[T](ctx: var ECB[T], key: openarray[byte]) {.inline.} = + ## Initialize ``ECB[T]`` with encryption key ``key``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key``. + ## + ## Length of ``key`` must be at least ``ECB[T].sizeKey()`` octets (bytes). + ## + ## You can see examples of usage ECB mode here ``examples/ecb.nim``. + assert(len(key) >= ctx.sizeKey()) + init(ctx, unsafeAddr key[0]) + +proc init*[T](ctx: var ECB[T], key: openarray[char]) {.inline.} = + ## Initialize ``ECB[T]`` with encryption key ``key``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key``. + ## + ## Length of ``key`` must be at least ``ECB[T].sizeKey()`` octets (bytes). + ## + ## You can see examples of usage ECB mode here ``examples/ecb.nim``. + assert(len(key) >= ctx.sizeKey()) + init(ctx, cast[ptr byte](unsafeAddr key[0])) + +proc clear*[T](ctx: var ECB[T]) {.inline.} = + ## Clear ``ECB[T]`` context ``ctx``. + burnMem(ctx) + +proc encrypt*[T](ctx: var ECB[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``ECB[T]`` encryption of plain data pointed by ``inp`` of length + ## ``length`` and store encrypted data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length mod uint(ctx.sizeBlock) == 0) + + var blen = uint(ctx.sizeBlock) + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var tp = cast[ptr UncheckedArray[byte]](addr ctx.tmp[0]) + + var i = length + while i != 0: + if i < blen: + copyMem(tp, ip, i) + ctx.cipher.encrypt(cast[ptr byte](tp), cast[ptr byte](op)) + break + ctx.cipher.encrypt(cast[ptr byte](ip), cast[ptr byte](op)) + i = i - blen + ip = cast[ptr UncheckedArray[byte]](cast[uint](ip) + blen) + op = cast[ptr UncheckedArray[byte]](cast[uint](op) + blen) + result = length + +proc decrypt*[T](ctx: var ECB[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``ECB[T]`` decryption of encrypted data pointed by ``inp`` of + ## length ``length`` and store plain data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin decrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length mod uint(ctx.sizeBlock) == 0) + + var blen = uint(ctx.sizeBlock) + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var i = length + while i != 0: + ctx.cipher.decrypt(cast[ptr byte](ip), cast[ptr byte](op)) + i = i - blen + ip = cast[ptr UncheckedArray[byte]](cast[uint](ip) + blen) + op = cast[ptr UncheckedArray[byte]](cast[uint](op) + blen) + result = length + +proc encrypt*[T](ctx: var ECB[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``ECB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc encrypt*[T](ctx: var ECB[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``ECB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +proc decrypt*[T](ctx: var ECB[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``ECB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc decrypt*[T](ctx: var ECB[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``ECB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +## CBC (Cipher Block Chaining) Mode + +template sizeBlock*[T](ctx: CBC[T]): int = + ## Size of ``CBC[T]`` block in octets (bytes). This value is equal + ## to cipher ``T`` block size. + mixin sizeBlock + sizeBlock(ctx.cipher) + +template sizeKey*[T](ctx: CBC[T]): int = + ## Size of ``CBC[T]`` key in octets (bytes). This value is equal + ## to cipher ``T`` key size. + mixin sizeKey + sizeKey(ctx.cipher) + +proc init*[T](ctx: var CBC[T], key: ptr byte, iv: ptr byte) = + ## Initialize ``CBC[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## Note! Size of encryption key pointed by ``key`` must be at least + ## ``ctx.sizeKey`` octets (bytes) and size of initial vector ``iv`` must be at + ## least ``ctx.sizeBlock`` octets (bytes). + ## + ## You can see examples of usage CBC mode here ``examples/cbc.nim``. + mixin init + assert(not isNil(key) and not isNil(iv)) + init(ctx.cipher, key) + assert(ctx.sizeBlock <= MaxBlockSize) + copyMem(addr ctx.iv[0], iv, ctx.sizeBlock) + +proc init*[T](ctx: var CBC[T], key: openarray[byte], iv: openarray[byte]) = + ## Initialize ``CBC[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` must be at least ``ctx.sizeBlock()`` octets (bytes) + ## + ## You can see examples of usage CBC mode here ``examples/cbc.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, unsafeAddr key[0]) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc init*[T](ctx: var CBC[T], key: openarray[char], iv: openarray[char]) = + ## Initialize ``CBC[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` must be at least ``ctx.sizeBlock()`` octets (bytes) + ## + ## You can see examples of usage CBC mode here ``examples/cbc.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, cast[ptr byte](unsafeAddr key[0])) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc clear*[T](ctx: var CBC[T]) {.inline.} = + ## Clear ``CBC[T]`` context ``ctx``. + burnMem(ctx) + +proc encrypt*[T](ctx: var CBC[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``CBC[T]`` encryption of plain data pointed by ``inp`` of length + ## ``length`` and store encrypted data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length != 0) + + var blen = uint(ctx.sizeBlock) + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var cp = cast[ptr UncheckedArray[byte]](addr ctx.iv[0]) + + var i = length + while i != 0: + var n = 0'u + while (n < blen) and (n < length): + op[n] = ip[n] xor cp[n] + inc(n) + while n < blen: + op[n] = cp[n] + inc(n) + ctx.cipher.encrypt(cast[ptr byte](op), cast[ptr byte](op)) + cp = op + if i < blen: + break + i = i - blen + ip = cast[ptr UncheckedArray[byte]](cast[uint](ip) + blen) + op = cast[ptr UncheckedArray[byte]](cast[uint](op) + blen) + copyMem(addr ctx.iv[0], cp, blen) + result = length + +proc decrypt*[T](ctx: var CBC[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``CBC[T]`` decryption of encrypted data pointed by ``inp`` of + ## length ``length`` and store plain data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin decrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length != 0) + + let blen = uint(ctx.sizeBlock) + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var tp = cast[ptr UncheckedArray[byte]](addr ctx.tmp[0]) + var cp = cast[ptr UncheckedArray[byte]](addr ctx.iv[0]) + + var i = length + while i != 0: + var n = 0'u + ctx.cipher.decrypt(cast[ptr byte](ip), cast[ptr byte](tp)) + while (n < blen) and (n < length): + var c = ip[n] + op[n] = tp[n] xor cp[n] + cp[n] = c + inc(n) + if i < blen: + while n < blen: + cp[n] = ip[n] + break + i = i - blen + ip = cast[ptr UncheckedArray[byte]](cast[uint](ip) + blen) + op = cast[ptr UncheckedArray[byte]](cast[uint](op) + blen) + result = length + +proc encrypt*[T](ctx: var CBC[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``CBC[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc encrypt*[T](ctx: var CBC[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``CBC[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +proc decrypt*[T](ctx: var CBC[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``CBC[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc decrypt*[T](ctx: var CBC[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``CBC[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +## CTR (Counter) Mode + +template sizeBlock*[T](ctx: CTR[T]): int = + ## Size of ``CTR[T]`` block in octets (bytes). This value is equal + ## to cipher ``T`` block size. + mixin sizeBlock + sizeBlock(ctx.cipher) + +template sizeKey*[T](ctx: CTR[T]): int = + ## Size of ``CTR[T]`` key in octets (bytes). This value is equal + ## to cipher ``T`` key size. + mixin sizeKey + sizeKey(ctx.cipher) + +proc inc128(counter: ptr UncheckedArray[byte]) = + var n = 16'u32 + var c = 1'u32 + while true: + dec(n) + c = c + counter[n] + counter[n] = cast[byte](c) + c = c shr 8 + if n == 0: + break + +proc inc128(counter: var array[16, byte]) = + var n = 16'u32 + var c = 1'u32 + while true: + dec(n) + c = c + counter[n] + counter[n] = cast[byte](c) + c = c shr 8 + if n == 0: + break + +proc inc256(counter: ptr UncheckedArray[byte]) = + var n = 32'u32 + var c = 1'u32 + while true: + dec(n) + c = c + counter[n] + counter[n] = cast[byte](c) + c = c shr 8 + if n == 0: + break + +proc init*[T](ctx: var CTR[T], key: ptr byte, iv: ptr byte) = + ## Initialize ``CTR[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## Note! Size of encryption key pointed by ``key`` must be at least + ## ``ctx.sizeKey`` octets (bytes) and size of initial vector ``iv`` must be at + ## least ``ctx.sizeBlock`` octets (bytes). + ## + ## You can see examples of usage CTR mode here ``examples/ctr.nim``. + mixin init + assert(not isNil(key) and not isNil(iv)) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, key) + copyMem(addr ctx.iv[0], iv, ctx.sizeBlock) + +proc init*[T](ctx: var CTR[T], key: openarray[byte], iv: openarray[byte]) = + ## Initialize ``CTR[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` array must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` array must be at least ``ctx.sizeBlock()`` octets (bytes). + ## + ## You can see examples of usage CTR mode here ``examples/ctr.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, unsafeAddr key[0]) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc init*[T](ctx: var CTR[T], key: openarray[char], + iv: openarray[char]) {.inline.} = + ## Initialize ``CTR[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` array must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` array must be at least ``ctx.sizeBlock()`` octets (bytes). + ## + ## You can see examples of usage CTR mode here ``examples/ctr.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, cast[ptr byte](unsafeAddr key[0])) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc clear*[T](ctx: var CTR[T]) {.inline.} = + ## Clear ``CTR[T]`` context ``ctx``. + burnMem(ctx) + +proc encrypt*[T](ctx: var CTR[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``CTR[T]`` encryption of plain data pointed by ``inp`` of length + ## ``length`` and store encrypted data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length != 0) + assert(ctx.sizeBlock == (128 div 8) or ctx.sizeBlock == (256 div 8)) + var n = ctx.num + var i = 0'u + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var cp = cast[ptr UncheckedArray[byte]](addr ctx.iv[0]) + let mask = uint(ctx.sizeBlock) + + while i < length: + if n == 0: + ctx.cipher.encrypt(addr ctx.iv[0], addr ctx.ecount[0]) + if ctx.sizeBlock == (128 div 8): + inc128(cp) + elif ctx.sizeBlock == (256 div 8): + inc256(cp) + op[i] = cast[byte](ip[i] xor ctx.ecount[n]) + inc(i) + n = (n + 1) mod mask + + ctx.num = uint(n) + result = ctx.num + +proc decrypt*[T](ctx: var CTR[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable, inline.} = + ## Perform ``CTR[T]`` decryption of encrypted data pointed by ``inp`` of + ## length ``length`` and store decrypted data to ``oup``. ``oup`` must be able + ## to hold at least ``length`` octets (bytes) of data. + ## + ## Procedures returns number of processed octets (bytes). + mixin encrypt + result = encrypt(ctx, inp, oup, length) + +proc encrypt*[T](ctx: var CTR[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``CTR[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc encrypt*[T](ctx: var CTR[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``CTR[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +proc decrypt*[T](ctx: var CTR[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``CTR[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc decrypt*[T](ctx: var CTR[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``CTR[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +## OFB (Output Feedback) Mode + +template sizeBlock*[T](ctx: OFB[T]): int = + ## Size of ``OFB[T]`` block in octets (bytes). This value is equal + ## to cipher ``T`` block size. + mixin sizeBlock + sizeBlock(ctx.cipher) + +template sizeKey*[T](ctx: OFB[T]): int = + ## Size of ``OFB[T]`` key in octets (bytes). This value is equal + ## to cipher ``T`` key size. + mixin sizeKey + sizeKey(ctx.cipher) + +proc init*[T](ctx: var OFB[T], key: ptr byte, iv: ptr byte) = + ## Initialize ``OFB[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## Note! Size of encryption key pointed by ``key`` must be at least + ## ``ctx.sizeKey`` octets (bytes) and size of initial vector ``iv`` must be at + ## least ``ctx.sizeBlock`` octets (bytes). + ## + ## You can see examples of usage OFB mode here ``examples/ofb.nim``. + mixin init + assert(not isNil(key) and not isNil(iv)) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, key) + copyMem(addr ctx.iv[0], iv, ctx.sizeBlock) + +proc init*[T](ctx: var OFB[T], key: openarray[byte], iv: openarray[byte]) = + ## Initialize ``OFB[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` array must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` array must be at least ``ctx.sizeBlock()`` octets (bytes). + ## + ## You can see examples of usage OFB mode here ``examples/ofb.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, unsafeAddr key[0]) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc init*[T](ctx: var OFB[T], key: openarray[char], iv: openarray[char]) = + ## Initialize ``OFB[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` array must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` array must be at least ``ctx.sizeBlock()`` octets (bytes). + ## + ## You can see examples of usage OFB mode here ``examples/ofb.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, cast[ptr byte](unsafeAddr key[0])) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc clear*[T](ctx: var OFB[T]) {.inline.} = + ## Clear ``OFB[T]`` context ``ctx``. + burnMem(ctx) + +proc encrypt*[T](ctx: var OFB[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``OFB[T]`` encryption of plain data pointed by ``inp`` of length + ## ``length`` and store encrypted data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length != 0) + assert(ctx.sizeBlock == (128 div 8) or ctx.sizeBlock == (256 div 8)) + var n = 0 + var i = 0'u + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var cp = cast[ptr UncheckedArray[byte]](addr ctx.iv[0]) + let mask = ctx.sizeBlock + + while i < length: + if n == 0: + ctx.cipher.encrypt(cast[ptr byte](cp), cast[ptr byte](cp)) + op[i] = ip[i] xor cp[n] + inc(i) + n = (n + 1) mod mask + result = uint(n) + +proc decrypt*[T](ctx: var OFB[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable, inline.} = + ## Perform ``OFB[T]`` decryption of encrypted data pointed by ``inp`` of + ## length ``length`` and store plain data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + result = encrypt(ctx, inp, oup, length) + +proc encrypt*[T](ctx: var OFB[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``OFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc encrypt*[T](ctx: var OFB[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``OFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +proc decrypt*[T](ctx: var OFB[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``OFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc decrypt*[T](ctx: var OFB[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``OFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +## CFB (Cipher Feedback) Mode + +template sizeBlock*[T](ctx: CFB[T]): int = + ## Size of ``CFB[T]`` block in octets (bytes). This value is equal + ## to cipher ``T`` block size. + mixin sizeBlock + sizeBlock(ctx.cipher) + +template sizeKey*[T](ctx: CFB[T]): int = + ## Size of ``CFB[T]`` key in octets (bytes). This value is equal + ## to cipher ``T`` key size. + mixin sizeKey + sizeKey(ctx.cipher) + +proc init*[T](ctx: var CFB[T], key: ptr byte, iv: ptr byte) = + ## Initialize ``CFB[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## Note! Size of encryption key pointed by ``key`` must be at least + ## ``ctx.sizeKey`` octets (bytes) and size of initial vector ``iv`` must be at + ## least ``ctx.sizeBlock`` octets (bytes). + ## + ## You can see examples of usage CFB mode here ``examples/cfb.nim``. + mixin init + assert(not isNil(key) and not isNil(iv)) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, key) + copyMem(addr ctx.iv[0], iv, ctx.sizeBlock) + +proc init*[T](ctx: var CFB[T], key: openarray[byte], iv: openarray[byte]) = + ## Initialize ``CFB[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` array must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` array must be at least ``ctx.sizeBlock()`` octets (bytes). + ## + ## You can see examples of usage CFB mode here ``examples/cfb.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, unsafeAddr key[0]) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc init*[T](ctx: var CFB[T], key: openarray[char], iv: openarray[char]) = + ## Initialize ``CFB[T]`` with encryption key ``key`` and initial vector (IV) + ## ``iv``. + ## + ## This procedure will not perform any additional padding for encryption + ## key ``key`` and initial vector ``iv``. + ## + ## Length of ``key`` array must be at least ``ctx.sizeKey()`` octets (bytes). + ## Length of ``iv`` array must be at least ``ctx.sizeBlock()`` octets (bytes). + ## + ## You can see examples of usage CFB mode here ``examples/cfb.nim``. + mixin init + assert(len(iv) >= ctx.sizeBlock) + assert(len(key) >= ctx.sizeKey) + assert(ctx.sizeBlock <= MaxBlockSize) + init(ctx.cipher, cast[ptr byte](unsafeAddr key[0])) + copyMem(addr ctx.iv[0], unsafeAddr iv[0], ctx.sizeBlock) + +proc clear*[T](ctx: var CFB[T]) {.inline.} = + ## Clear ``CFB[T]`` context ``ctx``. + burnMem(ctx) + +proc encrypt*[T](ctx: var CFB[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``CFB[T]`` encryption of plain data pointed by ``inp`` of length + ## ``length`` and store encrypted data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length != 0) + var n = 0 + var i = 0'u + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var cp = cast[ptr UncheckedArray[byte]](addr ctx.iv[0]) + let mask = ctx.sizeBlock + + while i < length: + if n == 0: + ctx.cipher.encrypt(cast[ptr byte](cp), cast[ptr byte](cp)) + cp[n] = cp[n] xor ip[i] + op[i] = cp[n] + inc(i) + n = (n + 1) mod mask + result = uint(n) + +proc decrypt*[T](ctx: var CFB[T], inp: ptr byte, oup: ptr byte, + length: uint): uint {.discardable.} = + ## Perform ``CFB[T]`` decryption of encrypted data pointed by ``inp`` of + ## length ``length`` and store plain data to ``oup``. ``oup`` must be able to + ## hold at least ``length`` octets (bytes) of data. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. ``length`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``length mod ctx.sizeBlock == 0``. + ## + ## Procedure returns number of processed octets (bytes). + mixin encrypt + assert(not isNil(inp) and not isNil(oup)) + assert(length != 0) + var n = 0 + var i = 0'u + var ip = cast[ptr UncheckedArray[byte]](inp) + var op = cast[ptr UncheckedArray[byte]](oup) + var cp = cast[ptr UncheckedArray[byte]](addr ctx.iv[0]) + let mask = ctx.sizeBlock + + while i < length: + if n == 0: + ctx.cipher.encrypt(cast[ptr byte](cp), cast[ptr byte](cp)) + let c = ip[i] + op[i] = cp[n] xor c + cp[n] = c + inc(i) + n = (n + 1) mod mask + result = uint(n) + +proc encrypt*[T](ctx: var CFB[T], input: openarray[byte], + output: var openarray[byte]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``CFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc encrypt*[T](ctx: var CFB[T], input: openarray[char], + output: var openarray[char]) {.inline.} = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``CFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + encrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +proc decrypt*[T](ctx: var CFB[T], input: openarray[byte], + output: var openarray[byte]) = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``CFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, unsafeAddr input[0], addr output[0], uint(len(input))) + +proc decrypt*[T](ctx: var CFB[T], input: openarray[char], + output: var openarray[char]) = + ## Decrypt array of data ``input`` and store decrypted data to array + ## ``output`` using ``CFB[T]`` context ``ctx``. + ## + ## Note that length of ``input`` array must be less or equal to length of + ## ``output`` array. Length of ``input`` array must not be zero. + ## + ## Note, that this procedure do not perform any additional padding, so you + ## need to do it on your own. Length of ``input`` must be aligned to the + ## ``ctx.sizeBlock`` value, e.g. ``len(input) mod ctx.sizeBlock == 0``. + assert(len(input) <= len(output)) + assert(len(input) > 0) + decrypt(ctx, cast[ptr byte](unsafeAddr input[0]), + cast[ptr byte](addr output[0]), uint(len(input))) + +## GCM (Galois Counter Mode) + +# GHASH implementation is Nim version of `ghash_ctmul64.c` which is part +# of decent BearSSL project . +# Copyright (c) 2016 Thomas Pornin + +proc bmul64(x, y: uint64): uint64 = + var x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3: uint64 + x0 = x and 0x1111111111111111'u64 + x1 = x and 0x2222222222222222'u64 + x2 = x and 0x4444444444444444'u64 + x3 = x and 0x8888888888888888'u64 + y0 = y and 0x1111111111111111'u64 + y1 = y and 0x2222222222222222'u64 + y2 = y and 0x4444444444444444'u64 + y3 = y and 0x8888888888888888'u64 + z0 = (x0 * y0) xor (x1 * y3) xor (x2 * y2) xor (x3 * y1) + z1 = (x0 * y1) xor (x1 * y0) xor (x2 * y3) xor (x3 * y2) + z2 = (x0 * y2) xor (x1 * y1) xor (x2 * y0) xor (x3 * y3) + z3 = (x0 * y3) xor (x1 * y2) xor (x2 * y1) xor (x3 * y0) + z0 = z0 and 0x1111111111111111'u64 + z1 = z1 and 0x2222222222222222'u64 + z2 = z2 and 0x4444444444444444'u64 + z3 = z3 and 0x8888888888888888'u64 + result = z0 or z1 or z2 or z3 + +template RMS(x, m, s) = + x = ((x and uint64(m)) shl (s)) or ((x shr (s)) and uint64(m)) + +proc rev64(x: uint64): uint64 = + var xx = x + RMS(xx, 0x5555555555555555'u64, 1) + RMS(xx, 0x3333333333333333'u64, 2) + RMS(xx, 0x0F0F0F0F0F0F0F0F'u64, 4) + RMS(xx, 0x00FF00FF00FF00FF'u64, 8) + RMS(xx, 0x0000FFFF0000FFFF'u64, 16) + result = (xx shl 32) or (xx shr 32) + +proc ghash(y: var openarray[byte], h: openarray[byte], + data: ptr byte, size: int) = + var + y0, y1, h0, h1, h2, h0r, h1r, h2r: uint64 + buf: ptr byte + + y1 = EGETU64(addr y[0], 0) + y0 = EGETU64(addr y[0], 8) + h1 = EGETU64(unsafeAddr h[0], 0) + h0 = EGETU64(unsafeAddr h[0], 8) + h0r = rev64(h0) + h1r = rev64(h1) + h2 = h0 xor h1 + h2r = h0r xor h1r + + var length = size + buf = data + while length > 0: + var tmp: array[16, byte] + var src: ptr byte + var y0r, y1r, y2, y2r: uint64 + var z0, z1, z2, z0h, z1h, z2h, v0, v1, v2, v3: uint64 + + if length >= 16: + src = buf + buf = cast[ptr byte](cast[uint](buf) + 16) + length -= 16 + else: + zeroMem(addr tmp[0], 16) + copyMem(addr tmp[0], buf, length) + src = addr tmp[0] + length = 0 + + y1 = y1 xor GETU64(src, 0) + y0 = y0 xor GETU64(src, 8) + + y0r = rev64(y0) + y1r = rev64(y1) + y2 = y0 xor y1; + y2r = y0r xor y1r; + + z0 = bmul64(y0, h0) + z1 = bmul64(y1, h1) + z2 = bmul64(y2, h2) + z0h = bmul64(y0r, h0r) + z1h = bmul64(y1r, h1r) + z2h = bmul64(y2r, h2r) + z2 = z2 xor (z0 xor z1) + z2h = z2h xor (z0h xor z1h) + z0h = rev64(z0h) shr 1 + z1h = rev64(z1h) shr 1 + z2h = rev64(z2h) shr 1 + + v0 = z0 + v1 = z0h xor z2 + v2 = z1 xor z2h + v3 = z1h + + v3 = (v3 shl 1) or (v2 shr 63) + v2 = (v2 shl 1) or (v1 shr 63) + v1 = (v1 shl 1) or (v0 shr 63) + v0 = (v0 shl 1) + + v2 = v2 xor (v0 xor (v0 shr 1) xor (v0 shr 2) xor (v0 shr 7)) + v1 = v1 xor ((v0 shl 63) xor (v0 shl 62) xor (v0 shl 57)) + v3 = v3 xor (v1 xor (v1 shr 1) xor (v1 shr 2) xor (v1 shr 7)) + v2 = v2 xor ((v1 shl 63) xor (v1 shl 62) xor (v1 shl 57)) + + y0 = v2 + y1 = v3 + + EPUTU64(addr y, 0, y1) + EPUTU64(addr y, 8, y0) + +template sizeBlock*[T](ctx: GCM[T]): int = + ## Size of ``GCM[T]`` block in octets (bytes). This value is equal + ## to cipher ``T`` block size. + mixin sizeBlock + sizeBlock(ctx.cipher) + +template sizeKey*[T](ctx: GCM[T]): int = + ## Size of ``GCM[T]`` key in octets (bytes). This value is equal + ## to cipher ``T`` key size. + mixin sizeKey + sizeKey(ctx.cipher) + +proc init*[T](ctx: var GCM[T], key: openarray[byte], iv: openarray[byte], + aad: openarray[byte]) = + ## Initialize ``GCM[T]`` with encryption key ``key``, initial vector (IV) + ## ``iv`` and additional authentication data (AAD) ``aad``. + ## + ## Size of ``key`` must be at least ``ctx.sizeKey()`` octets (bytes). + ## Size of cipher ``T`` block must be 128 bits (16 bytes). + ## + ## You can see examples of usage GCM mode here ``examples/gcm.nim``. + mixin init + # GCM supports only 128bit block ciphers + assert(ctx.sizeBlock == 16) + assert(len(key) == ctx.sizeKey) + burnMem(ctx) + ctx.cipher.init(key) + ctx.cipher.encrypt(ctx.h, ctx.h) + if len(iv) == 12: + copyMem(addr ctx.y[0], unsafeAddr iv[0], 12) + inc128(ctx.y) + else: + var tmp: array[16, byte] + ghash(ctx.y, ctx.h, unsafeAddr iv[0], len(iv)) + EPUTU32(addr tmp[0], 12, len(iv) shl 3) + ghash(ctx.y, ctx.h, addr tmp[0], 16) + ctx.cipher.encrypt(ctx.y, ctx.basectr) + let slen = len(aad) + ctx.aadlen = uint64(slen) + ctx.datalen = 0 + if len(aad) > 0: + ghash(ctx.buf, ctx.h, unsafeAddr aad[0], slen) + +proc encrypt*[T](ctx: var GCM[T], input: openarray[byte], + output: var openarray[byte]) = + ## Encrypt array of data ``input`` and store encrypted data to array + ## ``output`` using ``GCM[T]`` context ``ctx``. + ## + ## Note that length of ``input`` must be less or equal to length of + ## ``output``. Length of ``input`` must not be zero. + mixin encrypt + var ectr: array[16, byte] + assert(len(input) <= len(output)) + assert(len(input) > 0) + var length = len(input) + var offset = 0 + ctx.datalen += uint64(length) + while length > 0: + let uselen = if length < 16: length else: 16 + inc128(ctx.y) + ctx.cipher.encrypt(ctx.y, ectr) + for i in 0.. 0) + + var length = len(input) + var offset = 0 + ctx.datalen += uint64(length) + while length > 0: + let uselen = if length < 16: length else: 16 + inc128(ctx.y) + ctx.cipher.encrypt(ctx.y, ectr) + for i in 0.. 0: + copyMem(addr tag[0], addr ctx.basectr[0], uselen) + EPUTU64(addr workbuf[0], 0, ctx.aadlen shl 3) + EPUTU64(addr workbuf[0], 8, ctx.datalen shl 3) + ghash(ctx.buf, ctx.h, addr workbuf[0], 16) + for i in 0..= ctx.sizeDigest: + for i in 0..= ctx.sizeDigest: + for i in 0..= 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) diff --git a/src/blobsets/priv/nimcrypto/blowfish.nim b/src/blobsets/priv/nimcrypto/blowfish.nim new file mode 100644 index 0000000..2a80e9f --- /dev/null +++ b/src/blobsets/priv/nimcrypto/blowfish.nim @@ -0,0 +1,481 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements Blowfish crypto algorithm by Bruce Schneier +## +## Code based on `C implementation of the Blowfish algorithm` created by +## Paul Kocher [https://www.schneier.com/code/bfsh-koc.zip]. +## +## Tests made according to official test vectors by Eric Young +## [https://www.schneier.com/code/vectors.txt] and adopted version by +## Randy L. Milbert [https://www.schneier.com/code/vectors2.txt], except +## chaining mode tests. +## +## Implementation was made with "blowfish bug" in mind +## [https://www.schneier.com/blowfish-bug.txt] +## +## Some warnings from Paul Kocher: +## +## Warning #1: The code does not check key lengths. (Caveat encryptor.) +## Warning #2: Beware that Blowfish keys repeat such that "ab" = "abab". +## Warning #3: It is normally a good idea to zeroize the BLOWFISH_CTX before +## freeing it. +## Warning #4: Endianness conversions are the responsibility of the caller. +## (To encrypt bytes on a little-endian platforms, you'll probably want +## to swap bytes around instead of just casting.) +## Warning #5: Make sure to use a reasonable mode of operation for your +## application. (If you don't know what CBC mode is, see Warning #7.) +## Warning #6: This code is susceptible to timing attacks. +## Warning #7: Security engineering is risky and non-intuitive. Have someone +## check your work. If you don't know what you are doing, get help. + +import utils + +{.deadCodeElim:on.} + +const + N = 16 + + ORIG_P = [ 0x243F6A88'u32, 0x85A308D3'u32, 0x13198A2E'u32, 0x03707344'u32, + 0xA4093822'u32, 0x299F31D0'u32, 0x082EFA98'u32, 0xEC4E6C89'u32, + 0x452821E6'u32, 0x38D01377'u32, 0xBE5466CF'u32, 0x34E90C6C'u32, + 0xC0AC29B7'u32, 0xC97C50DD'u32, 0x3F84D5B5'u32, 0xB5470917'u32, + 0x9216D5D9'u32, 0x8979FB1B'u32 ] + ORIG_S = [ + [ + 0xD1310BA6'u32, 0x98DFB5AC'u32, 0x2FFD72DB'u32, 0xD01ADFB7'u32, + 0xB8E1AFED'u32, 0x6A267E96'u32, 0xBA7C9045'u32, 0xF12C7F99'u32, + 0x24A19947'u32, 0xB3916CF7'u32, 0x0801F2E2'u32, 0x858EFC16'u32, + 0x636920D8'u32, 0x71574E69'u32, 0xA458FEA3'u32, 0xF4933D7E'u32, + 0x0D95748F'u32, 0x728EB658'u32, 0x718BCD58'u32, 0x82154AEE'u32, + 0x7B54A41D'u32, 0xC25A59B5'u32, 0x9C30D539'u32, 0x2AF26013'u32, + 0xC5D1B023'u32, 0x286085F0'u32, 0xCA417918'u32, 0xB8DB38EF'u32, + 0x8E79DCB0'u32, 0x603A180E'u32, 0x6C9E0E8B'u32, 0xB01E8A3E'u32, + 0xD71577C1'u32, 0xBD314B27'u32, 0x78AF2FDA'u32, 0x55605C60'u32, + 0xE65525F3'u32, 0xAA55AB94'u32, 0x57489862'u32, 0x63E81440'u32, + 0x55CA396A'u32, 0x2AAB10B6'u32, 0xB4CC5C34'u32, 0x1141E8CE'u32, + 0xA15486AF'u32, 0x7C72E993'u32, 0xB3EE1411'u32, 0x636FBC2A'u32, + 0x2BA9C55D'u32, 0x741831F6'u32, 0xCE5C3E16'u32, 0x9B87931E'u32, + 0xAFD6BA33'u32, 0x6C24CF5C'u32, 0x7A325381'u32, 0x28958677'u32, + 0x3B8F4898'u32, 0x6B4BB9AF'u32, 0xC4BFE81B'u32, 0x66282193'u32, + 0x61D809CC'u32, 0xFB21A991'u32, 0x487CAC60'u32, 0x5DEC8032'u32, + 0xEF845D5D'u32, 0xE98575B1'u32, 0xDC262302'u32, 0xEB651B88'u32, + 0x23893E81'u32, 0xD396ACC5'u32, 0x0F6D6FF3'u32, 0x83F44239'u32, + 0x2E0B4482'u32, 0xA4842004'u32, 0x69C8F04A'u32, 0x9E1F9B5E'u32, + 0x21C66842'u32, 0xF6E96C9A'u32, 0x670C9C61'u32, 0xABD388F0'u32, + 0x6A51A0D2'u32, 0xD8542F68'u32, 0x960FA728'u32, 0xAB5133A3'u32, + 0x6EEF0B6C'u32, 0x137A3BE4'u32, 0xBA3BF050'u32, 0x7EFB2A98'u32, + 0xA1F1651D'u32, 0x39AF0176'u32, 0x66CA593E'u32, 0x82430E88'u32, + 0x8CEE8619'u32, 0x456F9FB4'u32, 0x7D84A5C3'u32, 0x3B8B5EBE'u32, + 0xE06F75D8'u32, 0x85C12073'u32, 0x401A449F'u32, 0x56C16AA6'u32, + 0x4ED3AA62'u32, 0x363F7706'u32, 0x1BFEDF72'u32, 0x429B023D'u32, + 0x37D0D724'u32, 0xD00A1248'u32, 0xDB0FEAD3'u32, 0x49F1C09B'u32, + 0x075372C9'u32, 0x80991B7B'u32, 0x25D479D8'u32, 0xF6E8DEF7'u32, + 0xE3FE501A'u32, 0xB6794C3B'u32, 0x976CE0BD'u32, 0x04C006BA'u32, + 0xC1A94FB6'u32, 0x409F60C4'u32, 0x5E5C9EC2'u32, 0x196A2463'u32, + 0x68FB6FAF'u32, 0x3E6C53B5'u32, 0x1339B2EB'u32, 0x3B52EC6F'u32, + 0x6DFC511F'u32, 0x9B30952C'u32, 0xCC814544'u32, 0xAF5EBD09'u32, + 0xBEE3D004'u32, 0xDE334AFD'u32, 0x660F2807'u32, 0x192E4BB3'u32, + 0xC0CBA857'u32, 0x45C8740F'u32, 0xD20B5F39'u32, 0xB9D3FBDB'u32, + 0x5579C0BD'u32, 0x1A60320A'u32, 0xD6A100C6'u32, 0x402C7279'u32, + 0x679F25FE'u32, 0xFB1FA3CC'u32, 0x8EA5E9F8'u32, 0xDB3222F8'u32, + 0x3C7516DF'u32, 0xFD616B15'u32, 0x2F501EC8'u32, 0xAD0552AB'u32, + 0x323DB5FA'u32, 0xFD238760'u32, 0x53317B48'u32, 0x3E00DF82'u32, + 0x9E5C57BB'u32, 0xCA6F8CA0'u32, 0x1A87562E'u32, 0xDF1769DB'u32, + 0xD542A8F6'u32, 0x287EFFC3'u32, 0xAC6732C6'u32, 0x8C4F5573'u32, + 0x695B27B0'u32, 0xBBCA58C8'u32, 0xE1FFA35D'u32, 0xB8F011A0'u32, + 0x10FA3D98'u32, 0xFD2183B8'u32, 0x4AFCB56C'u32, 0x2DD1D35B'u32, + 0x9A53E479'u32, 0xB6F84565'u32, 0xD28E49BC'u32, 0x4BFB9790'u32, + 0xE1DDF2DA'u32, 0xA4CB7E33'u32, 0x62FB1341'u32, 0xCEE4C6E8'u32, + 0xEF20CADA'u32, 0x36774C01'u32, 0xD07E9EFE'u32, 0x2BF11FB4'u32, + 0x95DBDA4D'u32, 0xAE909198'u32, 0xEAAD8E71'u32, 0x6B93D5A0'u32, + 0xD08ED1D0'u32, 0xAFC725E0'u32, 0x8E3C5B2F'u32, 0x8E7594B7'u32, + 0x8FF6E2FB'u32, 0xF2122B64'u32, 0x8888B812'u32, 0x900DF01C'u32, + 0x4FAD5EA0'u32, 0x688FC31C'u32, 0xD1CFF191'u32, 0xB3A8C1AD'u32, + 0x2F2F2218'u32, 0xBE0E1777'u32, 0xEA752DFE'u32, 0x8B021FA1'u32, + 0xE5A0CC0F'u32, 0xB56F74E8'u32, 0x18ACF3D6'u32, 0xCE89E299'u32, + 0xB4A84FE0'u32, 0xFD13E0B7'u32, 0x7CC43B81'u32, 0xD2ADA8D9'u32, + 0x165FA266'u32, 0x80957705'u32, 0x93CC7314'u32, 0x211A1477'u32, + 0xE6AD2065'u32, 0x77B5FA86'u32, 0xC75442F5'u32, 0xFB9D35CF'u32, + 0xEBCDAF0C'u32, 0x7B3E89A0'u32, 0xD6411BD3'u32, 0xAE1E7E49'u32, + 0x00250E2D'u32, 0x2071B35E'u32, 0x226800BB'u32, 0x57B8E0AF'u32, + 0x2464369B'u32, 0xF009B91E'u32, 0x5563911D'u32, 0x59DFA6AA'u32, + 0x78C14389'u32, 0xD95A537F'u32, 0x207D5BA2'u32, 0x02E5B9C5'u32, + 0x83260376'u32, 0x6295CFA9'u32, 0x11C81968'u32, 0x4E734A41'u32, + 0xB3472DCA'u32, 0x7B14A94A'u32, 0x1B510052'u32, 0x9A532915'u32, + 0xD60F573F'u32, 0xBC9BC6E4'u32, 0x2B60A476'u32, 0x81E67400'u32, + 0x08BA6FB5'u32, 0x571BE91F'u32, 0xF296EC6B'u32, 0x2A0DD915'u32, + 0xB6636521'u32, 0xE7B9F9B6'u32, 0xFF34052E'u32, 0xC5855664'u32, + 0x53B02D5D'u32, 0xA99F8FA1'u32, 0x08BA4799'u32, 0x6E85076A'u32 + ], + [ + 0x4B7A70E9'u32, 0xB5B32944'u32, 0xDB75092E'u32, 0xC4192623'u32, + 0xAD6EA6B0'u32, 0x49A7DF7D'u32, 0x9CEE60B8'u32, 0x8FEDB266'u32, + 0xECAA8C71'u32, 0x699A17FF'u32, 0x5664526C'u32, 0xC2B19EE1'u32, + 0x193602A5'u32, 0x75094C29'u32, 0xA0591340'u32, 0xE4183A3E'u32, + 0x3F54989A'u32, 0x5B429D65'u32, 0x6B8FE4D6'u32, 0x99F73FD6'u32, + 0xA1D29C07'u32, 0xEFE830F5'u32, 0x4D2D38E6'u32, 0xF0255DC1'u32, + 0x4CDD2086'u32, 0x8470EB26'u32, 0x6382E9C6'u32, 0x021ECC5E'u32, + 0x09686B3F'u32, 0x3EBAEFC9'u32, 0x3C971814'u32, 0x6B6A70A1'u32, + 0x687F3584'u32, 0x52A0E286'u32, 0xB79C5305'u32, 0xAA500737'u32, + 0x3E07841C'u32, 0x7FDEAE5C'u32, 0x8E7D44EC'u32, 0x5716F2B8'u32, + 0xB03ADA37'u32, 0xF0500C0D'u32, 0xF01C1F04'u32, 0x0200B3FF'u32, + 0xAE0CF51A'u32, 0x3CB574B2'u32, 0x25837A58'u32, 0xDC0921BD'u32, + 0xD19113F9'u32, 0x7CA92FF6'u32, 0x94324773'u32, 0x22F54701'u32, + 0x3AE5E581'u32, 0x37C2DADC'u32, 0xC8B57634'u32, 0x9AF3DDA7'u32, + 0xA9446146'u32, 0x0FD0030E'u32, 0xECC8C73E'u32, 0xA4751E41'u32, + 0xE238CD99'u32, 0x3BEA0E2F'u32, 0x3280BBA1'u32, 0x183EB331'u32, + 0x4E548B38'u32, 0x4F6DB908'u32, 0x6F420D03'u32, 0xF60A04BF'u32, + 0x2CB81290'u32, 0x24977C79'u32, 0x5679B072'u32, 0xBCAF89AF'u32, + 0xDE9A771F'u32, 0xD9930810'u32, 0xB38BAE12'u32, 0xDCCF3F2E'u32, + 0x5512721F'u32, 0x2E6B7124'u32, 0x501ADDE6'u32, 0x9F84CD87'u32, + 0x7A584718'u32, 0x7408DA17'u32, 0xBC9F9ABC'u32, 0xE94B7D8C'u32, + 0xEC7AEC3A'u32, 0xDB851DFA'u32, 0x63094366'u32, 0xC464C3D2'u32, + 0xEF1C1847'u32, 0x3215D908'u32, 0xDD433B37'u32, 0x24C2BA16'u32, + 0x12A14D43'u32, 0x2A65C451'u32, 0x50940002'u32, 0x133AE4DD'u32, + 0x71DFF89E'u32, 0x10314E55'u32, 0x81AC77D6'u32, 0x5F11199B'u32, + 0x043556F1'u32, 0xD7A3C76B'u32, 0x3C11183B'u32, 0x5924A509'u32, + 0xF28FE6ED'u32, 0x97F1FBFA'u32, 0x9EBABF2C'u32, 0x1E153C6E'u32, + 0x86E34570'u32, 0xEAE96FB1'u32, 0x860E5E0A'u32, 0x5A3E2AB3'u32, + 0x771FE71C'u32, 0x4E3D06FA'u32, 0x2965DCB9'u32, 0x99E71D0F'u32, + 0x803E89D6'u32, 0x5266C825'u32, 0x2E4CC978'u32, 0x9C10B36A'u32, + 0xC6150EBA'u32, 0x94E2EA78'u32, 0xA5FC3C53'u32, 0x1E0A2DF4'u32, + 0xF2F74EA7'u32, 0x361D2B3D'u32, 0x1939260F'u32, 0x19C27960'u32, + 0x5223A708'u32, 0xF71312B6'u32, 0xEBADFE6E'u32, 0xEAC31F66'u32, + 0xE3BC4595'u32, 0xA67BC883'u32, 0xB17F37D1'u32, 0x018CFF28'u32, + 0xC332DDEF'u32, 0xBE6C5AA5'u32, 0x65582185'u32, 0x68AB9802'u32, + 0xEECEA50F'u32, 0xDB2F953B'u32, 0x2AEF7DAD'u32, 0x5B6E2F84'u32, + 0x1521B628'u32, 0x29076170'u32, 0xECDD4775'u32, 0x619F1510'u32, + 0x13CCA830'u32, 0xEB61BD96'u32, 0x0334FE1E'u32, 0xAA0363CF'u32, + 0xB5735C90'u32, 0x4C70A239'u32, 0xD59E9E0B'u32, 0xCBAADE14'u32, + 0xEECC86BC'u32, 0x60622CA7'u32, 0x9CAB5CAB'u32, 0xB2F3846E'u32, + 0x648B1EAF'u32, 0x19BDF0CA'u32, 0xA02369B9'u32, 0x655ABB50'u32, + 0x40685A32'u32, 0x3C2AB4B3'u32, 0x319EE9D5'u32, 0xC021B8F7'u32, + 0x9B540B19'u32, 0x875FA099'u32, 0x95F7997E'u32, 0x623D7DA8'u32, + 0xF837889A'u32, 0x97E32D77'u32, 0x11ED935F'u32, 0x16681281'u32, + 0x0E358829'u32, 0xC7E61FD6'u32, 0x96DEDFA1'u32, 0x7858BA99'u32, + 0x57F584A5'u32, 0x1B227263'u32, 0x9B83C3FF'u32, 0x1AC24696'u32, + 0xCDB30AEB'u32, 0x532E3054'u32, 0x8FD948E4'u32, 0x6DBC3128'u32, + 0x58EBF2EF'u32, 0x34C6FFEA'u32, 0xFE28ED61'u32, 0xEE7C3C73'u32, + 0x5D4A14D9'u32, 0xE864B7E3'u32, 0x42105D14'u32, 0x203E13E0'u32, + 0x45EEE2B6'u32, 0xA3AAABEA'u32, 0xDB6C4F15'u32, 0xFACB4FD0'u32, + 0xC742F442'u32, 0xEF6ABBB5'u32, 0x654F3B1D'u32, 0x41CD2105'u32, + 0xD81E799E'u32, 0x86854DC7'u32, 0xE44B476A'u32, 0x3D816250'u32, + 0xCF62A1F2'u32, 0x5B8D2646'u32, 0xFC8883A0'u32, 0xC1C7B6A3'u32, + 0x7F1524C3'u32, 0x69CB7492'u32, 0x47848A0B'u32, 0x5692B285'u32, + 0x095BBF00'u32, 0xAD19489D'u32, 0x1462B174'u32, 0x23820E00'u32, + 0x58428D2A'u32, 0x0C55F5EA'u32, 0x1DADF43E'u32, 0x233F7061'u32, + 0x3372F092'u32, 0x8D937E41'u32, 0xD65FECF1'u32, 0x6C223BDB'u32, + 0x7CDE3759'u32, 0xCBEE7460'u32, 0x4085F2A7'u32, 0xCE77326E'u32, + 0xA6078084'u32, 0x19F8509E'u32, 0xE8EFD855'u32, 0x61D99735'u32, + 0xA969A7AA'u32, 0xC50C06C2'u32, 0x5A04ABFC'u32, 0x800BCADC'u32, + 0x9E447A2E'u32, 0xC3453484'u32, 0xFDD56705'u32, 0x0E1E9EC9'u32, + 0xDB73DBD3'u32, 0x105588CD'u32, 0x675FDA79'u32, 0xE3674340'u32, + 0xC5C43465'u32, 0x713E38D8'u32, 0x3D28F89E'u32, 0xF16DFF20'u32, + 0x153E21E7'u32, 0x8FB03D4A'u32, 0xE6E39F2B'u32, 0xDB83ADF7'u32 + ], + [ + 0xE93D5A68'u32, 0x948140F7'u32, 0xF64C261C'u32, 0x94692934'u32, + 0x411520F7'u32, 0x7602D4F7'u32, 0xBCF46B2E'u32, 0xD4A20068'u32, + 0xD4082471'u32, 0x3320F46A'u32, 0x43B7D4B7'u32, 0x500061AF'u32, + 0x1E39F62E'u32, 0x97244546'u32, 0x14214F74'u32, 0xBF8B8840'u32, + 0x4D95FC1D'u32, 0x96B591AF'u32, 0x70F4DDD3'u32, 0x66A02F45'u32, + 0xBFBC09EC'u32, 0x03BD9785'u32, 0x7FAC6DD0'u32, 0x31CB8504'u32, + 0x96EB27B3'u32, 0x55FD3941'u32, 0xDA2547E6'u32, 0xABCA0A9A'u32, + 0x28507825'u32, 0x530429F4'u32, 0x0A2C86DA'u32, 0xE9B66DFB'u32, + 0x68DC1462'u32, 0xD7486900'u32, 0x680EC0A4'u32, 0x27A18DEE'u32, + 0x4F3FFEA2'u32, 0xE887AD8C'u32, 0xB58CE006'u32, 0x7AF4D6B6'u32, + 0xAACE1E7C'u32, 0xD3375FEC'u32, 0xCE78A399'u32, 0x406B2A42'u32, + 0x20FE9E35'u32, 0xD9F385B9'u32, 0xEE39D7AB'u32, 0x3B124E8B'u32, + 0x1DC9FAF7'u32, 0x4B6D1856'u32, 0x26A36631'u32, 0xEAE397B2'u32, + 0x3A6EFA74'u32, 0xDD5B4332'u32, 0x6841E7F7'u32, 0xCA7820FB'u32, + 0xFB0AF54E'u32, 0xD8FEB397'u32, 0x454056AC'u32, 0xBA489527'u32, + 0x55533A3A'u32, 0x20838D87'u32, 0xFE6BA9B7'u32, 0xD096954B'u32, + 0x55A867BC'u32, 0xA1159A58'u32, 0xCCA92963'u32, 0x99E1DB33'u32, + 0xA62A4A56'u32, 0x3F3125F9'u32, 0x5EF47E1C'u32, 0x9029317C'u32, + 0xFDF8E802'u32, 0x04272F70'u32, 0x80BB155C'u32, 0x05282CE3'u32, + 0x95C11548'u32, 0xE4C66D22'u32, 0x48C1133F'u32, 0xC70F86DC'u32, + 0x07F9C9EE'u32, 0x41041F0F'u32, 0x404779A4'u32, 0x5D886E17'u32, + 0x325F51EB'u32, 0xD59BC0D1'u32, 0xF2BCC18F'u32, 0x41113564'u32, + 0x257B7834'u32, 0x602A9C60'u32, 0xDFF8E8A3'u32, 0x1F636C1B'u32, + 0x0E12B4C2'u32, 0x02E1329E'u32, 0xAF664FD1'u32, 0xCAD18115'u32, + 0x6B2395E0'u32, 0x333E92E1'u32, 0x3B240B62'u32, 0xEEBEB922'u32, + 0x85B2A20E'u32, 0xE6BA0D99'u32, 0xDE720C8C'u32, 0x2DA2F728'u32, + 0xD0127845'u32, 0x95B794FD'u32, 0x647D0862'u32, 0xE7CCF5F0'u32, + 0x5449A36F'u32, 0x877D48FA'u32, 0xC39DFD27'u32, 0xF33E8D1E'u32, + 0x0A476341'u32, 0x992EFF74'u32, 0x3A6F6EAB'u32, 0xF4F8FD37'u32, + 0xA812DC60'u32, 0xA1EBDDF8'u32, 0x991BE14C'u32, 0xDB6E6B0D'u32, + 0xC67B5510'u32, 0x6D672C37'u32, 0x2765D43B'u32, 0xDCD0E804'u32, + 0xF1290DC7'u32, 0xCC00FFA3'u32, 0xB5390F92'u32, 0x690FED0B'u32, + 0x667B9FFB'u32, 0xCEDB7D9C'u32, 0xA091CF0B'u32, 0xD9155EA3'u32, + 0xBB132F88'u32, 0x515BAD24'u32, 0x7B9479BF'u32, 0x763BD6EB'u32, + 0x37392EB3'u32, 0xCC115979'u32, 0x8026E297'u32, 0xF42E312D'u32, + 0x6842ADA7'u32, 0xC66A2B3B'u32, 0x12754CCC'u32, 0x782EF11C'u32, + 0x6A124237'u32, 0xB79251E7'u32, 0x06A1BBE6'u32, 0x4BFB6350'u32, + 0x1A6B1018'u32, 0x11CAEDFA'u32, 0x3D25BDD8'u32, 0xE2E1C3C9'u32, + 0x44421659'u32, 0x0A121386'u32, 0xD90CEC6E'u32, 0xD5ABEA2A'u32, + 0x64AF674E'u32, 0xDA86A85F'u32, 0xBEBFE988'u32, 0x64E4C3FE'u32, + 0x9DBC8057'u32, 0xF0F7C086'u32, 0x60787BF8'u32, 0x6003604D'u32, + 0xD1FD8346'u32, 0xF6381FB0'u32, 0x7745AE04'u32, 0xD736FCCC'u32, + 0x83426B33'u32, 0xF01EAB71'u32, 0xB0804187'u32, 0x3C005E5F'u32, + 0x77A057BE'u32, 0xBDE8AE24'u32, 0x55464299'u32, 0xBF582E61'u32, + 0x4E58F48F'u32, 0xF2DDFDA2'u32, 0xF474EF38'u32, 0x8789BDC2'u32, + 0x5366F9C3'u32, 0xC8B38E74'u32, 0xB475F255'u32, 0x46FCD9B9'u32, + 0x7AEB2661'u32, 0x8B1DDF84'u32, 0x846A0E79'u32, 0x915F95E2'u32, + 0x466E598E'u32, 0x20B45770'u32, 0x8CD55591'u32, 0xC902DE4C'u32, + 0xB90BACE1'u32, 0xBB8205D0'u32, 0x11A86248'u32, 0x7574A99E'u32, + 0xB77F19B6'u32, 0xE0A9DC09'u32, 0x662D09A1'u32, 0xC4324633'u32, + 0xE85A1F02'u32, 0x09F0BE8C'u32, 0x4A99A025'u32, 0x1D6EFE10'u32, + 0x1AB93D1D'u32, 0x0BA5A4DF'u32, 0xA186F20F'u32, 0x2868F169'u32, + 0xDCB7DA83'u32, 0x573906FE'u32, 0xA1E2CE9B'u32, 0x4FCD7F52'u32, + 0x50115E01'u32, 0xA70683FA'u32, 0xA002B5C4'u32, 0x0DE6D027'u32, + 0x9AF88C27'u32, 0x773F8641'u32, 0xC3604C06'u32, 0x61A806B5'u32, + 0xF0177A28'u32, 0xC0F586E0'u32, 0x006058AA'u32, 0x30DC7D62'u32, + 0x11E69ED7'u32, 0x2338EA63'u32, 0x53C2DD94'u32, 0xC2C21634'u32, + 0xBBCBEE56'u32, 0x90BCB6DE'u32, 0xEBFC7DA1'u32, 0xCE591D76'u32, + 0x6F05E409'u32, 0x4B7C0188'u32, 0x39720A3D'u32, 0x7C927C24'u32, + 0x86E3725F'u32, 0x724D9DB9'u32, 0x1AC15BB4'u32, 0xD39EB8FC'u32, + 0xED545578'u32, 0x08FCA5B5'u32, 0xD83D7CD3'u32, 0x4DAD0FC4'u32, + 0x1E50EF5E'u32, 0xB161E6F8'u32, 0xA28514D9'u32, 0x6C51133C'u32, + 0x6FD5C7E7'u32, 0x56E14EC4'u32, 0x362ABFCE'u32, 0xDDC6C837'u32, + 0xD79A3234'u32, 0x92638212'u32, 0x670EFA8E'u32, 0x406000E0'u32 + ], + [ + 0x3A39CE37'u32, 0xD3FAF5CF'u32, 0xABC27737'u32, 0x5AC52D1B'u32, + 0x5CB0679E'u32, 0x4FA33742'u32, 0xD3822740'u32, 0x99BC9BBE'u32, + 0xD5118E9D'u32, 0xBF0F7315'u32, 0xD62D1C7E'u32, 0xC700C47B'u32, + 0xB78C1B6B'u32, 0x21A19045'u32, 0xB26EB1BE'u32, 0x6A366EB4'u32, + 0x5748AB2F'u32, 0xBC946E79'u32, 0xC6A376D2'u32, 0x6549C2C8'u32, + 0x530FF8EE'u32, 0x468DDE7D'u32, 0xD5730A1D'u32, 0x4CD04DC6'u32, + 0x2939BBDB'u32, 0xA9BA4650'u32, 0xAC9526E8'u32, 0xBE5EE304'u32, + 0xA1FAD5F0'u32, 0x6A2D519A'u32, 0x63EF8CE2'u32, 0x9A86EE22'u32, + 0xC089C2B8'u32, 0x43242EF6'u32, 0xA51E03AA'u32, 0x9CF2D0A4'u32, + 0x83C061BA'u32, 0x9BE96A4D'u32, 0x8FE51550'u32, 0xBA645BD6'u32, + 0x2826A2F9'u32, 0xA73A3AE1'u32, 0x4BA99586'u32, 0xEF5562E9'u32, + 0xC72FEFD3'u32, 0xF752F7DA'u32, 0x3F046F69'u32, 0x77FA0A59'u32, + 0x80E4A915'u32, 0x87B08601'u32, 0x9B09E6AD'u32, 0x3B3EE593'u32, + 0xE990FD5A'u32, 0x9E34D797'u32, 0x2CF0B7D9'u32, 0x022B8B51'u32, + 0x96D5AC3A'u32, 0x017DA67D'u32, 0xD1CF3ED6'u32, 0x7C7D2D28'u32, + 0x1F9F25CF'u32, 0xADF2B89B'u32, 0x5AD6B472'u32, 0x5A88F54C'u32, + 0xE029AC71'u32, 0xE019A5E6'u32, 0x47B0ACFD'u32, 0xED93FA9B'u32, + 0xE8D3C48D'u32, 0x283B57CC'u32, 0xF8D56629'u32, 0x79132E28'u32, + 0x785F0191'u32, 0xED756055'u32, 0xF7960E44'u32, 0xE3D35E8C'u32, + 0x15056DD4'u32, 0x88F46DBA'u32, 0x03A16125'u32, 0x0564F0BD'u32, + 0xC3EB9E15'u32, 0x3C9057A2'u32, 0x97271AEC'u32, 0xA93A072A'u32, + 0x1B3F6D9B'u32, 0x1E6321F5'u32, 0xF59C66FB'u32, 0x26DCF319'u32, + 0x7533D928'u32, 0xB155FDF5'u32, 0x03563482'u32, 0x8ABA3CBB'u32, + 0x28517711'u32, 0xC20AD9F8'u32, 0xABCC5167'u32, 0xCCAD925F'u32, + 0x4DE81751'u32, 0x3830DC8E'u32, 0x379D5862'u32, 0x9320F991'u32, + 0xEA7A90C2'u32, 0xFB3E7BCE'u32, 0x5121CE64'u32, 0x774FBE32'u32, + 0xA8B6E37E'u32, 0xC3293D46'u32, 0x48DE5369'u32, 0x6413E680'u32, + 0xA2AE0810'u32, 0xDD6DB224'u32, 0x69852DFD'u32, 0x09072166'u32, + 0xB39A460A'u32, 0x6445C0DD'u32, 0x586CDECF'u32, 0x1C20C8AE'u32, + 0x5BBEF7DD'u32, 0x1B588D40'u32, 0xCCD2017F'u32, 0x6BB4E3BB'u32, + 0xDDA26A7E'u32, 0x3A59FF45'u32, 0x3E350A44'u32, 0xBCB4CDD5'u32, + 0x72EACEA8'u32, 0xFA6484BB'u32, 0x8D6612AE'u32, 0xBF3C6F47'u32, + 0xD29BE463'u32, 0x542F5D9E'u32, 0xAEC2771B'u32, 0xF64E6370'u32, + 0x740E0D8D'u32, 0xE75B1357'u32, 0xF8721671'u32, 0xAF537D5D'u32, + 0x4040CB08'u32, 0x4EB4E2CC'u32, 0x34D2466A'u32, 0x0115AF84'u32, + 0xE1B00428'u32, 0x95983A1D'u32, 0x06B89FB4'u32, 0xCE6EA048'u32, + 0x6F3F3B82'u32, 0x3520AB82'u32, 0x011A1D4B'u32, 0x277227F8'u32, + 0x611560B1'u32, 0xE7933FDC'u32, 0xBB3A792B'u32, 0x344525BD'u32, + 0xA08839E1'u32, 0x51CE794B'u32, 0x2F32C9B7'u32, 0xA01FBAC9'u32, + 0xE01CC87E'u32, 0xBCC7D1F6'u32, 0xCF0111C3'u32, 0xA1E8AAC7'u32, + 0x1A908749'u32, 0xD44FBD9A'u32, 0xD0DADECB'u32, 0xD50ADA38'u32, + 0x0339C32A'u32, 0xC6913667'u32, 0x8DF9317C'u32, 0xE0B12B4F'u32, + 0xF79E59B7'u32, 0x43F5BB3A'u32, 0xF2D519FF'u32, 0x27D9459C'u32, + 0xBF97222C'u32, 0x15E6FC2A'u32, 0x0F91FC71'u32, 0x9B941525'u32, + 0xFAE59361'u32, 0xCEB69CEB'u32, 0xC2A86459'u32, 0x12BAA8D1'u32, + 0xB6C1075E'u32, 0xE3056A0C'u32, 0x10D25065'u32, 0xCB03A442'u32, + 0xE0EC6E0E'u32, 0x1698DB3B'u32, 0x4C98A0BE'u32, 0x3278E964'u32, + 0x9F1F9532'u32, 0xE0D392DF'u32, 0xD3A0342B'u32, 0x8971F21E'u32, + 0x1B0A7441'u32, 0x4BA3348C'u32, 0xC5BE7120'u32, 0xC37632D8'u32, + 0xDF359F8D'u32, 0x9B992F2E'u32, 0xE60B6F47'u32, 0x0FE3F11D'u32, + 0xE54CDA54'u32, 0x1EDAD891'u32, 0xCE6279CF'u32, 0xCD3E7E6F'u32, + 0x1618B166'u32, 0xFD2C1D05'u32, 0x848FD2C5'u32, 0xF6FB2299'u32, + 0xF523F357'u32, 0xA6327623'u32, 0x93A83531'u32, 0x56CCCD02'u32, + 0xACF08162'u32, 0x5A75EBB5'u32, 0x6E163697'u32, 0x88D273CC'u32, + 0xDE966292'u32, 0x81B949D0'u32, 0x4C50901B'u32, 0x71C65614'u32, + 0xE6C6C7BD'u32, 0x327A140A'u32, 0x45E1D006'u32, 0xC3F27B9A'u32, + 0xC9AA53FD'u32, 0x62A80F00'u32, 0xBB25BFE2'u32, 0x35BDD2F6'u32, + 0x71126905'u32, 0xB2040222'u32, 0xB6CBCF7C'u32, 0xCD769C2B'u32, + 0x53113EC0'u32, 0x1640E3D3'u32, 0x38ABBD60'u32, 0x2547ADF0'u32, + 0xBA38209C'u32, 0xF746CE76'u32, 0x77AFA1C5'u32, 0x20756060'u32, + 0x85CBFE4E'u32, 0x8AE88DD8'u32, 0x7AAAF9B0'u32, 0x4CF9AA7E'u32, + 0x1948C25C'u32, 0x02FB8A8C'u32, 0x01C36AE4'u32, 0xD6EBE1F9'u32, + 0x90D4F869'u32, 0xA65CDEA0'u32, 0x3F09252D'u32, 0xC208E69F'u32, + 0xB74E6132'u32, 0xCE77E25B'u32, 0x578FDFE3'u32, 0x3AC372E6'u32 + ] + ] + +type + BlowfishContext[bits: static[uint]] = object + sizeKey: int + P: array[16 + 2, uint32] + S: array[4, array[256, uint32]] + + blowfish* = BlowfishContext[64] + +template f(ctx: var BlowfishContext, x: uint32): uint32 = + var vx = x + var d = cast[uint16](vx and 0xFF'u32) + vx = vx shr 8 + var c = cast[uint16](vx and 0xFF'u32) + vx = vx shr 8 + var b = cast[uint16](vx and 0xFF'u32) + vx = vx shr 8 + var a = cast[uint16](vx and 0xFF'u32) + var vy = ctx.S[0][a] + ctx.S[1][b] + vy = vy xor ctx.S[2][c] + vy = vy + ctx.S[3][d] + vy + +proc blowfishEncrypt*(ctx: var BlowfishContext, inp: ptr byte, + oup: ptr byte) = + var nxl = BSWAP(GET_DWORD(inp, 0)) + var nxr = BSWAP(GET_DWORD(inp, 1)) + + var temp = 0'u32 + var i = 0'i16 + + while i < N: + nxl = nxl xor ctx.P[i] + nxr = f(ctx, nxl) xor nxr + temp = nxl + nxl = nxr + nxr = temp + inc(i) + + temp = nxl + nxl = nxr + nxr = temp + + nxr = nxr xor ctx.P[N] + nxl = nxl xor ctx.P[N + 1] + + SET_DWORD(oup, 0, BSWAP(nxl)) + SET_DWORD(oup, 1, BSWAP(nxr)) + +proc blowfishDecrypt*(ctx: var BlowfishContext, inp: ptr byte, + oup: ptr byte) = + var nxl = BSWAP(GET_DWORD(inp, 0)) + var nxr = BSWAP(GET_DWORD(inp, 1)) + var temp = 0'u32 + + var i = N + 1 + while i > 1: + nxl = nxl xor ctx.P[i] + nxr = f(ctx, nxl) xor nxr + temp = nxl + nxl = nxr + nxr = temp + dec(i) + + temp = nxl + nxl = nxr + nxr = temp + + nxr = nxr xor ctx.P[1] + nxl = nxl xor ctx.P[0] + + SET_DWORD(oup, 0, BSWAP(nxl)) + SET_DWORD(oup, 1, BSWAP(nxr)) + +proc initBlowfishContext*(ctx: var BlowfishContext, key: ptr byte, nkey: int) = + var i = 0 + var j = 0 + var k = 0 + var data = 0'u32 + var length = nkey div 8 + + while i < 4: + j = 0 + while j < 256: + ctx.S[i][j] = ORIG_S[i][j] + inc(j) + inc(i) + + j = 0 + i = 0 + while i < N + 2: + data = 0 + k = 0 + while k < 4: + data = data shl 8 + data = data or (GETU8(key, j) and 0xFF) + inc(j) + if j >= length: + j = 0 + inc(k) + ctx.P[i] = ORIG_P[i] xor data + inc(i) + + i = 0 + var datarl = [0'u32, 0'u32] + while i < N + 2: + blowfishEncrypt(ctx, cast[ptr byte](addr datarl[0]), + cast[ptr byte](addr datarl[0])) + ctx.P[i] = datarl[0] + ctx.P[i + 1] = datarl[1] + i = i + 2 + + i = 0 + while i < 4: + j = 0 + while j < 256: + blowfishEncrypt(ctx, cast[ptr byte](addr datarl[0]), + cast[ptr byte](addr datarl[0])) + ctx.S[i][j] = datarl[0] + ctx.S[i][j + 1] = datarl[1] + j = j + 2 + inc(i) + +template sizeKey*(ctx: BlowfishContext): int = + (ctx.sizeKey shr 3) + +template sizeBlock*(ctx: BlowfishContext): int = + (8) + +template sizeKey*(r: typedesc[blowfish]): int = + {.error: "Could not obtain key size of Blowfish cipher at compile-time".} + +template sizeBlock*(r: typedesc[blowfish]): int = + (8) + +proc init*(ctx: var BlowfishContext, key: ptr byte, nkey: int) {.inline.} = + ctx.sizeKey = nkey shl 3 + initBlowfishContext(ctx, key, ctx.sizeKey) + +proc init*(ctx: var BlowfishContext, key: openarray[byte]) {.inline.} = + assert(len(key) > 0) + ctx.sizeKey = len(key) shl 3 + initBlowfishContext(ctx, unsafeAddr key[0], ctx.sizeKey) + +proc clear*(ctx: var BlowfishContext) {.inline.} = + burnMem(ctx) + +proc encrypt*(ctx: var BlowfishContext, inbytes: ptr byte, + outbytes: ptr byte) {.inline.} = + blowfishEncrypt(ctx, inbytes, outbytes) + +proc decrypt*(ctx: var BlowfishContext, inbytes: ptr byte, + outbytes: ptr byte) {.inline.} = + blowfishDecrypt(ctx, inbytes, outbytes) + +proc encrypt*(ctx: var BlowfishContext, input: openarray[byte], + output: var openarray[byte]) {.inline.} = + assert(len(input) == ctx.sizeBlock) + assert(len(input) <= len(output)) + blowfishEncrypt(ctx, unsafeAddr input[0], addr output[0]) + +proc decrypt*(ctx: var BlowfishContext, input: openarray[byte], + output: var openarray[byte]) {.inline.} = + assert(len(input) == ctx.sizeBlock) + assert(len(input) <= len(output)) + blowfishDecrypt(ctx, unsafeAddr input[0], addr output[0]) diff --git a/src/blobsets/priv/nimcrypto/hash.nim b/src/blobsets/priv/nimcrypto/hash.nim new file mode 100644 index 0000000..dc3be55 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/hash.nim @@ -0,0 +1,150 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module provides helper procedures for calculating secure digests +## supported by `nimcrypto` library. +import utils + +{.deadCodeElim:on.} + +const + MaxMDigestLength* = 64 + ## Maximum size of generated digests by `nimcrypto` library is 64 octets. + +type + MDigest*[bits: static[int]] = object + ## Message digest type + data*: array[bits div 8, byte] + + bchar* = byte | char + +proc `$`*(digest: MDigest): string = + ## Return hexadecimal string representation of ``digest``. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## var digestHexString = $sha256.digest("Hello World!") + ## echo digestHexString + result = "" + var i = 0'u + while i < uint(len(digest.data)): + result &= hexChar(cast[byte](digest.data[i])) + inc(i) + +proc digest*(HashType: typedesc, data: ptr byte, + ulen: uint): MDigest[HashType.bits] = + ## Calculate and return digest using algorithm ``HashType`` of data ``data`` + ## with length ``ulen``. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## var stringToHash = "Hello World!" + ## let data = cast[ptr byte](addr stringToHash[0]) + ## let datalen = uint(len(stringToHash)) + ## echo sha256.digest(data, datalen) + mixin init, update, finish, clear + var ctx: HashType + ctx.init() + ctx.update(data, ulen) + result = ctx.finish() + ctx.clear() + +proc digest*[T](HashType: typedesc, data: openarray[T], + ostart: int = 0, ofinish: int = -1): MDigest[HashType.bits] = + ## Calculate and return digest using algorithm ``HashType`` of data ``data`` + ## in slice ``[ostart, ofinish]``, both ``ostart`` and ``ofinish`` are + ## inclusive. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## var stringToHash = "Hello World!" + ## ## Calculate digest of whole string `Hello World!`. + ## echo sha256.digest(stringToHash) + ## ## Calcualte digest of `Hello`. + ## echo sha256.digest(stringToHash, ofinish = 4) + ## ## Calculate digest of `World!`. + ## echo sha256.digest(stringToHash, ostart = 6) + ## ## Calculate digest of constant `Hello`. + ## echo sha256.digest("Hello") + ## ## Calculate digest of constant `World!`. + ## echo sha256.digest("World!") + mixin init, update, finish, clear + var ctx: HashType + let so = if ostart < 0: (len(data) + ostart) else: ostart + let eo = if ofinish < 0: (len(data) + ofinish) else: ofinish + let length = (eo - so + 1) * sizeof(T) + ctx.init() + if length <= 0: + result = ctx.finish() + else: + ctx.update(cast[ptr byte](unsafeAddr data[so]), uint(length)) + result = ctx.finish() + ctx.clear() + +proc fromHex*(T: typedesc[MDigest], s: string): T = + ## Create ``MDigest`` object from hexadecimal string representation. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## var a = MDigest[256].fromHex("7F83B1657FF1FC53B92DC18148A1D65DFC2D4B1FA3D677284ADDD200126D9069") + ## echo $a + ## ## Get number of bits used by ``a``. + ## echo a.bits + hexToBytes(s, result.data) + +proc `==`*[A, B](d1: MDigest[A], d2: MDigest[B]): bool = + ## Check for equality between two ``MDigest`` objects ``d1`` and ``d2``. + ## If size in bits of ``d1`` is not equal to size in bits of ``d2`` then + ## digests considered as not equal. + if d1.bits != d2.bits: + return false + var n = len(d1.data) + var res, diff: int + while n > 0: + dec(n) + diff = int(d1.data[n]) - int(d2.data[n]) + res = (res and -not(diff)) or diff + result = (res == 0) + +when true: + proc toDigestAux(n: static int, s: static string): MDigest[n] = + static: + assert n > 0 and n mod 8 == 0, + "The provided hex string should have an even non-zero length" + hexToBytes(s, result.data) + + template toDigest*(s: static string): auto = + ## Convert hexadecimal string representation to ``MDigest`` object. + ## This template can be used to create ``MDigest`` constants. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## const SomeDigest = "7F83B1657FF1FC53B92DC18148A1D65DFC2D4B1FA3D677284ADDD200126D9069".toDigest + ## echo $SomeDigest + ## ## Get number of bits used by ``SomeDigest``. + ## echo SomeDigest.bits + const digest = toDigestAux(len(s) * 4, s) + digest + +else: + # This definition is shorter, but it turns out that it + # triggers a Nim bug. Calls to `toDigest` will compile, + # but the result values won't be considered the same + # type as MDigest[N] even when s.len * 4 == N + proc toDigest*(s: static string): MDigest[s.len * 4] = + static: + assert s.len > 0 and s.len mod 2 == 0, + "The provided hex string should have an even non-zero length" + const digest = hexToBytes(s, result.data) + return digest diff --git a/src/blobsets/priv/nimcrypto/hmac.nim b/src/blobsets/priv/nimcrypto/hmac.nim new file mode 100644 index 0000000..da692ac --- /dev/null +++ b/src/blobsets/priv/nimcrypto/hmac.nim @@ -0,0 +1,289 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements HMAC (Keyed-Hashing for Message Authentication) +## [http://www.ietf.org/rfc/rfc2104.txt]. +## +## Module provides two common interfaces for calculating HMAC. +## ``Classic`` method allows to process big chunks of data using limited amount +## of memory, while ``one-line`` method allows you to perform HMAC calculation +## in one line of code. +## +## .. code-block::nim +## import nimcrypto +## +## ## ``Classic`` method of HMAC calculation. +## +## var stringToHmac = "Hello World!" +## var stringHmacKey = "AliceKey" +## let ptrToHmac = cast[ptr byte](addr stringToHmac[0]) +## let ptrHmacKey = cast[ptr byte](addr stringHmacKey[0]) +## let toHmacLen = uint(len(stringToHmac)) +## let hmacKeyLen = uint(len(stringHmacKey)) +## +## # Declare context objects +## var hctx1, hctx2: HMAC[sha256] +## # Initalize HMAC[SHA256] contexts with key `AliceKey`. +## hctx1.init(stringHmacKey) +## hctx2.init(ptrHmacKey, hmacKeyLen) +## # Update HMAC[SHA256] context using data `Hello World!` twice. +## hctx1.update(stringToHmac) +## hctx1.update(stringToHmac) +## # Update HMAC[SHA256] context using data `Hello World!` twice. +## hctx2.update(ptrToHmac, toHmacLen) +## hctx2.update(ptrToHmac, toHmacLen) +## # Print HMAC[SHA256] digest. +## echo $hctx1.finish() +## echo $hctx2.finish() +## # Do not forget to clear contexts. +## hctx1.clear() +## hctx2.clear() +## +## ## ``One-line`` method of HMAC calculation. +## +## # Print HMAC[SHA256] digest of `Hello World!Hello World!` using key +## # `AliceKey`. +## echo $sha256.hmac(stringHmacKey, stringToHmac & stringToHmac) +## +## # Output to stdout must be 3 equal digests: +## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D +## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D +## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D +import hash, utils +from sha2 import Sha2Context +from ripemd import RipemdContext +from keccak import KeccakContext +from blake2 import Blake2Context + +{.deadCodeElim:on.} + +const + MaxHmacBlockSize = 256 + +type + HMAC*[HashType] = object + ## HMAC context object. + mdctx: HashType + opadctx: HashType + +template sizeBlock*(h: HMAC[Sha2Context]): uint = + ## Size of processing block in octets (bytes), while perform HMAC + ## operation using SHA2 algorithms. + cast[uint](h.HashType.sizeBlock) + +template sizeBlock*(h: HMAC[RipemdContext]): uint = + ## Size of processing block in octets (bytes), while perform HMAC + ## operation using RIPEMD algorithms. + cast[uint](h.HashType.sizeBlock) + +template sizeBlock*(h: HMAC[KeccakContext]): uint = + ## Size of processing block in octets (bytes), while perform HMAC + ## operation using KECCAK/SHA3/SHAKE algorithms. + when h.HashType.kind == Keccak or h.HashType.kind == Sha3: + when h.HashType.bits == 224: + 144'u + elif h.HashType.bits == 256: + 136'u + elif h.HashType.bits == 384: + 104'u + elif h.HashType.bits == 512: + 72'u + else: + {.fatal: "Choosen hash primitive is not yet supported!".} + else: + {.fatal: "Choosen hash primitive is not yet supported!".} + +template sizeBlock*(h: HMAC[Blake2Context]): uint = + ## Size of processing block in octets (bytes), while perform HMAC + ## operation using BLAKE2b/BLAKE2s algorithms. + cast[uint](h.HashType.sizeBlock) + +template sizeDigest*(h: HMAC[Sha2Context]): uint = + ## Size of HMAC digest in octets (bytes) using SHA2 algorithms. + cast[uint](h.mdctx.sizeDigest) + +template sizeDigest*(h: HMAC[RipemdContext]): uint = + ## Size of HMAC digest in octets (bytes) using RIPEMD algorithms. + cast[uint](h.mdctx.sizeDigest) + +template sizeDigest*(h: HMAC[KeccakContext]): uint = + ## Size of HMAC digest in octets (bytes) using KECCAK/SHA3/SHAKE + ## algorithms. + cast[uint](h.mdctx.sizeDigest) + +template sizeDigest*(h: HMAC[Blake2Context]): uint = + ## Size of HMAC digest in octets (bytes) using BLAKE2b/BLAKE2s algorithms. + cast[uint](h.mdctx.sizeDigest) + +proc init*[T](hmctx: var HMAC[T], key: ptr byte, ulen: uint) = + ## Initialize HMAC context ``hmctx`` with key using ``key`` and size ``ulen``. + ## + ## ``key`` can be ``nil``. + mixin init, update, finish + var k: array[MaxHmacBlockSize, byte] + var ipad: array[MaxHmacBlockSize, byte] + var opad: array[MaxHmacBlockSize, byte] + const sizeBlock = hmctx.sizeBlock + + hmctx.mdctx = T() + hmctx.opadctx = T() + init(hmctx.opadctx) + + if not isNil(key): + if ulen > sizeBlock: + init(hmctx.mdctx) + update(hmctx.mdctx, key, ulen) + discard finish(hmctx.mdctx, addr k[0], sizeBlock) + else: + if ulen > 0'u: copyMem(addr k[0], key, ulen) + + for i in 0..= hmctx.sizeDigest) + result = finish(hmctx, cast[ptr byte](addr data[0]), ulen) + +proc finish*(hmctx: var HMAC): MDigest[hmctx.HashType.bits] = + ## Finalize HMAC context ``hmctx`` and return calculated digest as ``MDigest`` + ## object. + discard finish(hmctx, cast[ptr byte](addr result.data[0]), + cast[uint](len(result.data))) + +proc hmac*(HashType: typedesc, key: ptr byte, klen: uint, + data: ptr byte, ulen: uint): MDigest[HashType.bits] = + ## Perform HMAC computation with hash algorithm ``HashType`` using key ``key`` + ## of length ``klen`` on data buffer pointed by ``data`` of length ``ulen``. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## var stringToHmac = "Hello World!" + ## var stringHmacKey = "AliceKey" + ## let data = cast[ptr byte](addr stringToHmac[0]) + ## let datalen = uint(len(stringToHmac)) + ## let key = cast[ptr byte](addr stringHmacKey[0]) + ## let keylen = uint(len(stringHmacKey)) + ## # Print HMAC[SHA256](key = "AliceKey", data = "Hello World!") + ## echo sha256.hmac(key, keylen, data, datalen) + ## # Print HMAC[SHA512](key = "AliceKey", data = "Hello World!") + ## echo sha512.hmac(key, keylen, data, datalen) + ## # Print HMAC[KECCAK256](key = "AliceKey", data = "Hello World!") + ## echo keccak256.hmac(key, keylen, data, datalen) + ## # Print HMAC[RIPEMD160](key = "AliceKey", data = "Hello World!") + ## echo ripemd160.hmac(key, keylen, data, datalen) + var ctx: HMAC[HashType] + ctx.init(key, klen) + ctx.update(data, ulen) + result = ctx.finish() + ctx.clear() + +proc hmac*[A, B](HashType: typedesc, key: openarray[A], + data: openarray[B], + ostart: int = 0, ofinish: int = -1): MDigest[HashType.bits] = + ## Perform HMAC computation with hash algorithm ``HashType`` using key ``key`` + ## of data ``data``, in slice ``[ostart, ofinish]``, both ``ostart`` and + ## ``ofinish`` are inclusive. + ## + ## .. code-block::nim + ## import nimcrypto + ## + ## var stringToHmac = "Hello World!" + ## var stringHmacKey = "AliceKey" + ## # Print HMAC[SHA256] digest of whole string `Hello World!` using + ## # key `AliceKey`. + ## echo sha256.hmac(stringHmacKey, stringToHmac) + ## # Print HMAC[SHA256] digest of `Hello` using key `AliceKey`. + ## echo sha256.hmac(stringHmacKey, stringToHmac, ofinish = 4) + ## # Print HMAC[SHA256] digest of `World!` using key `AliceKey`. + ## echo sha256.hmac(stringHmacKey, stringToHmac, ostart = 6) + ## # Print HMAC[SHA256] digest of constant `Hello` using constant key + ## # `AliceKey`. + ## echo sha256.hmac("AliceKey", "Hello") + ## # Print HMAC[SHA256] digest of constant `World!` using constant key + ## # `AliceKey` + ## echo sha256.hmac("AliceKey", "World!") + var ctx: HMAC[HashType] + let so = if ostart < 0: (len(data) + ostart) else: ostart + let eo = if ofinish < 0: (len(data) + ofinish) else: ofinish + let length = (eo - so + 1) * sizeof(B) + if len(key) == 0: + ctx.init(nil, 0) + else: + ctx.init(cast[ptr byte](unsafeAddr key[0]), + cast[uint](sizeof(A) * len(key))) + if length <= 0: + result = ctx.finish() + else: + ctx.update(cast[ptr byte](unsafeAddr data[so]), cast[uint](length)) + result = ctx.finish() + ctx.clear() diff --git a/src/blobsets/priv/nimcrypto/keccak.nim b/src/blobsets/priv/nimcrypto/keccak.nim new file mode 100644 index 0000000..df11715 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/keccak.nim @@ -0,0 +1,324 @@ +# +# +# NimCrypto +# (c) Copyright 2018 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements SHA3 (Secure Hash Algorithm 3) set of cryptographic +## hash functions designed by Guido Bertoni, Joan Daemen, Michaël Peeters and +## Gilles Van Assche. +## +## This module supports SHA3-224/256/384/512 and SHAKE-128/256. +## +## Tests for SHA3-225/256/384/512 made according to +## [https://www.di-mgt.com.au/sha_testvectors.html]. +## Test for SHAKE-128/256 made according to +## [https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values#aHashing] +## 0bit and 1600bit test vectors used. + +import hash, utils + +{.deadCodeElim:on.} + +const RNDC = [ + 0x0000000000000001'u64, 0x0000000000008082'u64, 0x800000000000808A'u64, + 0x8000000080008000'u64, 0x000000000000808B'u64, 0x0000000080000001'u64, + 0x8000000080008081'u64, 0x8000000000008009'u64, 0x000000000000008A'u64, + 0x0000000000000088'u64, 0x0000000080008009'u64, 0x000000008000000A'u64, + 0x000000008000808B'u64, 0x800000000000008B'u64, 0x8000000000008089'u64, + 0x8000000000008003'u64, 0x8000000000008002'u64, 0x8000000000000080'u64, + 0x000000000000800A'u64, 0x800000008000000A'u64, 0x8000000080008081'u64, + 0x8000000000008080'u64, 0x0000000080000001'u64, 0x8000000080008008'u64 +] + +type + KeccakKind* = enum + Sha3, Keccak, Shake + + KeccakContext*[bits: static[int], + kind: static[KeccakKind]] = object + q: array[25, uint64] + pt: int + + keccak224* = KeccakContext[224, Keccak] + keccak256* = KeccakContext[256, Keccak] + keccak384* = KeccakContext[384, Keccak] + keccak512* = KeccakContext[512, Keccak] + sha3_224* = KeccakContext[224, Sha3] + sha3_256* = KeccakContext[256, Sha3] + sha3_384* = KeccakContext[384, Sha3] + sha3_512* = KeccakContext[512, Sha3] + shake128* = KeccakContext[128, Shake] + shake256* = KeccakContext[256, Shake] + keccak* = keccak224 | keccak256 | keccak384 | keccak512 | + sha3_224 | sha3_256 | sha3_384 | sha3_512 + +template THETA1(a, b, c: untyped) = + (a)[(c)] = (b)[(c)] xor (b)[(c) + 5] xor (b)[(c) + 10] xor + (b)[(c) + 15] xor (b)[(c) + 20] + +template THETA2(a, b, c: untyped) = + (a) = (b)[((c) + 4) mod 5] xor ROL(cast[uint64]((b)[((c) + 1) mod 5]), 1) + +template THETA3(a, b) = + (a)[(b)] = (a)[(b)] xor t + (a)[(b) + 5] = (a)[(b) + 5] xor t + (a)[(b) + 10] = (a)[(b) + 10] xor t + (a)[(b) + 15] = (a)[(b) + 15] xor t + (a)[(b) + 20] = (a)[(b) + 20] xor t + +template RHOPI(a, b, c, d, e) = + (a)[0] = (b)[(d)] + (b)[(d)] = ROL(cast[uint64](c), e) + (c) = (a)[0] + +template CHI(a, b, c) = + (a)[0] = (b)[(c)] + (a)[1] = (b)[(c) + 1] + (a)[2] = (b)[(c) + 2] + (a)[3] = (b)[(c) + 3] + (a)[4] = (b)[(c) + 4] + (b)[(c)] = (b)[(c)] xor (not((a)[1]) and (a)[2]) + (b)[(c + 1)] = (b)[(c + 1)] xor (not((a)[2]) and (a)[3]) + (b)[(c + 2)] = (b)[(c + 2)] xor (not((a)[3]) and (a)[4]) + (b)[(c + 3)] = (b)[(c + 3)] xor (not((a)[4]) and (a)[0]) + (b)[(c + 4)] = (b)[(c + 4)] xor (not((a)[0]) and (a)[1]) + +template KECCAKROUND(a, b, c, r) = + THETA1((b), (a), 0) + THETA1((b), (a), 1) + THETA1((b), (a), 2) + THETA1((b), (a), 3) + THETA1((b), (a), 4) + + THETA2((c), (b), 0) + THETA3((a), 0) + THETA2((c), (b), 1) + THETA3((a), 1) + THETA2((c), (b), 2) + THETA3((a), 2) + THETA2((c), (b), 3) + THETA3((a), 3) + THETA2((c), (b), 4) + THETA3((a), 4) + + (c) = (a)[1] + RHOPI((b), (a), (c), 10, 1) + RHOPI((b), (a), (c), 7, 3) + RHOPI((b), (a), (c), 11, 6) + RHOPI((b), (a), (c), 17, 10) + RHOPI((b), (a), (c), 18, 15) + RHOPI((b), (a), (c), 3, 21) + RHOPI((b), (a), (c), 5, 28) + RHOPI((b), (a), (c), 16, 36) + RHOPI((b), (a), (c), 8, 45) + RHOPI((b), (a), (c), 21, 55) + RHOPI((b), (a), (c), 24, 2) + RHOPI((b), (a), (c), 4, 14) + RHOPI((b), (a), (c), 15, 27) + RHOPI((b), (a), (c), 23, 41) + RHOPI((b), (a), (c), 19, 56) + RHOPI((b), (a), (c), 13, 8) + RHOPI((b), (a), (c), 12, 25) + RHOPI((b), (a), (c), 2, 43) + RHOPI((b), (a), (c), 20, 62) + RHOPI((b), (a), (c), 14, 18) + RHOPI((b), (a), (c), 22, 39) + RHOPI((b), (a), (c), 9, 61) + RHOPI((b), (a), (c), 6, 20) + RHOPI((b), (a), (c), 1, 44) + + # Chi + CHI((b), (a), 0) + CHI((b), (a), 5) + CHI((b), (a), 10) + CHI((b), (a), 15) + CHI((b), (a), 20) + + (a)[0] = (a)[0] xor RNDC[(r)] + +proc keccakTransform(st: var array[25, uint64]) = + var bc: array[5, uint64] + var t: uint64 + + st[0] = BSWAP(st[0]) + st[1] = BSWAP(st[1]) + st[2] = BSWAP(st[2]) + st[3] = BSWAP(st[3]) + st[4] = BSWAP(st[4]) + st[5] = BSWAP(st[5]) + st[6] = BSWAP(st[6]) + st[7] = BSWAP(st[7]) + st[8] = BSWAP(st[8]) + st[9] = BSWAP(st[9]) + st[10] = BSWAP(st[10]) + st[11] = BSWAP(st[11]) + st[12] = BSWAP(st[12]) + st[13] = BSWAP(st[13]) + st[14] = BSWAP(st[14]) + st[15] = BSWAP(st[15]) + st[16] = BSWAP(st[16]) + st[17] = BSWAP(st[17]) + st[18] = BSWAP(st[18]) + st[19] = BSWAP(st[19]) + st[20] = BSWAP(st[20]) + st[21] = BSWAP(st[21]) + st[22] = BSWAP(st[22]) + st[23] = BSWAP(st[23]) + st[24] = BSWAP(st[24]) + + KECCAKROUND(st, bc, t, 0) + KECCAKROUND(st, bc, t, 1) + KECCAKROUND(st, bc, t, 2) + KECCAKROUND(st, bc, t, 3) + KECCAKROUND(st, bc, t, 4) + KECCAKROUND(st, bc, t, 5) + KECCAKROUND(st, bc, t, 6) + KECCAKROUND(st, bc, t, 7) + KECCAKROUND(st, bc, t, 8) + KECCAKROUND(st, bc, t, 9) + KECCAKROUND(st, bc, t, 10) + KECCAKROUND(st, bc, t, 11) + KECCAKROUND(st, bc, t, 12) + KECCAKROUND(st, bc, t, 13) + KECCAKROUND(st, bc, t, 14) + KECCAKROUND(st, bc, t, 15) + KECCAKROUND(st, bc, t, 16) + KECCAKROUND(st, bc, t, 17) + KECCAKROUND(st, bc, t, 18) + KECCAKROUND(st, bc, t, 19) + KECCAKROUND(st, bc, t, 20) + KECCAKROUND(st, bc, t, 21) + KECCAKROUND(st, bc, t, 22) + KECCAKROUND(st, bc, t, 23) + + st[0] = BSWAP(st[0]) + st[1] = BSWAP(st[1]) + st[2] = BSWAP(st[2]) + st[3] = BSWAP(st[3]) + st[4] = BSWAP(st[4]) + st[5] = BSWAP(st[5]) + st[6] = BSWAP(st[6]) + st[7] = BSWAP(st[7]) + st[8] = BSWAP(st[8]) + st[9] = BSWAP(st[9]) + st[10] = BSWAP(st[10]) + st[11] = BSWAP(st[11]) + st[12] = BSWAP(st[12]) + st[13] = BSWAP(st[13]) + st[14] = BSWAP(st[14]) + st[15] = BSWAP(st[15]) + st[16] = BSWAP(st[16]) + st[17] = BSWAP(st[17]) + st[18] = BSWAP(st[18]) + st[19] = BSWAP(st[19]) + st[20] = BSWAP(st[20]) + st[21] = BSWAP(st[21]) + st[22] = BSWAP(st[22]) + st[23] = BSWAP(st[23]) + st[24] = BSWAP(st[24]) + +template sizeDigest*(ctx: KeccakContext): uint = + (ctx.bits div 8) + +template sizeBlock*(ctx: KeccakContext): uint = + (200) + +template rsize(ctx: KeccakContext): int = + 200 - 2 * (ctx.bits div 8) + +template sizeDigest*(r: typedesc[keccak | shake128 | shake256]): int = + when r is shake128: + (16) + elif r is keccak224 or r is sha3_224: + (28) + elif r is keccak256 or r is sha3_256 or r is shake256: + (32) + elif r is keccak384 or r is sha3_384: + (48) + elif r is keccak512 or r is sha3_512: + (64) + +template sizeBlock*(r: typedesc[keccak | shake128 | shake256]): int = + (200) + +proc init*(ctx: var KeccakContext) = + burnMem(ctx) + +proc clear*(ctx: var KeccakContext) {.inline.} = + ctx.init() + +proc update*(ctx: var KeccakContext, data: ptr byte, ulen: uint) = + var j = ctx.pt + var s = cast[ptr UncheckedArray[byte]](data) + var d = cast[ptr UncheckedArray[byte]](addr ctx.q[0]) + if ulen > 0'u: + for i in 0..(ulen - 1): + d[j] = d[j] xor s[i] + inc(j) + if j >= ctx.rsize: + keccakTransform(ctx.q) + j = 0 + ctx.pt = j + +proc update*[T: bchar](ctx: var KeccakContext, data: openarray[T]) = + if len(data) == 0: + update(ctx, nil, 0'u) + else: + update(ctx, cast[ptr byte](unsafeAddr data[0]), cast[uint](len(data))) + +proc finalizeKeccak(ctx: var KeccakContext) = + var d = cast[ptr UncheckedArray[byte]](addr ctx.q[0]) + when ctx.kind == Sha3: + d[ctx.pt] = d[ctx.pt] xor 0x06'u8 + else: + d[ctx.pt] = d[ctx.pt] xor 0x01'u8 + d[ctx.rsize - 1] = d[ctx.rsize - 1] xor 0x80'u8 + keccakTransform(ctx.q) + +proc xof*(ctx: var KeccakContext) = + when ctx.kind != Shake: + {.error: "Only `Shake128` and `Shake256` types are supported".} + assert(ctx.kind == Shake) + var d = cast[ptr UncheckedArray[byte]](addr ctx.q[0]) + d[ctx.pt] = d[ctx.pt] xor 0x1F'u8 + d[ctx.rsize - 1] = d[ctx.rsize - 1] xor 0x80'u8 + keccakTransform(ctx.q) + ctx.pt = 0 + +proc output*(ctx: var KeccakContext, data: ptr byte, ulen: uint): uint = + when ctx.kind != Shake: + {.error: "Only `Shake128` and `Shake256` types are supported".} + var j = ctx.pt + var s = cast[ptr UncheckedArray[byte]](addr ctx.q[0]) + var d = cast[ptr UncheckedArray[byte]](data) + + if ulen > 0'u: + for i in 0..(ulen - 1): + if j >= ctx.rsize: + keccakTransform(ctx.q) + j = 0 + d[i] = s[j] + inc(j) + ctx.pt = j + result = ulen + +proc finish*(ctx: var KeccakContext, data: ptr byte, ulen: uint): uint = + finalizeKeccak(ctx) + var d = cast[ptr UncheckedArray[byte]](data) + var s = cast[ptr UncheckedArray[byte]](addr ctx.q[0]) + if ulen >= ctx.sizeDigest: + for i in 0..(ctx.sizeDigest - 1): + d[i] = s[i] + result = ctx.sizeDigest + +proc finish*(ctx: var KeccakContext): MDigest[ctx.bits] = + discard finish(ctx, cast[ptr byte](addr result.data[0]), + cast[uint](len(result.data))) + +proc finish*[T: bchar](ctx: var KeccakContext, data: var openarray[T]) = + assert(cast[uint](len(data)) >= ctx.sizeDigest) + discard ctx.finish(cast[ptr byte](addr data[0]), cast[uint](len(data))) diff --git a/src/blobsets/priv/nimcrypto/pbkdf2.nim b/src/blobsets/priv/nimcrypto/pbkdf2.nim new file mode 100644 index 0000000..b5a2c42 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/pbkdf2.nim @@ -0,0 +1,67 @@ +# +# +# NimCrypto +# (c) Copyright 2018 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements PBKDF2 (Password-Based Key Derivation Function 2) +## [https://tools.ietf.org/html/rfc2898#section-5.2] +## +## Tests for PBKDF2-HMAC-SHA224/256/384/512 made according to +## [https://github.com/Anti-weakpasswords/PBKDF2-Test-Vectors/releases] + +import hmac + +proc pbkdf2*[T](ctx: var HMAC[T], password: string, salt: string, c: int, + output: var openarray[byte], outlen: int = -1): int = + ## Calculate PBKDF2 result using HMAC algorithm `ctx`. + ## + ## ``ctx`` - HMAC[T] context + ## ``password`` - password string + ## ``salt`` - salt string + ## ``c`` - number of iterations + ## ``output`` - array of bytes where result will be stored. + ## ``outlen`` - length of bytes to be stored (-1 default, whole `output`) + ## + ## Returns number of bytes stored on success, or 0 on error. + mixin init, update, finish + var + counter: array[4, byte] + work: array[ctx.sizeDigest, byte] + md: array[ctx.sizeDigest, byte] + ctr: uint32 + glength: int + olength: int + bytesWrite: int + if len(output) > 0xFFFF_FFFF: # (2^32 - 1) + return 0 + let pwd = cast[seq[byte]](password) + let slt = cast[seq[byte]](salt) + ctr = 1 + glength = 0 + olength = if outlen == -1: len(output) else: outlen + while glength < olength: + counter[0] = byte((ctr shr 24) and 0xFF) + counter[1] = byte((ctr shr 16) and 0xFF) + counter[2] = byte((ctr shr 8) and 0xFF) + counter[3] = byte(ctr and 0xFF) + ctx.init(pwd) + ctx.update(slt) + ctx.update(counter) + discard ctx.finish(md) + work = md + for i in 1.. 10: + ENC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKe, 10) + ENC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKe, 11) + if ctx.Nr > 12: + ENC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKe, 12) + ENC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKe, 13) + + let offset = (ctx.Nr shl 2).uint32 + + s0 = (Te4[(t0 shr 24)] and 0xFF000000'u32) xor + (Te4[(t1 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Te4[(t2 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Te4[t3 and 0xFF] and 0x000000FF'u32) xor + ctx.RKe[offset] + s1 = (Te4[(t1 shr 24)] and 0xFF000000'u32) xor + (Te4[(t2 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Te4[(t3 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Te4[t0 and 0xFF] and 0x000000FF'u32) xor + ctx.RKe[offset + 1] + s2 = (Te4[(t2 shr 24)] and 0xFF000000'u32) xor + (Te4[(t3 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Te4[(t0 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Te4[t1 and 0xFF] and 0x000000FF'u32) xor + ctx.RKe[offset + 2] + s3 = (Te4[(t3 shr 24)] and 0xFF000000'u32) xor + (Te4[(t0 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Te4[(t1 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Te4[t2 and 0xFF] and 0x000000FF'u32) xor + ctx.RKe[offset + 3] + + PUTU32(oup, 0, s0) + PUTU32(oup, 4, s1) + PUTU32(oup, 8, s2) + PUTU32(oup, 12, s3) + +proc rijndaelDecrypt*(ctx: var RijndaelContext, inp: ptr byte, + oup: ptr byte) = + var t0, t1, t2, t3: uint32 + + var s0 = GETU32(inp, 0) xor ctx.RKd[0] + var s1 = GETU32(inp, 4) xor ctx.RKd[1] + var s2 = GETU32(inp, 8) xor ctx.RKd[2] + var s3 = GETU32(inp, 12) xor ctx.RKd[3] + + DEC_ROUND(t0, t1, t2 ,t3, s0, s1, s2, s3, ctx.RKd, 1) + DEC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKd, 2) + DEC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKd, 3) + DEC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKd, 4) + DEC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKd, 5) + DEC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKd, 6) + DEC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKd, 7) + DEC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKd, 8) + DEC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKd, 9) + if ctx.Nr > 10: + DEC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKd, 10) + DEC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKd, 11) + if ctx.Nr > 12: + DEC_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, ctx.RKd, 12) + DEC_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, ctx.RKd, 13) + + let offset = (ctx.Nr shl 2).uint32 + + s0 = (Td4[(t0 shr 24)] and 0xFF000000'u32) xor + (Td4[(t3 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Td4[(t2 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Td4[t1 and 0xFF] and 0x000000FF'u32) xor + ctx.RKd[offset] + s1 = (Td4[(t1 shr 24)] and 0xFF000000'u32) xor + (Td4[(t0 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Td4[(t3 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Td4[t2 and 0xFF] and 0x000000FF'u32) xor + ctx.RKd[offset + 1] + s2 = (Td4[(t2 shr 24)] and 0xFF000000'u32) xor + (Td4[(t1 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Td4[(t0 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Td4[t3 and 0xFF] and 0x000000FF'u32) xor + ctx.RKd[offset + 2] + s3 = (Td4[(t3 shr 24)] and 0xFF000000'u32) xor + (Td4[(t2 shr 16) and 0xFF] and 0x00FF0000'u32) xor + (Td4[(t1 shr 8) and 0xFF] and 0x0000FF00'u32) xor + (Td4[t0 and 0xFF] and 0x000000FF'u32) xor + ctx.RKd[offset + 3] + + PUTU32(oup, 0, s0) + PUTU32(oup, 4, s1) + PUTU32(oup, 8, s2) + PUTU32(oup, 12, s3) + +proc initRijndaelContext*(ctx: var RijndaelContext, N: int, key: ptr byte) = + ctx.Nr = rijndaelKeySetupDec(ctx, N, key) + +template sizeKey*(ctx: RijndaelContext): int = + (ctx.bits div 8) + +template sizeBlock*(ctx: RijndaelContext): int = + (16) + +template sizeKey*(r: typedesc[rijndael]): int = + when r is aes128 or r is rijndael128: + (16) + elif r is aes192 or r is rijndael192: + (24) + elif r is aes256 or r is rijndael256: + (32) + +template sizeBlock*(r: typedesc[rijndael]): int = + (16) + +proc init*(ctx: var RijndaelContext, key: ptr byte, nkey: int = 0) {.inline.} = + ctx.Nr = rijndaelKeySetupDec(ctx, ctx.bits, key) + +proc init*(ctx: var RijndaelContext, key: openarray[byte]) {.inline.} = + assert(len(key) >= ctx.sizeKey) + ctx.Nr = rijndaelKeySetupDec(ctx, ctx.bits, unsafeAddr key[0]) + +proc clear*(ctx: var RijndaelContext) {.inline.} = + burnMem(ctx) + +proc encrypt*(ctx: var RijndaelContext, inbytes: ptr byte, + outbytes: ptr byte) {.inline.} = + rijndaelEncrypt(ctx, inbytes, outbytes) + +proc decrypt*(ctx: var RijndaelContext, inbytes: ptr byte, + outbytes: ptr byte) {.inline.} = + rijndaelDecrypt(ctx, inbytes, outbytes) + +proc encrypt*(ctx: var RijndaelContext, input: openarray[byte], + output: var openarray[byte]) {.inline.} = + assert(len(input) == ctx.sizeBlock) + assert(len(input) <= len(output)) + rijndaelEncrypt(ctx, unsafeAddr input[0], addr output[0]) + +proc decrypt*(ctx: var RijndaelContext, input: openarray[byte], + output: var openarray[byte]) {.inline.} = + assert(len(input) == ctx.sizeBlock) + assert(len(input) <= len(output)) + rijndaelDecrypt(ctx, unsafeAddr input[0], addr output[0]) diff --git a/src/blobsets/priv/nimcrypto/ripemd.nim b/src/blobsets/priv/nimcrypto/ripemd.nim new file mode 100644 index 0000000..93c19cc --- /dev/null +++ b/src/blobsets/priv/nimcrypto/ripemd.nim @@ -0,0 +1,750 @@ +# +# +# NimCrypto +# (c) Copyright 2016-2018 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements RIPEMD set of cryptographic hash functions, +## designed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. +## [http://www.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf] +## +## This module is Nim adoptation of original C source code by +## Antoon Bosselaers. +## [https://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c] +## +## This module includes support of RIPEMD-128/160/256/320. +## +## Tests made according to official test vectors +## [https://homes.esat.kuleuven.be/~bosselae/ripemd160.html]. + +import hash, utils + +type + RipemdContext*[bits: static[int]] = object + count: array[2, uint32] + state: array[bits div 32, uint32] + buffer: array[64, byte] + + ripemd128* = RipemdContext[128] + ripemd160* = RipemdContext[160] + ripemd256* = RipemdContext[256] + ripemd320* = RipemdContext[320] + ripemd* = ripemd128 | ripemd160 | ripemd256 | ripemd320 + +# Five basic functions F(), G() and H() +template F(x, y, z: untyped): untyped = + # x^y^z + ((x) xor (y) xor (z)) + +template G(x, y, z: untyped): untyped = + # (x&y)|(~x&z) + (((x) and (y)) or (not (x) and (z))) + +template H(x, y, z: untyped): untyped = + # (x|~y)^z + (((x) or not (y)) xor (z)) + +template I(x, y, z: untyped): untyped = + # (x&z)|(y&~z) + (((x) and (z)) or ((y) and not (z))) + +template J(x, y, z: untyped): untyped = + # x^(y|~z) + ((x) xor ((y) or not (z))) + +# Eight basic operations FF() through III() for 128 and 256 bits +template FF128(a, b, c, d, x, s: untyped): void = + (a) = (a) + F((b), (c), (d)) + (x) + (a) = ROL(cast[uint32](a), (s)) + +template GG128(a, b, c, d, x, s: untyped): void = + (a) = (a) + G((b), (c), (d)) + (x) + 0x5A827999'u32 + (a) = ROL(cast[uint32](a), (s)) + +template HH128(a, b, c, d, x, s: untyped): void = + (a) = (a) + H((b), (c), (d)) + (x) + 0x6ED9EBA1'u32 + (a) = ROL(cast[uint32](a), (s)) + +template II128(a, b, c, d, x, s: untyped): void = + (a) = (a) + I((b), (c), (d)) + (x) + 0x8F1BBCDC'u32 + (a) = ROL(cast[uint32](a), (s)) + +template FFF128(a, b, c, d, x, s: untyped): void = + (a) = (a) + F((b), (c), (d)) + (x) + (a) = ROL(cast[uint32](a), (s)) + +template GGG128(a, b, c, d, x, s: untyped): void = + (a) = (a) + G((b), (c), (d)) + (x) + 0x6D703EF3'u32 + (a) = ROL(cast[uint32](a), (s)) + +template HHH128(a, b, c, d, x, s: untyped): void = + (a) = (a) + H((b), (c), (d)) + (x) + 0x5C4DD124'u32 + (a) = ROL(cast[uint32](a), (s)) + +template III128(a, b, c, d, x, s: untyped): void = + (a) = (a) + I((b), (c), (d)) + (x) + 0x50A28BE6'u32 + (a) = ROL((a), (s)) + +# Ten basic operations FF() through III() for 160 and 320 bits +template FF160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + F((b), (c), (d)) + (x) + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template GG160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + G((b), (c), (d)) + (x) + 0x5A827999'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template HH160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + H((b), (c), (d)) + (x) + 0x6ED9EBA1'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template II160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + I((b), (c), (d)) + (x) + 0x8F1BBCDC'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template JJ160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + J((b), (c), (d)) + (x) + 0xA953FD4E'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template FFF160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + F((b), (c), (d)) + (x) + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template GGG160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + G((b), (c), (d)) + (x) + 0x7A6D76E9'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template HHH160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + H((b), (c), (d)) + (x) + 0x6D703EF3'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template III160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + I((b), (c), (d)) + (x) + 0x5C4DD124'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template JJJ160(a, b, c, d, e, x, s: untyped): void = + (a) = (a) + J((b), (c), (d)) + (x) + 0x50A28BE6'u32 + (a) = ROL(cast[uint32](a), (s)) + (e) + (c) = ROL(cast[uint32](c), 10) + +template LROUND128N1(a, b, c, d, x): void = + FF128(a, b, c, d, x[ 0], 11) + FF128(d, a, b, c, x[ 1], 14) + FF128(c, d, a, b, x[ 2], 15) + FF128(b, c, d, a, x[ 3], 12) + FF128(a, b, c, d, x[ 4], 5) + FF128(d, a, b, c, x[ 5], 8) + FF128(c, d, a, b, x[ 6], 7) + FF128(b, c, d, a, x[ 7], 9) + FF128(a, b, c, d, x[ 8], 11) + FF128(d, a, b, c, x[ 9], 13) + FF128(c, d, a, b, x[10], 14) + FF128(b, c, d, a, x[11], 15) + FF128(a, b, c, d, x[12], 6) + FF128(d, a, b, c, x[13], 7) + FF128(c, d, a, b, x[14], 9) + FF128(b, c, d, a, x[15], 8) + +template LROUND128N2(a, b, c, d, x): void = + GG128(a, b, c, d, x[ 7], 7) + GG128(d, a, b, c, x[ 4], 6) + GG128(c, d, a, b, x[13], 8) + GG128(b, c, d, a, x[ 1], 13) + GG128(a, b, c, d, x[10], 11) + GG128(d, a, b, c, x[ 6], 9) + GG128(c, d, a, b, x[15], 7) + GG128(b, c, d, a, x[ 3], 15) + GG128(a, b, c, d, x[12], 7) + GG128(d, a, b, c, x[ 0], 12) + GG128(c, d, a, b, x[ 9], 15) + GG128(b, c, d, a, x[ 5], 9) + GG128(a, b, c, d, x[ 2], 11) + GG128(d, a, b, c, x[14], 7) + GG128(c, d, a, b, x[11], 13) + GG128(b, c, d, a, x[ 8], 12) + +template LROUND128N3(a, b, c, d, x): void = + HH128(a, b, c, d, x[ 3], 11) + HH128(d, a, b, c, x[10], 13) + HH128(c, d, a, b, x[14], 6) + HH128(b, c, d, a, x[ 4], 7) + HH128(a, b, c, d, x[ 9], 14) + HH128(d, a, b, c, x[15], 9) + HH128(c, d, a, b, x[ 8], 13) + HH128(b, c, d, a, x[ 1], 15) + HH128(a, b, c, d, x[ 2], 14) + HH128(d, a, b, c, x[ 7], 8) + HH128(c, d, a, b, x[ 0], 13) + HH128(b, c, d, a, x[ 6], 6) + HH128(a, b, c, d, x[13], 5) + HH128(d, a, b, c, x[11], 12) + HH128(c, d, a, b, x[ 5], 7) + HH128(b, c, d, a, x[12], 5) + +template LROUND128N4(a, b, c, d, x): void = + II128(a, b, c, d, x[ 1], 11) + II128(d, a, b, c, x[ 9], 12) + II128(c, d, a, b, x[11], 14) + II128(b, c, d, a, x[10], 15) + II128(a, b, c, d, x[ 0], 14) + II128(d, a, b, c, x[ 8], 15) + II128(c, d, a, b, x[12], 9) + II128(b, c, d, a, x[ 4], 8) + II128(a, b, c, d, x[13], 9) + II128(d, a, b, c, x[ 3], 14) + II128(c, d, a, b, x[ 7], 5) + II128(b, c, d, a, x[15], 6) + II128(a, b, c, d, x[14], 8) + II128(d, a, b, c, x[ 5], 6) + II128(c, d, a, b, x[ 6], 5) + II128(b, c, d, a, x[ 2], 12) + +template RROUND128N1(a, b, c, d, x): void = + III128(a, b, c, d, x[ 5], 8) + III128(d, a, b, c, x[14], 9) + III128(c, d, a, b, x[ 7], 9) + III128(b, c, d, a, x[ 0], 11) + III128(a, b, c, d, x[ 9], 13) + III128(d, a, b, c, x[ 2], 15) + III128(c, d, a, b, x[11], 15) + III128(b, c, d, a, x[ 4], 5) + III128(a, b, c, d, x[13], 7) + III128(d, a, b, c, x[ 6], 7) + III128(c, d, a, b, x[15], 8) + III128(b, c, d, a, x[ 8], 11) + III128(a, b, c, d, x[ 1], 14) + III128(d, a, b, c, x[10], 14) + III128(c, d, a, b, x[ 3], 12) + III128(b, c, d, a, x[12], 6) + +template RROUND128N2(a, b, c, d, x): void = + HHH128(a, b, c, d, x[ 6], 9) + HHH128(d, a, b, c, x[11], 13) + HHH128(c, d, a, b, x[ 3], 15) + HHH128(b, c, d, a, x[ 7], 7) + HHH128(a, b, c, d, x[ 0], 12) + HHH128(d, a, b, c, x[13], 8) + HHH128(c, d, a, b, x[ 5], 9) + HHH128(b, c, d, a, x[10], 11) + HHH128(a, b, c, d, x[14], 7) + HHH128(d, a, b, c, x[15], 7) + HHH128(c, d, a, b, x[ 8], 12) + HHH128(b, c, d, a, x[12], 7) + HHH128(a, b, c, d, x[ 4], 6) + HHH128(d, a, b, c, x[ 9], 15) + HHH128(c, d, a, b, x[ 1], 13) + HHH128(b, c, d, a, x[ 2], 11) + +template RROUND128N3(a, b, c, d, x): void = + GGG128(a, b, c, d, x[15], 9) + GGG128(d, a, b, c, x[ 5], 7) + GGG128(c, d, a, b, x[ 1], 15) + GGG128(b, c, d, a, x[ 3], 11) + GGG128(a, b, c, d, x[ 7], 8) + GGG128(d, a, b, c, x[14], 6) + GGG128(c, d, a, b, x[ 6], 6) + GGG128(b, c, d, a, x[ 9], 14) + GGG128(a, b, c, d, x[11], 12) + GGG128(d, a, b, c, x[ 8], 13) + GGG128(c, d, a, b, x[12], 5) + GGG128(b, c, d, a, x[ 2], 14) + GGG128(a, b, c, d, x[10], 13) + GGG128(d, a, b, c, x[ 0], 13) + GGG128(c, d, a, b, x[ 4], 7) + GGG128(b, c, d, a, x[13], 5) + +template RROUND128N4(a, b, c, d, x): void = + FFF128(a, b, c, d, x[ 8], 15) + FFF128(d, a, b, c, x[ 6], 5) + FFF128(c, d, a, b, x[ 4], 8) + FFF128(b, c, d, a, x[ 1], 11) + FFF128(a, b, c, d, x[ 3], 14) + FFF128(d, a, b, c, x[11], 14) + FFF128(c, d, a, b, x[15], 6) + FFF128(b, c, d, a, x[ 0], 14) + FFF128(a, b, c, d, x[ 5], 6) + FFF128(d, a, b, c, x[12], 9) + FFF128(c, d, a, b, x[ 2], 12) + FFF128(b, c, d, a, x[13], 9) + FFF128(a, b, c, d, x[ 9], 12) + FFF128(d, a, b, c, x[ 7], 5) + FFF128(c, d, a, b, x[10], 15) + FFF128(b, c, d, a, x[14], 8) + +template LROUND160N1(a, b, c, d, e, x): void = + FF160(a, b, c, d, e, x[ 0], 11) + FF160(e, a, b, c, d, x[ 1], 14) + FF160(d, e, a, b, c, x[ 2], 15) + FF160(c, d, e, a, b, x[ 3], 12) + FF160(b, c, d, e, a, x[ 4], 5) + FF160(a, b, c, d, e, x[ 5], 8) + FF160(e, a, b, c, d, x[ 6], 7) + FF160(d, e, a, b, c, x[ 7], 9) + FF160(c, d, e, a, b, x[ 8], 11) + FF160(b, c, d, e, a, x[ 9], 13) + FF160(a, b, c, d, e, x[10], 14) + FF160(e, a, b, c, d, x[11], 15) + FF160(d, e, a, b, c, x[12], 6) + FF160(c, d, e, a, b, x[13], 7) + FF160(b, c, d, e, a, x[14], 9) + FF160(a, b, c, d, e, x[15], 8) + +template LROUND160N2(a, b, c, d, e, x): void = + GG160(e, a, b, c, d, x[ 7], 7) + GG160(d, e, a, b, c, x[ 4], 6) + GG160(c, d, e, a, b, x[13], 8) + GG160(b, c, d, e, a, x[ 1], 13) + GG160(a, b, c, d, e, x[10], 11) + GG160(e, a, b, c, d, x[ 6], 9) + GG160(d, e, a, b, c, x[15], 7) + GG160(c, d, e, a, b, x[ 3], 15) + GG160(b, c, d, e, a, x[12], 7) + GG160(a, b, c, d, e, x[ 0], 12) + GG160(e, a, b, c, d, x[ 9], 15) + GG160(d, e, a, b, c, x[ 5], 9) + GG160(c, d, e, a, b, x[ 2], 11) + GG160(b, c, d, e, a, x[14], 7) + GG160(a, b, c, d, e, x[11], 13) + GG160(e, a, b, c, d, x[ 8], 12) + +template LROUND160N3(a, b, c, d, e, x): void = + HH160(d, e, a, b, c, x[ 3], 11) + HH160(c, d, e, a, b, x[10], 13) + HH160(b, c, d, e, a, x[14], 6) + HH160(a, b, c, d, e, x[ 4], 7) + HH160(e, a, b, c, d, x[ 9], 14) + HH160(d, e, a, b, c, x[15], 9) + HH160(c, d, e, a, b, x[ 8], 13) + HH160(b, c, d, e, a, x[ 1], 15) + HH160(a, b, c, d, e, x[ 2], 14) + HH160(e, a, b, c, d, x[ 7], 8) + HH160(d, e, a, b, c, x[ 0], 13) + HH160(c, d, e, a, b, x[ 6], 6) + HH160(b, c, d, e, a, x[13], 5) + HH160(a, b, c, d, e, x[11], 12) + HH160(e, a, b, c, d, x[ 5], 7) + HH160(d, e, a, b, c, x[12], 5) + +template LROUND160N4(a, b, c, d, e, x): void = + II160(c, d, e, a, b, x[ 1], 11) + II160(b, c, d, e, a, x[ 9], 12) + II160(a, b, c, d, e, x[11], 14) + II160(e, a, b, c, d, x[10], 15) + II160(d, e, a, b, c, x[ 0], 14) + II160(c, d, e, a, b, x[ 8], 15) + II160(b, c, d, e, a, x[12], 9) + II160(a, b, c, d, e, x[ 4], 8) + II160(e, a, b, c, d, x[13], 9) + II160(d, e, a, b, c, x[ 3], 14) + II160(c, d, e, a, b, x[ 7], 5) + II160(b, c, d, e, a, x[15], 6) + II160(a, b, c, d, e, x[14], 8) + II160(e, a, b, c, d, x[ 5], 6) + II160(d, e, a, b, c, x[ 6], 5) + II160(c, d, e, a, b, x[ 2], 12) + +template LROUND160N5(a, b, c, d, e, x): void = + JJ160(b, c, d, e, a, x[ 4], 9) + JJ160(a, b, c, d, e, x[ 0], 15) + JJ160(e, a, b, c, d, x[ 5], 5) + JJ160(d, e, a, b, c, x[ 9], 11) + JJ160(c, d, e, a, b, x[ 7], 6) + JJ160(b, c, d, e, a, x[12], 8) + JJ160(a, b, c, d, e, x[ 2], 13) + JJ160(e, a, b, c, d, x[10], 12) + JJ160(d, e, a, b, c, x[14], 5) + JJ160(c, d, e, a, b, x[ 1], 12) + JJ160(b, c, d, e, a, x[ 3], 13) + JJ160(a, b, c, d, e, x[ 8], 14) + JJ160(e, a, b, c, d, x[11], 11) + JJ160(d, e, a, b, c, x[ 6], 8) + JJ160(c, d, e, a, b, x[15], 5) + JJ160(b, c, d, e, a, x[13], 6) + +template RROUND160N1(a, b, c, d, e, x): void = + JJJ160(a, b, c, d, e, x[ 5], 8) + JJJ160(e, a, b, c, d, x[14], 9) + JJJ160(d, e, a, b, c, x[ 7], 9) + JJJ160(c, d, e, a, b, x[ 0], 11) + JJJ160(b, c, d, e, a, x[ 9], 13) + JJJ160(a, b, c, d, e, x[ 2], 15) + JJJ160(e, a, b, c, d, x[11], 15) + JJJ160(d, e, a, b, c, x[ 4], 5) + JJJ160(c, d, e, a, b, x[13], 7) + JJJ160(b, c, d, e, a, x[ 6], 7) + JJJ160(a, b, c, d, e, x[15], 8) + JJJ160(e, a, b, c, d, x[ 8], 11) + JJJ160(d, e, a, b, c, x[ 1], 14) + JJJ160(c, d, e, a, b, x[10], 14) + JJJ160(b, c, d, e, a, x[ 3], 12) + JJJ160(a, b, c, d, e, x[12], 6) + +template RROUND160N2(a, b, c, d, e, x): void = + III160(e, a, b, c, d, x[ 6], 9) + III160(d, e, a, b, c, x[11], 13) + III160(c, d, e, a, b, x[ 3], 15) + III160(b, c, d, e, a, x[ 7], 7) + III160(a, b, c, d, e, x[ 0], 12) + III160(e, a, b, c, d, x[13], 8) + III160(d, e, a, b, c, x[ 5], 9) + III160(c, d, e, a, b, x[10], 11) + III160(b, c, d, e, a, x[14], 7) + III160(a, b, c, d, e, x[15], 7) + III160(e, a, b, c, d, x[ 8], 12) + III160(d, e, a, b, c, x[12], 7) + III160(c, d, e, a, b, x[ 4], 6) + III160(b, c, d, e, a, x[ 9], 15) + III160(a, b, c, d, e, x[ 1], 13) + III160(e, a, b, c, d, x[ 2], 11) + +template RROUND160N3(a, b, c, d, e, x): void = + HHH160(d, e, a, b, c, x[15], 9) + HHH160(c, d, e, a, b, x[ 5], 7) + HHH160(b, c, d, e, a, x[ 1], 15) + HHH160(a, b, c, d, e, x[ 3], 11) + HHH160(e, a, b, c, d, x[ 7], 8) + HHH160(d, e, a, b, c, x[14], 6) + HHH160(c, d, e, a, b, x[ 6], 6) + HHH160(b, c, d, e, a, x[ 9], 14) + HHH160(a, b, c, d, e, x[11], 12) + HHH160(e, a, b, c, d, x[ 8], 13) + HHH160(d, e, a, b, c, x[12], 5) + HHH160(c, d, e, a, b, x[ 2], 14) + HHH160(b, c, d, e, a, x[10], 13) + HHH160(a, b, c, d, e, x[ 0], 13) + HHH160(e, a, b, c, d, x[ 4], 7) + HHH160(d, e, a, b, c, x[13], 5) + +template RROUND160N4(a, b, c, d, e, x): void = + GGG160(c, d, e, a, b, x[ 8], 15) + GGG160(b, c, d, e, a, x[ 6], 5) + GGG160(a, b, c, d, e, x[ 4], 8) + GGG160(e, a, b, c, d, x[ 1], 11) + GGG160(d, e, a, b, c, x[ 3], 14) + GGG160(c, d, e, a, b, x[11], 14) + GGG160(b, c, d, e, a, x[15], 6) + GGG160(a, b, c, d, e, x[ 0], 14) + GGG160(e, a, b, c, d, x[ 5], 6) + GGG160(d, e, a, b, c, x[12], 9) + GGG160(c, d, e, a, b, x[ 2], 12) + GGG160(b, c, d, e, a, x[13], 9) + GGG160(a, b, c, d, e, x[ 9], 12) + GGG160(e, a, b, c, d, x[ 7], 5) + GGG160(d, e, a, b, c, x[10], 15) + GGG160(c, d, e, a, b, x[14], 8) + +template RROUND160N5(a, b, c, d, e, x): void = + FFF160(b, c, d, e, a, x[12] , 8) + FFF160(a, b, c, d, e, x[15] , 5) + FFF160(e, a, b, c, d, x[10] , 12) + FFF160(d, e, a, b, c, x[ 4] , 9) + FFF160(c, d, e, a, b, x[ 1] , 12) + FFF160(b, c, d, e, a, x[ 5] , 5) + FFF160(a, b, c, d, e, x[ 8] , 14) + FFF160(e, a, b, c, d, x[ 7] , 6) + FFF160(d, e, a, b, c, x[ 6] , 8) + FFF160(c, d, e, a, b, x[ 2] , 13) + FFF160(b, c, d, e, a, x[13] , 6) + FFF160(a, b, c, d, e, x[14] , 5) + FFF160(e, a, b, c, d, x[ 0] , 15) + FFF160(d, e, a, b, c, x[ 3] , 13) + FFF160(c, d, e, a, b, x[ 9] , 11) + FFF160(b, c, d, e, a, x[11] , 11) + +proc ripemd128Transform(state: var array[4, uint32], data: ptr byte) = + var + aa = state[0] + bb = state[1] + cc = state[2] + dd = state[3] + aaa = state[0] + bbb = state[1] + ccc = state[2] + ddd = state[3] + X = cast[ptr UncheckedArray[uint32]](data) + + LROUND128N1(aa, bb, cc, dd, X) + LROUND128N2(aa, bb, cc, dd, X) + LROUND128N3(aa, bb, cc, dd, X) + LROUND128N4(aa, bb, cc, dd, X) + RROUND128N1(aaa, bbb, ccc, ddd, X) + RROUND128N2(aaa, bbb, ccc, ddd, X) + RROUND128N3(aaa, bbb, ccc, ddd, X) + RROUND128N4(aaa, bbb, ccc, ddd, X) + + # combine results + ddd = ddd + cc + state[1] + state[1] = state[2] + dd + aaa + state[2] = state[3] + aa + bbb + state[3] = state[0] + bb + ccc + state[0] = ddd + +proc ripemd256Transform(state: var array[8, uint32], data: ptr byte) = + var + aa = state[0] + bb = state[1] + cc = state[2] + dd = state[3] + aaa = state[4] + bbb = state[5] + ccc = state[6] + ddd = state[7] + X = cast[ptr UncheckedArray[uint32]](data) + + LROUND128N1(aa, bb, cc, dd, X) + RROUND128N1(aaa, bbb, ccc, ddd, X) + swap(aa, aaa) + LROUND128N2(aa, bb, cc, dd, X) + RROUND128N2(aaa, bbb, ccc, ddd, X) + swap(bb, bbb) + LROUND128N3(aa, bb, cc, dd, X) + RROUND128N3(aaa, bbb, ccc, ddd, X) + swap(cc, ccc) + LROUND128N4(aa, bb, cc, dd, X) + RROUND128N4(aaa, bbb, ccc, ddd, X) + swap(dd, ddd) + + # combine results + state[0] = state[0] + aa + state[1] = state[1] + bb + state[2] = state[2] + cc + state[3] = state[3] + dd + state[4] = state[4] + aaa + state[5] = state[5] + bbb + state[6] = state[6] + ccc + state[7] = state[7] + ddd + +proc ripemd160Transform(state: var array[5, uint32], data: ptr byte) = + var + aa = state[0] + bb = state[1] + cc = state[2] + dd = state[3] + ee = state[4] + aaa = state[0] + bbb = state[1] + ccc = state[2] + ddd = state[3] + eee = state[4] + X = cast[ptr UncheckedArray[uint32]](data) + + LROUND160N1(aa, bb, cc, dd, ee, X) + LROUND160N2(aa, bb, cc, dd, ee, X) + LROUND160N3(aa, bb, cc, dd, ee, X) + LROUND160N4(aa, bb, cc, dd, ee, X) + LROUND160N5(aa, bb, cc, dd, ee, X) + RROUND160N1(aaa, bbb, ccc, ddd, eee, X) + RROUND160N2(aaa, bbb, ccc, ddd, eee, X) + RROUND160N3(aaa, bbb, ccc, ddd, eee, X) + RROUND160N4(aaa, bbb, ccc, ddd, eee, X) + RROUND160N5(aaa, bbb, ccc, ddd, eee, X) + + # combine results + ddd = ddd + cc + state[1] + state[1] = state[2] + dd + eee + state[2] = state[3] + ee + aaa + state[3] = state[4] + aa + bbb + state[4] = state[0] + bb + ccc + state[0] = ddd + +proc ripemd320Transform(state: var array[10, uint32], data: ptr byte) = + var + aa = state[0] + bb = state[1] + cc = state[2] + dd = state[3] + ee = state[4] + aaa = state[5] + bbb = state[6] + ccc = state[7] + ddd = state[8] + eee = state[9] + X = cast[ptr UncheckedArray[uint32]](data) + + LROUND160N1(aa, bb, cc, dd, ee, X) + RROUND160N1(aaa, bbb, ccc, ddd, eee, X) + swap(aa, aaa) + LROUND160N2(aa, bb, cc, dd, ee, X) + RROUND160N2(aaa, bbb, ccc, ddd, eee, X) + swap(bb, bbb) + LROUND160N3(aa, bb, cc, dd, ee, X) + RROUND160N3(aaa, bbb, ccc, ddd, eee, X) + swap(cc, ccc) + LROUND160N4(aa, bb, cc, dd, ee, X) + RROUND160N4(aaa, bbb, ccc, ddd, eee, X) + swap(dd, ddd) + LROUND160N5(aa, bb, cc, dd, ee, X) + RROUND160N5(aaa, bbb, ccc, ddd, eee, X) + swap(ee, eee) + + # combine results + state[0] = state[0] + aa + state[1] = state[1] + bb + state[2] = state[2] + cc + state[3] = state[3] + dd + state[4] = state[4] + ee + state[5] = state[5] + aaa + state[6] = state[6] + bbb + state[7] = state[7] + ccc + state[8] = state[8] + ddd + state[9] = state[9] + eee + +template sizeDigest*(ctx: RipemdContext): uint = + (ctx.bits div 8) + +template sizeBlock*(ctx: RipemdContext): uint = + (64) + +template sizeDigest*(r: typedesc[ripemd]): int = + when r is ripemd128: + (16) + elif r is ripemd160: + (20) + elif r is ripemd256: + (32) + elif r is ripemd320: + (40) + +template sizeBlock*(r: typedesc[ripemd]): int = + (64) + +proc init*(ctx: var RipemdContext) = + ctx.count[0] = 0 + ctx.count[1] = 0 + + zeroMem(addr ctx.buffer[0], sizeof(byte) * 64) + + when ctx.bits == 128: + ctx.state[0] = 0x67452301'u32 + ctx.state[1] = 0xEFCDAB89'u32 + ctx.state[2] = 0x98BADCFE'u32 + ctx.state[3] = 0x10325476'u32 + elif ctx.bits == 160: + ctx.state[0] = 0x67452301'u32 + ctx.state[1] = 0xEFCDAB89'u32 + ctx.state[2] = 0x98BADCFE'u32 + ctx.state[3] = 0x10325476'u32 + ctx.state[4] = 0xC3D2E1F0'u32 + elif ctx.bits == 256: + ctx.state[0] = 0x67452301'u32 + ctx.state[1] = 0xEFCDAB89'u32 + ctx.state[2] = 0x98BADCFE'u32 + ctx.state[3] = 0x10325476'u32 + ctx.state[4] = 0x76543210'u32 + ctx.state[5] = 0xFEDCBA98'u32 + ctx.state[6] = 0x89ABCDEF'u32 + ctx.state[7] = 0x01234567'u32 + elif ctx.bits == 320: + ctx.state[0] = 0x67452301'u32 + ctx.state[1] = 0xEFCDAB89'u32 + ctx.state[2] = 0x98BADCFE'u32 + ctx.state[3] = 0x10325476'u32 + ctx.state[4] = 0xC3D2E1F0'u32 + ctx.state[5] = 0x76543210'u32 + ctx.state[6] = 0xFEDCBA98'u32 + ctx.state[7] = 0x89ABCDEF'u32 + ctx.state[8] = 0x01234567'u32 + ctx.state[9] = 0x3C2D1E0F'u32 + +proc clear*(ctx: var RipemdContext) {.inline.} = + burnMem(ctx) + +proc update*(ctx: var RipemdContext, data: ptr byte, ulen: uint) = + var pos = 0'u + var length = ulen + + while length > 0'u: + let offset = cast[uint](ctx.count[0] and 0x3F) + let size = min(64'u - offset, length) + copyMem(addr(ctx.buffer[offset]), + cast[pointer](cast[uint](data) + pos), size) + pos = pos + size + length = length - size + ctx.count[0] += cast[uint32](size) + if ctx.count[0] < cast[uint32](size): + ctx.count[1] += 1'u32 + if (ctx.count[0] and 0x3F) == 0: + when ctx.bits == 128: + ripemd128Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 160: + ripemd160Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 256: + ripemd256Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 320: + ripemd320Transform(ctx.state, addr(ctx.buffer[0])) + +proc update*[T: bchar](ctx: var RipemdContext, data: openarray[T]) = + if len(data) == 0: + ctx.update(nil, 0) + else: + ctx.update(cast[ptr byte](unsafeAddr data[0]), cast[uint](len(data))) + +proc finalize(ctx: var RipemdContext) = + let size = (ctx.count[0] and 0x3F) + var buffer = addr(ctx.buffer[0]) + zeroMem(addr(ctx.buffer[size]), 0x40'u - size) + ctx.buffer[size] = 0x80 + if size > 55'u32: + when ctx.bits == 128: + ripemd128Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 160: + ripemd160Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 256: + ripemd256Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 320: + ripemd320Transform(ctx.state, addr(ctx.buffer[0])) + zeroMem(addr(ctx.buffer[0]), 0x40) + SET_DWORD(buffer, 14, (ctx.count[0]) shl 3) + SET_DWORD(buffer, 15, (ctx.count[0] shr 29) or (ctx.count[1] shl 3)) + when ctx.bits == 128: + ripemd128Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 160: + ripemd160Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 256: + ripemd256Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bits == 320: + ripemd320Transform(ctx.state, addr(ctx.buffer[0])) + +proc finish*(ctx: var RipemdContext, data: ptr byte, ulen: uint): uint = + result = 0 + finalize(ctx) + when ctx.bits == 128: + if ulen >= 16'u: + result = sizeDigest(ctx) + for i in 0..3: + SET_DWORD(data, i, BSWAP(ctx.state[i])) + elif ctx.bits == 160: + if ulen >= 20'u: + result = sizeDigest(ctx) + for i in 0..4: + SET_DWORD(data, i, BSWAP(ctx.state[i])) + elif ctx.bits == 256: + if ulen >= 32'u: + result = sizeDigest(ctx) + for i in 0..7: + SET_DWORD(data, i, BSWAP(ctx.state[i])) + elif ctx.bits == 320: + if ulen >= 40'u: + result = sizeDigest(ctx) + for i in 0..9: + SET_DWORD(data, i, BSWAP(ctx.state[i])) + +proc finish*(ctx: var RipemdContext): MDigest[ctx.bits] = + discard finish(ctx, cast[ptr byte](addr result.data[0]), + cast[uint](len(result.data))) + +proc finish*[T: bchar](ctx: var RipemdContext, data: var openarray[T]) = + assert(uint(len(data)) >= ctx.sizeDigest) + discard ctx.finish(cast[ptr byte](addr data[0]), cast[uint](len(data))) diff --git a/src/blobsets/priv/nimcrypto/sha2.nim b/src/blobsets/priv/nimcrypto/sha2.nim new file mode 100644 index 0000000..ec91bf0 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/sha2.nim @@ -0,0 +1,572 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements SHA2 (Secure Hash Algorithm 2) set of cryptographic +## hash functions designed by National Security Agency, version FIPS-180-4. +## [http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf] +## +## Tests made according to official test vectors +## [http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf]. + +import hash, utils + +{.deadCodeElim:on.} + +const + ## Compile with ``-d:smallcode`` to generate smaller code footprint + smallCode = defined(smallcode) + + K0 = [ + 0x428a2f98'u32, 0x71374491'u32, 0xb5c0fbcf'u32, 0xe9b5dba5'u32, + 0x3956c25b'u32, 0x59f111f1'u32, 0x923f82a4'u32, 0xab1c5ed5'u32, + 0xd807aa98'u32, 0x12835b01'u32, 0x243185be'u32, 0x550c7dc3'u32, + 0x72be5d74'u32, 0x80deb1fe'u32, 0x9bdc06a7'u32, 0xc19bf174'u32, + 0xe49b69c1'u32, 0xefbe4786'u32, 0x0fc19dc6'u32, 0x240ca1cc'u32, + 0x2de92c6f'u32, 0x4a7484aa'u32, 0x5cb0a9dc'u32, 0x76f988da'u32, + 0x983e5152'u32, 0xa831c66d'u32, 0xb00327c8'u32, 0xbf597fc7'u32, + 0xc6e00bf3'u32, 0xd5a79147'u32, 0x06ca6351'u32, 0x14292967'u32, + 0x27b70a85'u32, 0x2e1b2138'u32, 0x4d2c6dfc'u32, 0x53380d13'u32, + 0x650a7354'u32, 0x766a0abb'u32, 0x81c2c92e'u32, 0x92722c85'u32, + 0xa2bfe8a1'u32, 0xa81a664b'u32, 0xc24b8b70'u32, 0xc76c51a3'u32, + 0xd192e819'u32, 0xd6990624'u32, 0xf40e3585'u32, 0x106aa070'u32, + 0x19a4c116'u32, 0x1e376c08'u32, 0x2748774c'u32, 0x34b0bcb5'u32, + 0x391c0cb3'u32, 0x4ed8aa4a'u32, 0x5b9cca4f'u32, 0x682e6ff3'u32, + 0x748f82ee'u32, 0x78a5636f'u32, 0x84c87814'u32, 0x8cc70208'u32, + 0x90befffa'u32, 0xa4506ceb'u32, 0xbef9a3f7'u32, 0xc67178f2'u32 + ] + + K1 = [ + 0x428a2f98d728ae22'u64, 0x7137449123ef65cd'u64, 0xb5c0fbcfec4d3b2f'u64, + 0xe9b5dba58189dbbc'u64, 0x3956c25bf348b538'u64, 0x59f111f1b605d019'u64, + 0x923f82a4af194f9b'u64, 0xab1c5ed5da6d8118'u64, 0xd807aa98a3030242'u64, + 0x12835b0145706fbe'u64, 0x243185be4ee4b28c'u64, 0x550c7dc3d5ffb4e2'u64, + 0x72be5d74f27b896f'u64, 0x80deb1fe3b1696b1'u64, 0x9bdc06a725c71235'u64, + 0xc19bf174cf692694'u64, 0xe49b69c19ef14ad2'u64, 0xefbe4786384f25e3'u64, + 0x0fc19dc68b8cd5b5'u64, 0x240ca1cc77ac9c65'u64, 0x2de92c6f592b0275'u64, + 0x4a7484aa6ea6e483'u64, 0x5cb0a9dcbd41fbd4'u64, 0x76f988da831153b5'u64, + 0x983e5152ee66dfab'u64, 0xa831c66d2db43210'u64, 0xb00327c898fb213f'u64, + 0xbf597fc7beef0ee4'u64, 0xc6e00bf33da88fc2'u64, 0xd5a79147930aa725'u64, + 0x06ca6351e003826f'u64, 0x142929670a0e6e70'u64, 0x27b70a8546d22ffc'u64, + 0x2e1b21385c26c926'u64, 0x4d2c6dfc5ac42aed'u64, 0x53380d139d95b3df'u64, + 0x650a73548baf63de'u64, 0x766a0abb3c77b2a8'u64, 0x81c2c92e47edaee6'u64, + 0x92722c851482353b'u64, 0xa2bfe8a14cf10364'u64, 0xa81a664bbc423001'u64, + 0xc24b8b70d0f89791'u64, 0xc76c51a30654be30'u64, 0xd192e819d6ef5218'u64, + 0xd69906245565a910'u64, 0xf40e35855771202a'u64, 0x106aa07032bbd1b8'u64, + 0x19a4c116b8d2d0c8'u64, 0x1e376c085141ab53'u64, 0x2748774cdf8eeb99'u64, + 0x34b0bcb5e19b48a8'u64, 0x391c0cb3c5c95a63'u64, 0x4ed8aa4ae3418acb'u64, + 0x5b9cca4f7763e373'u64, 0x682e6ff3d6b2b8a3'u64, 0x748f82ee5defb2fc'u64, + 0x78a5636f43172f60'u64, 0x84c87814a1f0ab72'u64, 0x8cc702081a6439ec'u64, + 0x90befffa23631e28'u64, 0xa4506cebde82bde9'u64, 0xbef9a3f7b2c67915'u64, + 0xc67178f2e372532b'u64, 0xca273eceea26619c'u64, 0xd186b8c721c0c207'u64, + 0xeada7dd6cde0eb1e'u64, 0xf57d4f7fee6ed178'u64, 0x06f067aa72176fba'u64, + 0x0a637dc5a2c898a6'u64, 0x113f9804bef90dae'u64, 0x1b710b35131c471b'u64, + 0x28db77f523047d84'u64, 0x32caab7b40c72493'u64, 0x3c9ebe0a15c9bebc'u64, + 0x431d67c49c100d4c'u64, 0x4cc5d4becb3e42b6'u64, 0x597f299cfc657e2a'u64, + 0x5fcb6fab3ad6faec'u64, 0x6c44198c4a475817'u64 + ] + +template CH0(x, y, z): uint32 = + ((x) and (y)) xor (not(x) and (z)) +template MAJ0(x, y, z): uint32 = + ((x) and (y)) xor ((x) and (z)) xor ((y) and (z)) +template CH1(x, y, z): uint64 = + ((x) and (y)) xor (not(x) and (z)) +template MAJ1(x, y, z): uint64 = + ((x) and (y)) xor ((x) and (z)) xor ((y) and (z)) +template TAU0(x: uint32): uint32 = + (ROR(x, 2) xor ROR(x, 13) xor ROR(x, 22)) +template TAU1(x: uint32): uint32 = + (ROR(x, 6) xor ROR(x, 11) xor ROR(x, 25)) +template SIG0(x): uint32 = + ROR(x, 7) xor ROR(x, 18) xor (x shr 3) +template SIG1(x): uint32 = + ROR(x, 17) xor ROR(x, 19) xor (x shr 10) +template PHI0(x): uint64 = + ROR(x, 28) xor ROR(x, 34) xor ROR(x, 39) +template PHI1(x): uint64 = + ROR(x, 14) xor ROR(x, 18) xor ROR(x, 41) +template RHO0(x): uint64 = + ROR(x, 1) xor ROR(x, 8) xor (x shr 7) +template RHO1(x): uint64 = + ROR(x, 19) xor ROR(x, 61) xor (x shr 6) + +type + Sha2Context*[bits: static[int], + bsize: static[int], + T: uint32|uint64] = object + count: array[2, T] + state: array[8, T] + buffer: array[bsize, byte] + + sha224* = Sha2Context[224, 64, uint32] + sha256* = Sha2Context[256, 64, uint32] + sha384* = Sha2Context[384, 128, uint64] + sha512* = Sha2Context[512, 128, uint64] + sha512_224* = Sha2Context[224, 128, uint64] + sha512_256* = Sha2Context[256, 128, uint64] + sha2* = sha224 | sha256 | sha384 | sha512 | sha512_224 | sha512_256 + +template sizeDigest*(ctx: Sha2Context): uint = + (ctx.bits div 8) + +template sizeBlock*(ctx: Sha2Context): uint = + (ctx.bsize) + +template sizeDigest*(r: typedesc[sha2]): int = + when r is sha224 or r is sha512_224: + (28) + elif r is sha256 or r is sha512_256: + (32) + elif r is sha384: + (48) + elif r is sha512: + (64) + +template sizeBlock*(r: typedesc[sha2]): int = + when r is sha224 or r is sha256: + (64) + else: + (128) + +proc init*(ctx: var Sha2Context) = + ctx.count[0] = 0 + ctx.count[1] = 0 + when ctx.bits == 224 and ctx.bsize == 64: + ctx.state[0] = 0xC1059ED8'u32 + ctx.state[1] = 0x367CD507'u32 + ctx.state[2] = 0x3070DD17'u32 + ctx.state[3] = 0xF70E5939'u32 + ctx.state[4] = 0xFFC00B31'u32 + ctx.state[5] = 0x68581511'u32 + ctx.state[6] = 0x64F98FA7'u32 + ctx.state[7] = 0xBEFA4FA4'u32 + elif ctx.bits == 256 and ctx.bsize == 64: + ctx.state[0] = 0x6A09E667'u32 + ctx.state[1] = 0xBB67AE85'u32 + ctx.state[2] = 0x3C6EF372'u32 + ctx.state[3] = 0xA54FF53A'u32 + ctx.state[4] = 0x510E527F'u32 + ctx.state[5] = 0x9B05688C'u32 + ctx.state[6] = 0x1F83D9AB'u32 + ctx.state[7] = 0x5BE0CD19'u32 + elif ctx.bits == 384 and ctx.bsize == 128: + ctx.state[0] = 0xCBBB9D5DC1059ED8'u64 + ctx.state[1] = 0x629A292A367CD507'u64 + ctx.state[2] = 0x9159015A3070DD17'u64 + ctx.state[3] = 0x152FECD8F70E5939'u64 + ctx.state[4] = 0x67332667FFC00B31'u64 + ctx.state[5] = 0x8EB44A8768581511'u64 + ctx.state[6] = 0xDB0C2E0D64F98FA7'u64 + ctx.state[7] = 0x47B5481DBEFA4FA4'u64 + elif ctx.bits == 512 and ctx.bsize == 128: + ctx.state[0] = 0x6A09E667F3BCC908'u64 + ctx.state[1] = 0xBB67AE8584CAA73B'u64 + ctx.state[2] = 0x3C6EF372FE94F82B'u64 + ctx.state[3] = 0xA54FF53A5F1D36F1'u64 + ctx.state[4] = 0x510E527FADE682D1'u64 + ctx.state[5] = 0x9B05688C2B3E6C1F'u64 + ctx.state[6] = 0x1F83D9ABFB41BD6B'u64 + ctx.state[7] = 0x5BE0CD19137E2179'u64 + elif ctx.bits == 224 and ctx.bsize == 128: + ctx.state[0] = 0x8C3D37C819544DA2'u64 + ctx.state[1] = 0x73E1996689DCD4D6'u64 + ctx.state[2] = 0x1DFAB7AE32FF9C82'u64 + ctx.state[3] = 0x679DD514582F9FCF'u64 + ctx.state[4] = 0x0F6D2B697BD44DA8'u64 + ctx.state[5] = 0x77E36F7304C48942'u64 + ctx.state[6] = 0x3F9D85A86A1D36C8'u64 + ctx.state[7] = 0x1112E6AD91D692A1'u64 + elif ctx.bits == 256 and ctx.bsize == 128: + ctx.state[0] = 0x22312194FC2BF72C'u64 + ctx.state[1] = 0x9F555FA3C84C64C2'u64 + ctx.state[2] = 0x2393B86B6F53B151'u64 + ctx.state[3] = 0x963877195940EABD'u64 + ctx.state[4] = 0x96283EE2A88EFFE3'u64 + ctx.state[5] = 0xBE5E1E2553863992'u64 + ctx.state[6] = 0x2B0199FC2C85B8AA'u64 + ctx.state[7] = 0x0EB72DDC81C52CA2'u64 + +proc clear*(ctx: var Sha2Context) {.inline.} = + burnMem(ctx) + +when not smallCode: + template ROUND256(a, b, c, d, e, f, g, h, z) = + t0 = h + TAU1(e) + CH0(e, f, g) + K0[z] + W[z] + t1 = TAU0(a) + MAJ0(a, b, c) + d = d + t0 + h = t0 + t1 + + template ROUND512(a, b, c, d, e, f, g, h, z) = + t0 = h + PHI1(e) + CH1(e, f, g) + K1[z] + W[z] + t1 = PHI0(a) + MAJ1(a, b, c) + d = d + t0 + h = t0 + t1 + +proc sha256Transform(state: var array[8, uint32], data: ptr byte) = + var t0, t1: uint32 + var W: array[64, uint32] + + var i = 0 + while i < 16: + W[i] = LSWAP(GET_DWORD(data, i)) + inc(i) + while i < 64: + W[i] = SIG1(W[i - 2]) + W[i - 7] + SIG0(W[i - 15]) + W[i - 16] + inc(i) + + var s0 = state[0] + var s1 = state[1] + var s2 = state[2] + var s3 = state[3] + var s4 = state[4] + var s5 = state[5] + var s6 = state[6] + var s7 = state[7] + + when smallCode: + i = 0 + while i < 64: + t0 = s7 + TAU1(s4) + CH0(s4, s5, s6) + K0[i] + W[i] + t1 = TAU0(s0) + MAJ0(s0, s1, s2) + s7 = s6 + s6 = s5 + s5 = s4 + s4 = s3 + t0 + s3 = s2 + s2 = s1 + s1 = s0 + s0 = t0 + t1 + inc(i) + else: + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 0) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 1) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 2) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 3) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 4) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 5) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 6) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 7) + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 8) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 9) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 10) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 11) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 12) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 13) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 14) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 15) + + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 16) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 17) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 18) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 19) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 20) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 21) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 22) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 23) + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 24) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 25) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 26) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 27) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 28) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 29) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 30) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 31) + + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 32) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 33) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 34) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 35) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 36) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 37) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 38) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 39) + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 40) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 41) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 42) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 43) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 44) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 45) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 46) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 47) + + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 48) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 49) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 50) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 51) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 52) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 53) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 54) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 55) + ROUND256(s0, s1, s2, s3, s4, s5, s6, s7, 56) + ROUND256(s7, s0, s1, s2, s3, s4, s5, s6, 57) + ROUND256(s6, s7, s0, s1, s2, s3, s4, s5, 58) + ROUND256(s5, s6, s7, s0, s1, s2, s3, s4, 59) + ROUND256(s4, s5, s6, s7, s0, s1, s2, s3, 60) + ROUND256(s3, s4, s5, s6, s7, s0, s1, s2, 61) + ROUND256(s2, s3, s4, s5, s6, s7, s0, s1, 62) + ROUND256(s1, s2, s3, s4, s5, s6, s7, s0, 63) + + state[0] += s0 + state[1] += s1 + state[2] += s2 + state[3] += s3 + state[4] += s4 + state[5] += s5 + state[6] += s6 + state[7] += s7 + +proc sha512Transform(state: var array[8, uint64], data: ptr byte) = + var t0, t1: uint64 + var W: array[80, uint64] + + var i = 0 + while i < 16: + W[i] = LSWAP(GET_QWORD(data, i)) + inc(i) + while i < 80: + W[i] = RHO1(W[i - 2]) + W[i - 7] + RHO0(W[i - 15]) + W[i - 16] + inc(i) + + var s0 = state[0] + var s1 = state[1] + var s2 = state[2] + var s3 = state[3] + var s4 = state[4] + var s5 = state[5] + var s6 = state[6] + var s7 = state[7] + + when smallCode: + i = 0 + while i < 80: + t0 = s7 + PHI1(s4) + CH1(s4, s5, s6) + K1[i] + W[i] + t1 = PHI0(s0) + MAJ1(s0, s1, s2) + s7 = s6 + s6 = s5 + s5 = s4 + s4 = s3 + t0 + s3 = s2 + s2 = s1 + s1 = s0 + s0 = t0 + t1 + inc(i) + else: + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 0) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 1) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 2) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 3) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 4) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 5) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 6) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 7) + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 8) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 9) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 10) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 11) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 12) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 13) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 14) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 15) + + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 16) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 17) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 18) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 19) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 20) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 21) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 22) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 23) + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 24) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 25) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 26) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 27) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 28) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 29) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 30) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 31) + + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 32) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 33) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 34) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 35) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 36) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 37) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 38) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 39) + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 40) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 41) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 42) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 43) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 44) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 45) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 46) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 47) + + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 48) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 49) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 50) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 51) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 52) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 53) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 54) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 55) + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 56) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 57) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 58) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 59) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 60) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 61) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 62) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 63) + + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 64) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 65) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 66) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 67) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 68) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 69) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 70) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 71) + ROUND512(s0, s1, s2, s3, s4, s5, s6, s7, 72) + ROUND512(s7, s0, s1, s2, s3, s4, s5, s6, 73) + ROUND512(s6, s7, s0, s1, s2, s3, s4, s5, 74) + ROUND512(s5, s6, s7, s0, s1, s2, s3, s4, 75) + ROUND512(s4, s5, s6, s7, s0, s1, s2, s3, 76) + ROUND512(s3, s4, s5, s6, s7, s0, s1, s2, 77) + ROUND512(s2, s3, s4, s5, s6, s7, s0, s1, 78) + ROUND512(s1, s2, s3, s4, s5, s6, s7, s0, 79) + + state[0] += s0 + state[1] += s1 + state[2] += s2 + state[3] += s3 + state[4] += s4 + state[5] += s5 + state[6] += s6 + state[7] += s7 + +proc update*(ctx: var Sha2Context, data: ptr byte, inlen: uint) = + var pos = 0'u + var length = inlen + + when ctx.bsize == 64: + while length > 0'u: + let offset = cast[uint](ctx.count[0] and 0x3F) + let size = min(64'u - offset, length) + copyMem(addr(ctx.buffer[offset]), + cast[pointer](cast[uint](data) + pos), size) + pos = pos + size + length = length - size + ctx.count[0] += cast[uint32](size) + if ctx.count[0] < cast[uint32](size): + ctx.count[1] += 1'u32 + if (ctx.count[0] and 0x3F) == 0: + sha256Transform(ctx.state, addr(ctx.buffer[0])) + elif ctx.bsize == 128: + while length > 0'u: + let offset = cast[uint](ctx.count[0] and 0x7F) + let size = min(128'u - offset, length) + copyMem(addr(ctx.buffer[offset]), + cast[pointer](cast[uint](data) + pos), size) + pos = pos + size + length = length - size + ctx.count[0] += cast[uint64](size) + if ctx.count[0] < cast[uint64](size): + ctx.count[1] += 1'u64 + if (ctx.count[0] and 0x7F) == 0: + sha512Transform(ctx.state, addr(ctx.buffer[0])) + +proc update*[T: bchar](ctx: var Sha2Context, data: openarray[T]) = + if len(data) == 0: + ctx.update(nil, 0) + else: + ctx.update(cast[ptr byte](unsafeAddr data[0]), cast[uint](len(data))) + +proc finalize256(ctx: var Sha2Context) = + var buffer = addr(ctx.buffer[0]) + var j = int(ctx.count[0] and 0x3F) + ctx.buffer[j] = 0x80 + inc(j) + while j != 56: + if j == 64: + sha256Transform(ctx.state, buffer) + j = 0 + ctx.buffer[j] = 0x00 + inc(j) + ctx.count[1] = (ctx.count[1] shl 3) + (ctx.count[0] shr 29) + ctx.count[0] = ctx.count[0] shl 3 + SET_DWORD(buffer, 14, LSWAP(ctx.count[1])) + SET_DWORD(buffer, 15, LSWAP(ctx.count[0])) + sha256Transform(ctx.state, buffer) + +proc finalize512(ctx: var Sha2Context) = + var buffer = addr(ctx.buffer[0]) + var j = int(ctx.count[0] and 0x7F) + ctx.buffer[j] = 0x80 + inc(j) + while j != 112: + if j == 128: + sha512Transform(ctx.state, buffer) + j = 0 + ctx.buffer[j] = 0x00 + inc(j) + ctx.count[1] = (ctx.count[1] shl 3) + (ctx.count[0] shr 29) + ctx.count[0] = ctx.count[0] shl 3 + SET_QWORD(buffer, 14, LSWAP(ctx.count[1])) + SET_QWORD(buffer, 15, LSWAP(ctx.count[0])) + sha512Transform(ctx.state, buffer) + +proc finish*(ctx: var Sha2Context, pBytes: ptr byte, nBytes: uint): uint = + result = 0 + when ctx.bits == 224 and ctx.bsize == 64: + finalize256(ctx) + if nBytes >= 28'u: + result = sizeDigest(ctx) + for i in 0..6: + SET_DWORD(pBytes, i, LSWAP(ctx.state[i])) + elif ctx.bits == 256 and ctx.bsize == 64: + finalize256(ctx) + if nBytes >= 32'u: + result = sizeDigest(ctx) + for i in 0..7: + SET_DWORD(pBytes, i, LSWAP(ctx.state[i])) + elif ctx.bits == 384 and ctx.bsize == 128: + finalize512(ctx) + if nBytes >= 48'u: + result = sizeDigest(ctx) + for i in 0..5: + SET_QWORD(pBytes, i, LSWAP(ctx.state[i])) + elif ctx.bits == 512 and ctx.bsize == 128: + finalize512(ctx) + if nBytes >= 64'u: + result = sizeDigest(ctx) + for i in 0..7: + SET_QWORD(pBytes, i, LSWAP(ctx.state[i])) + elif ctx.bits == 256 and ctx.bsize == 128: + finalize512(ctx) + if nBytes >= 32'u: + result = sizeDigest(ctx) + for i in 0..3: + SET_QWORD(pBytes, i, LSWAP(ctx.state[i])) + elif ctx.bits == 224 and ctx.bsize == 128: + finalize512(ctx) + if nBytes >= 28'u: + result = sizeDigest(ctx) + SET_QWORD(pBytes, 0, LSWAP(ctx.state[0])) + SET_QWORD(pBytes, 1, LSWAP(ctx.state[1])) + SET_QWORD(pBytes, 2, LSWAP(ctx.state[2])) + SET_DWORD(pBytes, 6, cast[uint32](LSWAP(ctx.state[3]))) + +proc finish*(ctx: var Sha2Context): MDigest[ctx.bits] = + discard finish(ctx, cast[ptr byte](addr result.data[0]), + cast[uint](len(result.data))) + +proc finish*[T: bchar](ctx: var Sha2Context, data: var openarray[T]) = + assert(cast[uint](len(data)) >= ctx.sizeDigest) + discard ctx.finish(cast[ptr byte](addr data[0]), cast[uint](len(data))) diff --git a/src/blobsets/priv/nimcrypto/sysrand.nim b/src/blobsets/priv/nimcrypto/sysrand.nim new file mode 100644 index 0000000..9925e5c --- /dev/null +++ b/src/blobsets/priv/nimcrypto/sysrand.nim @@ -0,0 +1,289 @@ +# +# +# NimCrypto +# (c) Copyright 2018 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements interface to operation system's random number +## generator. +## +## ``Windows`` using BCryptGenRandom (if available), +## CryptGenRandom(PROV_INTEL_SEC) (if available), RtlGenRandom. +## +## RtlGenRandom (available from Windows XP) +## BCryptGenRandom (available from Windows Vista SP1) +## CryptGenRandom(PROV_INTEL_SEC) (only when Intel SandyBridge +## CPU is available). +## +## ``Linux`` using genrandom (if available), `/dev/urandom`. +## +## ``OpenBSD`` using getentropy. +## +## ``NetBSD``, ``FreeBSD``, ``MacOS``, ``Solaris`` using `/dev/urandom`. + +{.deadCodeElim:on.} + +when defined(posix): + import os, posix + + proc urandomRead(pbytes: pointer, nbytes: int): int = + result = -1 + var st: Stat + let fd = posix.open("/dev/urandom", posix.O_RDONLY) + if fd != -1: + if posix.fstat(fd, st) != -1 and S_ISCHR(st.st_mode): + result = 0 + while result < nbytes: + var p = cast[pointer](cast[uint]((pbytes)) + uint(result)) + var res = posix.read(fd, p, nbytes - result) + if res > 0: + result += res + elif res == 0: + break + else: + if osLastError().int32 != EINTR: + result = -1 + break + discard posix.close(fd) + +when defined(openbsd): + import posix, os + + proc getentropy(pBytes: pointer, nBytes: int): cint + {.importc: "getentropy", header: "".} + + proc randomBytes*(pbytes: pointer, nbytes: int): int = + var p: pointer + while result < nbytes: + p = cast[pointer](cast[uint](pbytes) + uint(result)) + let res = getentropy(p, nbytes - result) + if res > 0: + result += res + elif res == 0: + break + else: + if osLastError().int32 != EINTR: + result = -1 + break + + if result == -1: + result = urandomRead(pbytes, nbytes) + elif result < nbytes: + p = cast[pointer](cast[uint](pbytes) + uint(result)) + let res = urandomRead(p, nbytes - result) + if res != -1: + result += res + +elif defined(linux): + import posix, os + when defined(i386): + const SYS_getrandom = 355 + elif defined(powerpc64) or defined(powerpc64el) or defined(powerpc): + const SYS_getrandom = 359 + elif defined(arm64): + const SYS_getrandom = 278 + elif defined(arm): + const SYS_getrandom = 384 + elif defined(amd64): + const SYS_getrandom = 318 + elif defined(mips): + when sizeof(int) == 8: + const SYS_getrandom = 4000 + 313 + else: + const SYS_getrandom = 4000 + 353 + else: + const SYS_getrandom = 0 + const + GRND_NONBLOCK = 1 + + type + SystemRng = ref object of RootRef + getRandomPresent: bool + + proc syscall(number: clong): clong {.importc: "syscall", + header: """#include + #include """, varargs, discardable.} + + var gSystemRng {.threadvar.}: SystemRng ## System thread global RNG + + proc newSystemRNG(): SystemRng = + result = SystemRng() + + if SYS_getrandom != 0: + var data: int + result.getRandomPresent = true + let res = syscall(SYS_getrandom, addr data, 1, GRND_NONBLOCK) + if res == -1: + let err = osLastError().int32 + if err == ENOSYS or err == EPERM: + result.getRandomPresent = false + + proc getSystemRNG(): SystemRng = + if gSystemRng.isNil: gSystemRng = newSystemRng() + result = gSystemRng + + proc randomBytes*(pbytes: pointer, nbytes: int): int = + var p: pointer + let srng = getSystemRNG() + if srng.getRandomPresent: + while result < nbytes: + p = cast[pointer](cast[uint](pbytes) + uint(result)) + let res = syscall(SYS_getrandom, pBytes, nBytes - result, 0) + if res > 0: + result += res + elif res == 0: + break + else: + if osLastError().int32 != EINTR: + result = -1 + break + + if result == -1: + result = urandomRead(pbytes, nbytes) + elif result < nbytes: + p = cast[pointer](cast[uint](pbytes) + uint(result)) + let res = urandomRead(p, nbytes - result) + if res != -1: + result += res + else: + result = urandomRead(pbytes, nbytes) + +elif defined(windows): + import os, winlean, dynlib + + const + VER_GREATER_EQUAL = 3'u8 + VER_MINORVERSION = 0x0000001 + VER_MAJORVERSION = 0x0000002 + VER_SERVICEPACKMINOR = 0x0000010 + VER_SERVICEPACKMAJOR = 0x0000020 + PROV_INTEL_SEC = 22 + INTEL_DEF_PROV = "Intel Hardware Cryptographic Service Provider" + CRYPT_VERIFYCONTEXT = 0xF0000000'i32 + CRYPT_SILENT = 0x00000040'i32 + BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002 + type + OSVERSIONINFOEXW {.final, pure.} = object + dwOSVersionInfoSize: DWORD + dwMajorVersion: DWORD + dwMinorVersion: DWORD + dwBuildNumber: DWORD + dwPlatformId: DWORD + szCSDVersion: array[128, Utf16Char] + wServicePackMajor: uint16 + wServicePackMinor: uint16 + wSuiteMask: uint16 + wProductType: byte + wReserved: byte + + HCRYPTPROV = uint + + BCGRMPROC = proc(hAlgorithm: pointer, pBuffer: pointer, cBuffer: ULONG, + dwFlags: ULONG): LONG {.stdcall, gcsafe.} + QPCPROC = proc(hProcess: Handle, cycleTime: var uint64): WINBOOL {. + stdcall, gcsafe.} + QUITPROC = proc(itime: var uint64) {.stdcall, gcsafe.} + QIPCPROC = proc(bufferLength: var uint32, idleTime: ptr uint64): WINBOOL {. + stdcall, gcsafe.} + + SystemRng = ref object of RootRef + bCryptGenRandom: BCGRMPROC + queryProcessCycleTime: QPCPROC + queryUnbiasedInterruptTime: QUITPROC + queryIdleProcessorCycleTime: QIPCPROC + coresCount: uint32 + hIntel: HCRYPTPROV + + var gSystemRng {.threadvar.}: SystemRng ## System thread global RNG + + proc verifyVersionInfo(lpVerInfo: ptr OSVERSIONINFOEXW, dwTypeMask: DWORD, + dwlConditionMask: uint64): WINBOOL + {.importc: "VerifyVersionInfoW", stdcall, dynlib: "kernel32.dll".} + proc verSetConditionMask(conditionMask: uint64, dwTypeMask: DWORD, + condition: byte): uint64 + {.importc: "VerSetConditionMask", stdcall, dynlib: "kernel32.dll".} + proc cryptAcquireContext(phProv: ptr HCRYPTPROV, pszContainer: WideCString, + pszProvider: WideCString, dwProvType: DWORD, + dwFlags: DWORD): WINBOOL + {.importc: "CryptAcquireContextW", stdcall, dynlib: "advapi32.dll".} + proc cryptReleaseContext(phProv: HCRYPTPROV, dwFlags: DWORD): WINBOOL + {.importc: "CryptReleaseContext", stdcall, dynlib: "advapi32.dll".} + proc cryptGenRandom(phProv: HCRYPTPROV, dwLen: DWORD, + pBuffer: pointer): WINBOOL + {.importc: "CryptGenRandom", stdcall, dynlib: "advapi32.dll".} + proc rtlGenRandom(bufptr: pointer, buflen: ULONG): WINBOOL + {.importc: "SystemFunction036", stdcall, dynlib: "advapi32.dll".} + + proc isEqualOrHigher(major: int, minor: int, servicePack: int): bool = + var mask = 0'u64 + var ov = OSVERSIONINFOEXW() + ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW).DWORD + ov.dwMajorVersion = major.DWORD + ov.dwMinorVersion = minor.DWORD + ov.wServicePackMajor = servicePack.uint16 + ov.wServicePackMinor = 0 + var typeMask = (VER_MAJORVERSION or VER_MINORVERSION or + VER_SERVICEPACKMAJOR or VER_SERVICEPACKMINOR).DWORD + mask = verSetConditionMask(mask, VER_MAJORVERSION, VER_GREATER_EQUAL) + mask = verSetConditionMask(mask, VER_MINORVERSION, VER_GREATER_EQUAL) + mask = verSetConditionMask(mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL) + mask = verSetConditionMask(mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL) + return (verifyVersionInfo(addr ov, typeMask, mask) == 1) + + proc newSystemRNG(): SystemRng = + result = SystemRng() + if isEqualOrHigher(6, 0, 0): + if isEqualOrHigher(6, 0, 1): + let lib = loadLib("bcrypt.dll") + if lib != nil: + var lProc = cast[BCGRMPROC](symAddr(lib, "BCryptGenRandom")) + if not isNil(lProc): + result.bCryptGenRandom = lProc + + var hp: HCRYPTPROV = 0 + let intelDef = newWideCString(INTEL_DEF_PROV) + let res1 = cryptAcquireContext(addr hp, nil, intelDef, PROV_INTEL_SEC, + CRYPT_VERIFYCONTEXT or CRYPT_SILENT).bool + if res1: + result.hIntel = hp + + proc getSystemRNG(): SystemRng = + if gSystemRng.isNil: gSystemRng = newSystemRng() + result = gSystemRng + + proc randomBytes*(pbytes: pointer, nbytes: int): int = + let srng = getSystemRNG() + result = -1 + if not isNil(srng.bCryptGenRandom): + if srng.bCryptGenRandom(nil, pbytes, nbytes.ULONG, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0: + result = nbytes + + if srng.hIntel != 0 and result == -1: + if cryptGenRandom(srng.hIntel, nbytes.DWORD, pbytes) != 0: + result = nbytes + + if result == -1: + if rtlGenRandom(pBytes, nbytes.ULONG) != 0: + result = nbytes + + proc randomClose*() = + let srng = getSystemRNG() + if srng.hIntel != 0: + if cryptReleaseContext(srng.hIntel, 0) == 0: + raiseOsError(osLastError()) +else: + import posix, os + + proc randomBytes*(pbytes: pointer, nbytes: int): int = + result = urandomRead(pbytes, nbytes) + +proc randomBytes*[T](bytes: var openarray[T]): int = + assert(len(bytes) > 0) + let length = len(bytes) * sizeof(T) + result = randomBytes(addr bytes[0], length) + if result != -1: + result = result div sizeof(T) diff --git a/src/blobsets/priv/nimcrypto/twofish.nim b/src/blobsets/priv/nimcrypto/twofish.nim new file mode 100644 index 0000000..858a997 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/twofish.nim @@ -0,0 +1,449 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module implements Twofish crypto algorithm by Bruce Schneier. +## +## Code based on `Optimized C` created by Drew Csillag +## [https://www.schneier.com/code/twofish-cpy.zip]. +## +## Tests made according to official test vectors +## [https://www.schneier.com/code/ecb_ival.txt]. + +import utils + +{.deadCodeElim:on.} + +const + RS_MOD = 0x14D + RHO = 0x01010101 + + RS = [ + [0x01'u8, 0xA4'u8, 0x55'u8, 0x87'u8, 0x5A'u8, 0x58'u8, 0xDB'u8, 0x9E'u8], + [0xA4'u8, 0x56'u8, 0x82'u8, 0xF3'u8, 0x1E'u8, 0xC6'u8, 0x68'u8, 0xE5'u8], + [0x02'u8, 0xA1'u8, 0xFC'u8, 0xC1'u8, 0x47'u8, 0xAE'u8, 0x3D'u8, 0x19'u8], + [0xA4'u8, 0x55'u8, 0x87'u8, 0x5A'u8, 0x58'u8, 0xDB'u8, 0x9E'u8, 0x03'u8] + ] + + Q0 = [ + 0xA9'u8, 0x67'u8, 0xB3'u8, 0xE8'u8, 0x04'u8, 0xFD'u8, 0xA3'u8, 0x76'u8, + 0x9A'u8, 0x92'u8, 0x80'u8, 0x78'u8, 0xE4'u8, 0xDD'u8, 0xD1'u8, 0x38'u8, + 0x0D'u8, 0xC6'u8, 0x35'u8, 0x98'u8, 0x18'u8, 0xF7'u8, 0xEC'u8, 0x6C'u8, + 0x43'u8, 0x75'u8, 0x37'u8, 0x26'u8, 0xFA'u8, 0x13'u8, 0x94'u8, 0x48'u8, + 0xF2'u8, 0xD0'u8, 0x8B'u8, 0x30'u8, 0x84'u8, 0x54'u8, 0xDF'u8, 0x23'u8, + 0x19'u8, 0x5B'u8, 0x3D'u8, 0x59'u8, 0xF3'u8, 0xAE'u8, 0xA2'u8, 0x82'u8, + 0x63'u8, 0x01'u8, 0x83'u8, 0x2E'u8, 0xD9'u8, 0x51'u8, 0x9B'u8, 0x7C'u8, + 0xA6'u8, 0xEB'u8, 0xA5'u8, 0xBE'u8, 0x16'u8, 0x0C'u8, 0xE3'u8, 0x61'u8, + 0xC0'u8, 0x8C'u8, 0x3A'u8, 0xF5'u8, 0x73'u8, 0x2C'u8, 0x25'u8, 0x0B'u8, + 0xBB'u8, 0x4E'u8, 0x89'u8, 0x6B'u8, 0x53'u8, 0x6A'u8, 0xB4'u8, 0xF1'u8, + 0xE1'u8, 0xE6'u8, 0xBD'u8, 0x45'u8, 0xE2'u8, 0xF4'u8, 0xB6'u8, 0x66'u8, + 0xCC'u8, 0x95'u8, 0x03'u8, 0x56'u8, 0xD4'u8, 0x1C'u8, 0x1E'u8, 0xD7'u8, + 0xFB'u8, 0xC3'u8, 0x8E'u8, 0xB5'u8, 0xE9'u8, 0xCF'u8, 0xBF'u8, 0xBA'u8, + 0xEA'u8, 0x77'u8, 0x39'u8, 0xAF'u8, 0x33'u8, 0xC9'u8, 0x62'u8, 0x71'u8, + 0x81'u8, 0x79'u8, 0x09'u8, 0xAD'u8, 0x24'u8, 0xCD'u8, 0xF9'u8, 0xD8'u8, + 0xE5'u8, 0xC5'u8, 0xB9'u8, 0x4D'u8, 0x44'u8, 0x08'u8, 0x86'u8, 0xE7'u8, + 0xA1'u8, 0x1D'u8, 0xAA'u8, 0xED'u8, 0x06'u8, 0x70'u8, 0xB2'u8, 0xD2'u8, + 0x41'u8, 0x7B'u8, 0xA0'u8, 0x11'u8, 0x31'u8, 0xC2'u8, 0x27'u8, 0x90'u8, + 0x20'u8, 0xF6'u8, 0x60'u8, 0xFF'u8, 0x96'u8, 0x5C'u8, 0xB1'u8, 0xAB'u8, + 0x9E'u8, 0x9C'u8, 0x52'u8, 0x1B'u8, 0x5F'u8, 0x93'u8, 0x0A'u8, 0xEF'u8, + 0x91'u8, 0x85'u8, 0x49'u8, 0xEE'u8, 0x2D'u8, 0x4F'u8, 0x8F'u8, 0x3B'u8, + 0x47'u8, 0x87'u8, 0x6D'u8, 0x46'u8, 0xD6'u8, 0x3E'u8, 0x69'u8, 0x64'u8, + 0x2A'u8, 0xCE'u8, 0xCB'u8, 0x2F'u8, 0xFC'u8, 0x97'u8, 0x05'u8, 0x7A'u8, + 0xAC'u8, 0x7F'u8, 0xD5'u8, 0x1A'u8, 0x4B'u8, 0x0E'u8, 0xA7'u8, 0x5A'u8, + 0x28'u8, 0x14'u8, 0x3F'u8, 0x29'u8, 0x88'u8, 0x3C'u8, 0x4C'u8, 0x02'u8, + 0xB8'u8, 0xDA'u8, 0xB0'u8, 0x17'u8, 0x55'u8, 0x1F'u8, 0x8A'u8, 0x7D'u8, + 0x57'u8, 0xC7'u8, 0x8D'u8, 0x74'u8, 0xB7'u8, 0xC4'u8, 0x9F'u8, 0x72'u8, + 0x7E'u8, 0x15'u8, 0x22'u8, 0x12'u8, 0x58'u8, 0x07'u8, 0x99'u8, 0x34'u8, + 0x6E'u8, 0x50'u8, 0xDE'u8, 0x68'u8, 0x65'u8, 0xBC'u8, 0xDB'u8, 0xF8'u8, + 0xC8'u8, 0xA8'u8, 0x2B'u8, 0x40'u8, 0xDC'u8, 0xFE'u8, 0x32'u8, 0xA4'u8, + 0xCA'u8, 0x10'u8, 0x21'u8, 0xF0'u8, 0xD3'u8, 0x5D'u8, 0x0F'u8, 0x00'u8, + 0x6F'u8, 0x9D'u8, 0x36'u8, 0x42'u8, 0x4A'u8, 0x5E'u8, 0xC1'u8, 0xE0'u8 + ] + + Q1 = [ + 0x75'u8, 0xF3'u8, 0xC6'u8, 0xF4'u8, 0xDB'u8, 0x7B'u8, 0xFB'u8, 0xC8'u8, + 0x4A'u8, 0xD3'u8, 0xE6'u8, 0x6B'u8, 0x45'u8, 0x7D'u8, 0xE8'u8, 0x4B'u8, + 0xD6'u8, 0x32'u8, 0xD8'u8, 0xFD'u8, 0x37'u8, 0x71'u8, 0xF1'u8, 0xE1'u8, + 0x30'u8, 0x0F'u8, 0xF8'u8, 0x1B'u8, 0x87'u8, 0xFA'u8, 0x06'u8, 0x3F'u8, + 0x5E'u8, 0xBA'u8, 0xAE'u8, 0x5B'u8, 0x8A'u8, 0x00'u8, 0xBC'u8, 0x9D'u8, + 0x6D'u8, 0xC1'u8, 0xB1'u8, 0x0E'u8, 0x80'u8, 0x5D'u8, 0xD2'u8, 0xD5'u8, + 0xA0'u8, 0x84'u8, 0x07'u8, 0x14'u8, 0xB5'u8, 0x90'u8, 0x2C'u8, 0xA3'u8, + 0xB2'u8, 0x73'u8, 0x4C'u8, 0x54'u8, 0x92'u8, 0x74'u8, 0x36'u8, 0x51'u8, + 0x38'u8, 0xB0'u8, 0xBD'u8, 0x5A'u8, 0xFC'u8, 0x60'u8, 0x62'u8, 0x96'u8, + 0x6C'u8, 0x42'u8, 0xF7'u8, 0x10'u8, 0x7C'u8, 0x28'u8, 0x27'u8, 0x8C'u8, + 0x13'u8, 0x95'u8, 0x9C'u8, 0xC7'u8, 0x24'u8, 0x46'u8, 0x3B'u8, 0x70'u8, + 0xCA'u8, 0xE3'u8, 0x85'u8, 0xCB'u8, 0x11'u8, 0xD0'u8, 0x93'u8, 0xB8'u8, + 0xA6'u8, 0x83'u8, 0x20'u8, 0xFF'u8, 0x9F'u8, 0x77'u8, 0xC3'u8, 0xCC'u8, + 0x03'u8, 0x6F'u8, 0x08'u8, 0xBF'u8, 0x40'u8, 0xE7'u8, 0x2B'u8, 0xE2'u8, + 0x79'u8, 0x0C'u8, 0xAA'u8, 0x82'u8, 0x41'u8, 0x3A'u8, 0xEA'u8, 0xB9'u8, + 0xE4'u8, 0x9A'u8, 0xA4'u8, 0x97'u8, 0x7E'u8, 0xDA'u8, 0x7A'u8, 0x17'u8, + 0x66'u8, 0x94'u8, 0xA1'u8, 0x1D'u8, 0x3D'u8, 0xF0'u8, 0xDE'u8, 0xB3'u8, + 0x0B'u8, 0x72'u8, 0xA7'u8, 0x1C'u8, 0xEF'u8, 0xD1'u8, 0x53'u8, 0x3E'u8, + 0x8F'u8, 0x33'u8, 0x26'u8, 0x5F'u8, 0xEC'u8, 0x76'u8, 0x2A'u8, 0x49'u8, + 0x81'u8, 0x88'u8, 0xEE'u8, 0x21'u8, 0xC4'u8, 0x1A'u8, 0xEB'u8, 0xD9'u8, + 0xC5'u8, 0x39'u8, 0x99'u8, 0xCD'u8, 0xAD'u8, 0x31'u8, 0x8B'u8, 0x01'u8, + 0x18'u8, 0x23'u8, 0xDD'u8, 0x1F'u8, 0x4E'u8, 0x2D'u8, 0xF9'u8, 0x48'u8, + 0x4F'u8, 0xF2'u8, 0x65'u8, 0x8E'u8, 0x78'u8, 0x5C'u8, 0x58'u8, 0x19'u8, + 0x8D'u8, 0xE5'u8, 0x98'u8, 0x57'u8, 0x67'u8, 0x7F'u8, 0x05'u8, 0x64'u8, + 0xAF'u8, 0x63'u8, 0xB6'u8, 0xFE'u8, 0xF5'u8, 0xB7'u8, 0x3C'u8, 0xA5'u8, + 0xCE'u8, 0xE9'u8, 0x68'u8, 0x44'u8, 0xE0'u8, 0x4D'u8, 0x43'u8, 0x69'u8, + 0x29'u8, 0x2E'u8, 0xAC'u8, 0x15'u8, 0x59'u8, 0xA8'u8, 0x0A'u8, 0x9E'u8, + 0x6E'u8, 0x47'u8, 0xDF'u8, 0x34'u8, 0x35'u8, 0x6A'u8, 0xCF'u8, 0xDC'u8, + 0x22'u8, 0xC9'u8, 0xC0'u8, 0x9B'u8, 0x89'u8, 0xD4'u8, 0xED'u8, 0xAB'u8, + 0x12'u8, 0xA2'u8, 0x0D'u8, 0x52'u8, 0xBB'u8, 0x02'u8, 0x2F'u8, 0xA9'u8, + 0xD7'u8, 0x61'u8, 0x1E'u8, 0xB4'u8, 0x50'u8, 0x04'u8, 0xF6'u8, 0xC2'u8, + 0x16'u8, 0x25'u8, 0x86'u8, 0x56'u8, 0x55'u8, 0x09'u8, 0xBE'u8, 0x91'u8 + ] + + mult5B = [ + 0x00'u8, 0x5B'u8, 0xB6'u8, 0xED'u8, 0x05'u8, 0x5E'u8, 0xB3'u8, 0xE8'u8, + 0x0A'u8, 0x51'u8, 0xBC'u8, 0xE7'u8, 0x0F'u8, 0x54'u8, 0xB9'u8, 0xE2'u8, + 0x14'u8, 0x4F'u8, 0xA2'u8, 0xF9'u8, 0x11'u8, 0x4A'u8, 0xA7'u8, 0xFC'u8, + 0x1E'u8, 0x45'u8, 0xA8'u8, 0xF3'u8, 0x1B'u8, 0x40'u8, 0xAD'u8, 0xF6'u8, + 0x28'u8, 0x73'u8, 0x9E'u8, 0xC5'u8, 0x2D'u8, 0x76'u8, 0x9B'u8, 0xC0'u8, + 0x22'u8, 0x79'u8, 0x94'u8, 0xCF'u8, 0x27'u8, 0x7C'u8, 0x91'u8, 0xCA'u8, + 0x3C'u8, 0x67'u8, 0x8A'u8, 0xD1'u8, 0x39'u8, 0x62'u8, 0x8F'u8, 0xD4'u8, + 0x36'u8, 0x6D'u8, 0x80'u8, 0xDB'u8, 0x33'u8, 0x68'u8, 0x85'u8, 0xDE'u8, + 0x50'u8, 0x0B'u8, 0xE6'u8, 0xBD'u8, 0x55'u8, 0x0E'u8, 0xE3'u8, 0xB8'u8, + 0x5A'u8, 0x01'u8, 0xEC'u8, 0xB7'u8, 0x5F'u8, 0x04'u8, 0xE9'u8, 0xB2'u8, + 0x44'u8, 0x1F'u8, 0xF2'u8, 0xA9'u8, 0x41'u8, 0x1A'u8, 0xF7'u8, 0xAC'u8, + 0x4E'u8, 0x15'u8, 0xF8'u8, 0xA3'u8, 0x4B'u8, 0x10'u8, 0xFD'u8, 0xA6'u8, + 0x78'u8, 0x23'u8, 0xCE'u8, 0x95'u8, 0x7D'u8, 0x26'u8, 0xCB'u8, 0x90'u8, + 0x72'u8, 0x29'u8, 0xC4'u8, 0x9F'u8, 0x77'u8, 0x2C'u8, 0xC1'u8, 0x9A'u8, + 0x6C'u8, 0x37'u8, 0xDA'u8, 0x81'u8, 0x69'u8, 0x32'u8, 0xDF'u8, 0x84'u8, + 0x66'u8, 0x3D'u8, 0xD0'u8, 0x8B'u8, 0x63'u8, 0x38'u8, 0xD5'u8, 0x8E'u8, + 0xA0'u8, 0xFB'u8, 0x16'u8, 0x4D'u8, 0xA5'u8, 0xFE'u8, 0x13'u8, 0x48'u8, + 0xAA'u8, 0xF1'u8, 0x1C'u8, 0x47'u8, 0xAF'u8, 0xF4'u8, 0x19'u8, 0x42'u8, + 0xB4'u8, 0xEF'u8, 0x02'u8, 0x59'u8, 0xB1'u8, 0xEA'u8, 0x07'u8, 0x5C'u8, + 0xBE'u8, 0xE5'u8, 0x08'u8, 0x53'u8, 0xBB'u8, 0xE0'u8, 0x0D'u8, 0x56'u8, + 0x88'u8, 0xD3'u8, 0x3E'u8, 0x65'u8, 0x8D'u8, 0xD6'u8, 0x3B'u8, 0x60'u8, + 0x82'u8, 0xD9'u8, 0x34'u8, 0x6F'u8, 0x87'u8, 0xDC'u8, 0x31'u8, 0x6A'u8, + 0x9C'u8, 0xC7'u8, 0x2A'u8, 0x71'u8, 0x99'u8, 0xC2'u8, 0x2F'u8, 0x74'u8, + 0x96'u8, 0xCD'u8, 0x20'u8, 0x7B'u8, 0x93'u8, 0xC8'u8, 0x25'u8, 0x7E'u8, + 0xF0'u8, 0xAB'u8, 0x46'u8, 0x1D'u8, 0xF5'u8, 0xAE'u8, 0x43'u8, 0x18'u8, + 0xFA'u8, 0xA1'u8, 0x4C'u8, 0x17'u8, 0xFF'u8, 0xA4'u8, 0x49'u8, 0x12'u8, + 0xE4'u8, 0xBF'u8, 0x52'u8, 0x09'u8, 0xE1'u8, 0xBA'u8, 0x57'u8, 0x0C'u8, + 0xEE'u8, 0xB5'u8, 0x58'u8, 0x03'u8, 0xEB'u8, 0xB0'u8, 0x5D'u8, 0x06'u8, + 0xD8'u8, 0x83'u8, 0x6E'u8, 0x35'u8, 0xDD'u8, 0x86'u8, 0x6B'u8, 0x30'u8, + 0xD2'u8, 0x89'u8, 0x64'u8, 0x3F'u8, 0xD7'u8, 0x8C'u8, 0x61'u8, 0x3A'u8, + 0xCC'u8, 0x97'u8, 0x7A'u8, 0x21'u8, 0xC9'u8, 0x92'u8, 0x7F'u8, 0x24'u8, + 0xC6'u8, 0x9D'u8, 0x70'u8, 0x2B'u8, 0xC3'u8, 0x98'u8, 0x75'u8, 0x2E'u8 + ] + + multEF = [ + 0x00'u8, 0xEF'u8, 0xB7'u8, 0x58'u8, 0x07'u8, 0xE8'u8, 0xB0'u8, 0x5F'u8, + 0x0E'u8, 0xE1'u8, 0xB9'u8, 0x56'u8, 0x09'u8, 0xE6'u8, 0xBE'u8, 0x51'u8, + 0x1C'u8, 0xF3'u8, 0xAB'u8, 0x44'u8, 0x1B'u8, 0xF4'u8, 0xAC'u8, 0x43'u8, + 0x12'u8, 0xFD'u8, 0xA5'u8, 0x4A'u8, 0x15'u8, 0xFA'u8, 0xA2'u8, 0x4D'u8, + 0x38'u8, 0xD7'u8, 0x8F'u8, 0x60'u8, 0x3F'u8, 0xD0'u8, 0x88'u8, 0x67'u8, + 0x36'u8, 0xD9'u8, 0x81'u8, 0x6E'u8, 0x31'u8, 0xDE'u8, 0x86'u8, 0x69'u8, + 0x24'u8, 0xCB'u8, 0x93'u8, 0x7C'u8, 0x23'u8, 0xCC'u8, 0x94'u8, 0x7B'u8, + 0x2A'u8, 0xC5'u8, 0x9D'u8, 0x72'u8, 0x2D'u8, 0xC2'u8, 0x9A'u8, 0x75'u8, + 0x70'u8, 0x9F'u8, 0xC7'u8, 0x28'u8, 0x77'u8, 0x98'u8, 0xC0'u8, 0x2F'u8, + 0x7E'u8, 0x91'u8, 0xC9'u8, 0x26'u8, 0x79'u8, 0x96'u8, 0xCE'u8, 0x21'u8, + 0x6C'u8, 0x83'u8, 0xDB'u8, 0x34'u8, 0x6B'u8, 0x84'u8, 0xDC'u8, 0x33'u8, + 0x62'u8, 0x8D'u8, 0xD5'u8, 0x3A'u8, 0x65'u8, 0x8A'u8, 0xD2'u8, 0x3D'u8, + 0x48'u8, 0xA7'u8, 0xFF'u8, 0x10'u8, 0x4F'u8, 0xA0'u8, 0xF8'u8, 0x17'u8, + 0x46'u8, 0xA9'u8, 0xF1'u8, 0x1E'u8, 0x41'u8, 0xAE'u8, 0xF6'u8, 0x19'u8, + 0x54'u8, 0xBB'u8, 0xE3'u8, 0x0C'u8, 0x53'u8, 0xBC'u8, 0xE4'u8, 0x0B'u8, + 0x5A'u8, 0xB5'u8, 0xED'u8, 0x02'u8, 0x5D'u8, 0xB2'u8, 0xEA'u8, 0x05'u8, + 0xE0'u8, 0x0F'u8, 0x57'u8, 0xB8'u8, 0xE7'u8, 0x08'u8, 0x50'u8, 0xBF'u8, + 0xEE'u8, 0x01'u8, 0x59'u8, 0xB6'u8, 0xE9'u8, 0x06'u8, 0x5E'u8, 0xB1'u8, + 0xFC'u8, 0x13'u8, 0x4B'u8, 0xA4'u8, 0xFB'u8, 0x14'u8, 0x4C'u8, 0xA3'u8, + 0xF2'u8, 0x1D'u8, 0x45'u8, 0xAA'u8, 0xF5'u8, 0x1A'u8, 0x42'u8, 0xAD'u8, + 0xD8'u8, 0x37'u8, 0x6F'u8, 0x80'u8, 0xDF'u8, 0x30'u8, 0x68'u8, 0x87'u8, + 0xD6'u8, 0x39'u8, 0x61'u8, 0x8E'u8, 0xD1'u8, 0x3E'u8, 0x66'u8, 0x89'u8, + 0xC4'u8, 0x2B'u8, 0x73'u8, 0x9C'u8, 0xC3'u8, 0x2C'u8, 0x74'u8, 0x9B'u8, + 0xCA'u8, 0x25'u8, 0x7D'u8, 0x92'u8, 0xCD'u8, 0x22'u8, 0x7A'u8, 0x95'u8, + 0x90'u8, 0x7F'u8, 0x27'u8, 0xC8'u8, 0x97'u8, 0x78'u8, 0x20'u8, 0xCF'u8, + 0x9E'u8, 0x71'u8, 0x29'u8, 0xC6'u8, 0x99'u8, 0x76'u8, 0x2E'u8, 0xC1'u8, + 0x8C'u8, 0x63'u8, 0x3B'u8, 0xD4'u8, 0x8B'u8, 0x64'u8, 0x3C'u8, 0xD3'u8, + 0x82'u8, 0x6D'u8, 0x35'u8, 0xDA'u8, 0x85'u8, 0x6A'u8, 0x32'u8, 0xDD'u8, + 0xA8'u8, 0x47'u8, 0x1F'u8, 0xF0'u8, 0xAF'u8, 0x40'u8, 0x18'u8, 0xF7'u8, + 0xA6'u8, 0x49'u8, 0x11'u8, 0xFE'u8, 0xA1'u8, 0x4E'u8, 0x16'u8, 0xF9'u8, + 0xB4'u8, 0x5B'u8, 0x03'u8, 0xEC'u8, 0xB3'u8, 0x5C'u8, 0x04'u8, 0xEB'u8, + 0xBA'u8, 0x55'u8, 0x0D'u8, 0xE2'u8, 0xBD'u8, 0x52'u8, 0x0A'u8, 0xE5'u8 + ] + +type + TwofishContext[bits: static[uint]] = object + S: array[4, array[256, uint32]] + K: array[40, uint32] + + twofish128* = TwofishContext[128] + twofish192* = TwofishContext[192] + twofish256* = TwofishContext[256] + twofish* = twofish128 | twofish192 | twofish256 + +template bn(x, n: uint32): byte = + cast[byte]((x shr (n * 8)) and 0xFF'u32) +template b0(x: uint32): byte = + cast[byte](x) +template b1(x: uint32): byte = + cast[byte](x shr 8) +template b2(x: uint32): byte = + cast[byte](x shr 16) +template b3(x: uint32): byte = + cast[byte](x shr 24) + +template BYTEARRAY_TO_U32(arr): uint32 = + ((cast[uint32](arr[0]) shl 24) xor (cast[uint32](arr[1]) shl 16) xor + (cast[uint32](arr[2]) shl 8) xor (cast[uint32](arr[3]))) +template BYTES_TO_U32(r0, r1, r2, r3): uint32 = + ((cast[uint32](r0) shl 24) xor (cast[uint32](r1) shl 16) xor + (cast[uint32](r2) shl 8) xor (cast[uint32](r3))) + +proc polyMult(a, b: uint32): uint32 = + result = 0'u32 + var va = a + var vb = b + while va != 0: + if (va and 1) != 0: result = result xor vb + vb = vb shl 1 + va = va shr 1 + +proc gfMod(t, modulus: uint32): uint32 = + var vmodulus = modulus shl 7 + result = t + for i in 0..<8: + var tt = result xor vmodulus + if tt < result: result = tt + vmodulus = vmodulus shr 1 + +template gfMult(a, b, modulus: uint32): uint32 = + gfMod(polyMult(a, b), modulus) + +proc rsMatrixMultiply(sd: array[8, byte]): uint32 = + var res = [0'u32, 0'u32, 0'u32, 0'u32] + for j in 0..<4: + var t = 0'u32 + for k in 0..<8: + t = t xor gfMult(RS[j][k], sd[k], RS_MOD) + res[3 - j] = t + result = BYTEARRAY_TO_U32(res) + +proc h(ax: uint32, al: array[4, uint32], k: uint32): uint32 = + var y0 = b0(ax) + var y1 = b1(ax) + var y2 = b2(ax) + var y3 = b3(ax) + + if k == 4: + y0 = Q1[y0] xor b0(al[3]) + y1 = Q0[y1] xor b1(al[3]) + y2 = Q0[y2] xor b2(al[3]) + y3 = Q1[y3] xor b3(al[3]) + if k == 4 or k == 3: + y0 = Q1[y0] xor b0(al[2]) + y1 = Q1[y1] xor b1(al[2]) + y2 = Q0[y2] xor b2(al[2]) + y3 = Q0[y3] xor b3(al[2]) + if k == 4 or k == 3 or k == 2: + y0 = Q1[Q0[Q0[y0] xor b0(al[1])] xor b0(al[0])] + y1 = Q0[Q0[Q1[y1] xor b1(al[1])] xor b1(al[0])] + y2 = Q1[Q1[Q0[y2] xor b2(al[1])] xor b2(al[0])] + y3 = Q0[Q1[Q1[y3] xor b3(al[1])] xor b3(al[0])] + + var z0 = multEF[y0] xor y1 xor multEF[y2] xor mult5B[y3] + var z1 = multEF[y0] xor mult5B[y1] xor y2 xor multEF[y3] + var z2 = mult5B[y0] xor multEF[y1] xor multEF[y2] xor y3 + var z3 = y0 xor multEF[y1] xor mult5B[y2] xor mult5B[y3] + + result = BYTES_TO_U32(z0, z1, z2, z3) + +proc fullKey(al: array[4, uint32], k: int32, + QF: var array[4, array[256, uint32]]) = + for i in 0..<256: + var y0 = byte(i) + var y1 = byte(i) + var y2 = byte(i) + var y3 = byte(i) + + if k == 4: + y0 = Q1[y0] xor b0(al[3]) + y1 = Q0[y1] xor b1(al[3]) + y2 = Q0[y2] xor b2(al[3]) + y3 = Q1[y3] xor b3(al[3]) + if k == 4 or k == 3: + y0 = Q1[y0] xor b0(al[2]) + y1 = Q1[y1] xor b1(al[2]) + y2 = Q0[y2] xor b2(al[2]) + y3 = Q0[y3] xor b3(al[2]) + if k == 4 or k == 3 or k == 2: + y0 = Q1[Q0[Q0[y0] xor b0(al[1])] xor b0(al[0])] + y1 = Q0[Q0[Q1[y1] xor b1(al[1])] xor b1(al[0])] + y2 = Q1[Q1[Q0[y2] xor b2(al[1])] xor b2(al[0])] + y3 = Q0[Q1[Q1[y3] xor b3(al[1])] xor b3(al[0])] + + QF[0][i] = ((multEF[y0].uint32 shl 24) or + (multEF[y0].uint32 shl 16) or + (mult5B[y0].uint32 shl 8) or + uint32(y0)) + QF[1][i] = ((y1.uint32 shl 24'u32) or + (mult5B[y1].uint32 shl 16) or + (multEF[y1].uint32 shl 8) or + (multEF[y1].uint32)) + QF[2][i] = ((multEF[y2].uint32 shl 24) or + (y2.uint32 shl 16) or + (multEF[y2].uint32 shl 8) or + (mult5B[y2].uint32)) + QF[3][i] = ((mult5B[y3].uint32 shl 24) or + (multEF[y3].uint32 shl 16) or + (y3.uint32 shl 8) or + mult5B[y3].uint32) + +# fully keyed h (aka g) function +template fkh(S, X): uint32 = + (S[0][b0(X)] xor S[1][b1(X)] xor S[2][b2(X)] xor S[3][b3(X)]) + +template ENC_ROUND(CTX, R0, R1, R2, R3, round) = + T0 = fkh(CTX.S, R0) + T1 = fkh(CTX.S, ROL(R1, 8)) + R2 = ROR(R2 xor (T1 + T0 + CTX.K[2 * round + 8]), 1) + R3 = ROL(R3, 1) xor (2'u32 * T1 + T0 + CTX.K[2 * round + 9]) + +template DEC_ROUND(CTX, R0, R1, R2, R3, round) = + T0 = fkh(CTX.S, R0) + T1 = fkh(CTX.S, ROL(R1, 8)) + R2 = ROL(R2, 1) xor (T0 + T1 + CTX.K[2 * round + 8]) + R3 = ROR(R3 xor (T0 + 2'u32 * T1 + CTX.K[2 * round + 9]), 1) + +proc twofishEncrypt(ctx: var TwofishContext, inp: ptr byte, oup: ptr byte) = + var T0, T1: uint32 + + var r3 = ctx.K[3] xor BSWAP(GET_DWORD(inp, 3)) + var r2 = ctx.K[2] xor BSWAP(GET_DWORD(inp, 2)) + var r1 = ctx.K[1] xor BSWAP(GET_DWORD(inp, 1)) + var r0 = ctx.K[0] xor BSWAP(GET_DWORD(inp, 0)) + + ENC_ROUND(ctx, r0, r1, r2, r3, 0) + ENC_ROUND(ctx, r2, r3, r0, r1, 1) + ENC_ROUND(ctx, r0, r1, r2, r3, 2) + ENC_ROUND(ctx, r2, r3, r0, r1, 3) + ENC_ROUND(ctx, r0, r1, r2, r3, 4) + ENC_ROUND(ctx, r2, r3, r0, r1, 5) + ENC_ROUND(ctx, r0, r1, r2, r3, 6) + ENC_ROUND(ctx, r2, r3, r0, r1, 7) + ENC_ROUND(ctx, r0, r1, r2, r3, 8) + ENC_ROUND(ctx, r2, r3, r0, r1, 9) + ENC_ROUND(ctx, r0, r1, r2, r3, 10) + ENC_ROUND(ctx, r2, r3, r0, r1, 11) + ENC_ROUND(ctx, r0, r1, r2, r3, 12) + ENC_ROUND(ctx, r2, r3, r0, r1, 13) + ENC_ROUND(ctx, r0, r1, r2, r3, 14) + ENC_ROUND(ctx, r2, r3, r0, r1, 15) + + SET_DWORD(oup, 3, BSWAP(r1 xor ctx.K[7])) + SET_DWORD(oup, 2, BSWAP(r0 xor ctx.K[6])) + SET_DWORD(oup, 1, BSWAP(r3 xor ctx.K[5])) + SET_DWORD(oup, 0, BSWAP(r2 xor ctx.K[4])) + +proc twofishDecrypt(ctx: var TwofishContext, inp: ptr byte, oup: ptr byte) = + var T0, T1: uint32 + + var r3 = ctx.K[7] xor BSWAP(GET_DWORD(inp, 3)) + var r2 = ctx.K[6] xor BSWAP(GET_DWORD(inp, 2)) + var r1 = ctx.K[5] xor BSWAP(GET_DWORD(inp, 1)) + var r0 = ctx.K[4] xor BSWAP(GET_DWORD(inp, 0)) + + DEC_ROUND(ctx, r0, r1, r2, r3, 15) + DEC_ROUND(ctx, r2, r3, r0, r1, 14) + DEC_ROUND(ctx, r0, r1, r2, r3, 13) + DEC_ROUND(ctx, r2, r3, r0, r1, 12) + DEC_ROUND(ctx, r0, r1, r2, r3, 11) + DEC_ROUND(ctx, r2, r3, r0, r1, 10) + DEC_ROUND(ctx, r0, r1, r2, r3, 9) + DEC_ROUND(ctx, r2, r3, r0, r1, 8) + DEC_ROUND(ctx, r0, r1, r2, r3, 7) + DEC_ROUND(ctx, r2, r3, r0, r1, 6) + DEC_ROUND(ctx, r0, r1, r2, r3, 5) + DEC_ROUND(ctx, r2, r3, r0, r1, 4) + DEC_ROUND(ctx, r0, r1, r2, r3, 3) + DEC_ROUND(ctx, r2, r3, r0, r1, 2) + DEC_ROUND(ctx, r0, r1, r2, r3, 1) + DEC_ROUND(ctx, r2, r3, r0, r1, 0) + + SET_DWORD(oup, 3, BSWAP(r1 xor ctx.K[3])) + SET_DWORD(oup, 2, BSWAP(r0 xor ctx.K[2])) + SET_DWORD(oup, 1, BSWAP(r3 xor ctx.K[1])) + SET_DWORD(oup, 0, BSWAP(r2 xor ctx.K[0])) + +proc initTwofishContext(ctx: var TwofishContext, N: int, key: ptr byte) = + var + A, B: uint32 + + var Mo = [0'u32, 0'u32, 0'u32, 0'u32] + var Me = [0'u32, 0'u32, 0'u32, 0'u32] + var S = [0'u32, 0'u32, 0'u32, 0'u32] + var vector = [0'u8, 0'u8, 0'u8, 0'u8, 0'u8, 0'u8, 0'u8, 0'u8] + let k = (N + 63) div 64 + + for i in 0..= ctx.sizeKey()) + initTwofishContext(ctx, ctx.bits, unsafeAddr key[0]) + +proc clear*(ctx: var TwofishContext) {.inline.} = + burnMem(ctx) + +proc encrypt*(ctx: var TwofishContext, inbytes: ptr byte, + outbytes: ptr byte) {.inline.} = + twofishEncrypt(ctx, inbytes, outbytes) + +proc decrypt*(ctx: var TwofishContext, inbytes: ptr byte, + outbytes: ptr byte) {.inline.} = + twofishDecrypt(ctx, inbytes, outbytes) + +proc encrypt*(ctx: var TwofishContext, input: openarray[byte], + output: var openarray[byte]) {.inline.} = + assert(len(input) == ctx.sizeBlock) + assert(len(input) <= len(output)) + twofishEncrypt(ctx, unsafeAddr input[0], addr output[0]) + +proc decrypt*(ctx: var TwofishContext, input: openarray[byte], + output: var openarray[byte]) {.inline.} = + assert(len(input) == ctx.sizeBlock) + assert(len(input) <= len(output)) + twofishDecrypt(ctx, unsafeAddr input[0], addr output[0]) diff --git a/src/blobsets/priv/nimcrypto/utils.nim b/src/blobsets/priv/nimcrypto/utils.nim new file mode 100644 index 0000000..eaa6405 --- /dev/null +++ b/src/blobsets/priv/nimcrypto/utils.nim @@ -0,0 +1,227 @@ +# +# +# NimCrypto +# (c) Copyright 2016 Eugene Kabanov +# +# See the file "LICENSE", included in this +# distribution, for details about the copyright. +# + +## This module provides utility functions common to all other submodules of nimcrypto. + +{.deadCodeElim:on.} + +proc ROL*[T: uint32|uint64](x: T, n: int): T {.inline.} = + when T is uint32: + result = (x shl T(n and 0x1F)) or (x shr T(8 * sizeof(T) - (n and 0x1F))) + else: + result = (x shl T(n and 0x3F)) or (x shr T(8 * sizeof(T) - (n and 0x3F))) + +proc ROR*[T: uint32|uint64](x: T, n: int): T {.inline.} = + when T is uint32: + result = (x shr T(n and 0x1F)) or (x shl T(8 * sizeof(T) - (n and 0x1F))) + else: + result = (x shr T(n and 0x3F)) or (x shl T(8 * sizeof(T) - (n and 0x3F))) + +template GETU32*(p, o): uint32 = + (cast[uint32](cast[ptr byte](cast[uint](p) + o)[]) shl 24) xor + (cast[uint32](cast[ptr byte](cast[uint](p) + (o + 1))[]) shl 16) xor + (cast[uint32](cast[ptr byte](cast[uint](p) + (o + 2))[]) shl 8) xor + (cast[uint32](cast[ptr byte](cast[uint](p) + (o + 3))[])) + +template GETU64*(p, o): uint64 = + (cast[uint64](cast[ptr byte](cast[uint](p) + o)[]) shl 56) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 1))[]) shl 48) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 2))[]) shl 40) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 3))[]) shl 32) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 4))[]) shl 24) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 5))[]) shl 16) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 6))[]) shl 8) xor + (cast[uint64](cast[ptr byte](cast[uint](p) + (o + 7))[])) + +template PUTU32*(p, o, v) = + cast[ptr byte](cast[uint](p) + o)[] = cast[byte](v shr 24) + cast[ptr byte](cast[uint](p) + o + 1)[] = cast[byte](v shr 16) + cast[ptr byte](cast[uint](p) + o + 2)[] = cast[byte](v shr 8) + cast[ptr byte](cast[uint](p) + o + 3)[] = cast[byte](v) + +template PUTU64*(p, o, v) = + cast[ptr byte](cast[uint](p) + o)[] = cast[byte](v shr 56) + cast[ptr byte](cast[uint](p) + o + 1)[] = cast[byte](v shr 48) + cast[ptr byte](cast[uint](p) + o + 2)[] = cast[byte](v shr 40) + cast[ptr byte](cast[uint](p) + o + 3)[] = cast[byte](v shr 32) + cast[ptr byte](cast[uint](p) + o + 4)[] = cast[byte](v shr 24) + cast[ptr byte](cast[uint](p) + o + 5)[] = cast[byte](v shr 16) + cast[ptr byte](cast[uint](p) + o + 6)[] = cast[byte](v shr 8) + cast[ptr byte](cast[uint](p) + o + 7)[] = cast[byte](v) + +when cpuEndian == bigEndian: + template BSWAP*[T: uint32|uint64](x: T): T = + when T is uint32: + ((ROR(x, 8) and 0xFF00FF00'u32) or (ROL(x, 8) and 0x00FF00FF'u32)) + else: + ((x shl 56) or + ((x shl 40) and 0xFF000000000000'u64) or + ((x shl 24) and 0xFF0000000000'u64) or + ((x shl 8) and 0xFF00000000'u64) or + ((x shr 8) and 0xFF000000'u64) or + ((x shr 24) and 0xFF0000'u64) or + ((x shr 40) and 0xFF00'u64) or + (x shr 56)) + template LSWAP*[T: uint32|uint64](x: T): T = + x + template EGETU32*(p, o): uint32 = + cast[ptr uint32]((cast[uint](p) + cast[uint](o)))[] + template EPUTU32*(p, o, v) = + cast[ptr uint32]((cast[uint](p) + cast[uint](o)))[] = v + template EGETU64*(p, o): uint64 = + cast[ptr uint64]((cast[uint](p) + cast[uint](o)))[] + template EPUTU64*(p, o, v) = + cast[ptr uint64]((cast[uint](p) + cast[uint](o)))[] = v +else: + template BSWAP*[T: uint32|uint64](x: T): T = + x + template LSWAP*[T: uint32|uint64](x: T): T = + when T is uint32: + ((ROR(x, 8) and 0xFF00FF00'u32) or (ROL(x, 8) and 0x00FF00FF'u32)) + else: + ((x shl 56) or + ((x shl 40) and 0xFF000000000000'u64) or + ((x shl 24) and 0xFF0000000000'u64) or + ((x shl 8) and 0xFF00000000'u64) or + ((x shr 8) and 0xFF000000'u64) or + ((x shr 24) and 0xFF0000'u64) or + ((x shr 40) and 0xFF00'u64) or + (x shr 56)) + template EGETU32*(p, o): uint32 = + GETU32(p, o) + template EPUTU32*(p, o, v) = + PUTU32(p, o, v) + template EGETU64*(p, o): uint64 = + GETU64(p, o) + template EPUTU64*(p, o, v) = + PUTU64(p, o, v) + +template GET_DWORD*(p: ptr byte, i: int): uint32 = + cast[ptr uint32](cast[uint](p) + cast[uint](sizeof(uint32) * i))[] + +template SET_DWORD*(p: ptr byte, i: int, v: uint32) = + cast[ptr uint32](cast[uint](p) + cast[uint](sizeof(uint32) * i))[] = v + +template GET_QWORD*(p: ptr byte, i: int): uint64 = + cast[ptr uint64](cast[uint](p) + cast[uint](sizeof(uint64) * i))[] + +template SET_QWORD*(p: ptr byte, i: int, v: uint64) = + cast[ptr uint64](cast[uint](p) + cast[uint](sizeof(uint64) * i))[] = v + +template GETU8*(p, o): byte = + cast[ptr byte](cast[uint](p) + cast[uint](o))[] + +template PUTU8*(p, o, v) = + cast[ptr byte](cast[uint](p) + cast[uint](o))[] = v + +proc hexToBytes*(a: string, result: var openarray[byte]) = + doAssert(len(a) == 2 * len(result)) + var i = 0 + var k = 0 + var r = 0 + if len(a) > 0: + while i < len(a): + let c = a[i] + if i != 0 and i %% 2 == 0: + result[k] = r.byte + r = 0 + inc(k) + else: + r = r shl 4 + case c + of 'a'..'f': + r = r or (10 + ord(c) - ord('a')) + of 'A'..'F': + r = r or (10 + ord(c) - ord('A')) + of '0'..'9': + r = r or (ord(c) - ord('0')) + else: + doAssert(false) + inc(i) + result[k] = r.byte + +proc fromHex*(a: string): seq[byte] = + doAssert(len(a) %% 2 == 0) + if len(a) == 0: + result = newSeq[byte]() + else: + result = newSeq[byte](len(a) div 2) + hexToBytes(a, result) + +proc hexChar*(c: byte, lowercase: bool = false): string = + var alpha: int + if lowercase: + alpha = ord('a') + else: + alpha = ord('A') + result = newString(2) + let t1 = ord(c) shr 4 + let t0 = ord(c) and 0x0F + case t1 + of 0..9: result[0] = chr(t1 + ord('0')) + else: result[0] = chr(t1 - 10 + alpha) + case t0: + of 0..9: result[1] = chr(t0 + ord('0')) + else: result[1] = chr(t0 - 10 + alpha) + +proc toHex*(a: openarray[byte], lowercase: bool = false): string = + result = "" + for i in a: + result = result & hexChar(i, lowercase) + +proc stripSpaces*(s: string): string = + result = "" + let allowed:set[char] = {'A'..'Z', 'a'..'z', '0'..'9'} + for i in s: + if i in allowed: + result &= i + +proc burnMem*(p: pointer, size: Natural) = + var sp {.volatile.} = cast[ptr byte](p) + var c = size + if not isNil(sp): + zeroMem(p, size) + while c > 0: + sp[] = 0 + sp = cast[ptr byte](cast[uint](sp) + 1) + dec(c) + +proc burnArray*[T](a: var openarray[T]) {.inline.} = + if len(a) > 0: + burnMem(addr a[0], len(a) * sizeof(T)) + +template burnMem*[T](a: var seq[T]) = + burnArray(a) + +template burnMem*[A, B](a: var array[A, B]) = + burnArray(a) + +proc burnMem*[T](a: var T) {.inline.} = + burnMem(addr a, sizeof(T)) + +proc isFullZero*(p: pointer, size: Natural): bool = + result = true + var counter = 0 + var sp {.volatile.} = cast[ptr byte](p) + var c = size + if not isNil(sp): + while c > 0: + if sp[] != 0'u8: + counter += 1 + sp = cast[ptr byte](cast[uint](sp) + 1) + dec(c) + result = (counter == 0) + +proc isFullZero*[T](a: openarray[T]): bool {.inline.} = + result = true + if len(a) > 0: + result = isFullZero(unsafeAddr a[0], len(a) * sizeof(T)) + +proc isFullZero*[T](a: T): bool {.inline.} = + result = isFullZero(unsafeAddr a, sizeof(T))