Use Tiger tree hashes

Switch from BLAKE2B-256 tree hashing to the Tiger tree hash scheme
used by the ADC protocol. Hashes are now 192-bit (96-bit security)
and the tree leaf nodes 1 KiB.
This commit is contained in:
Ehmry - 2019-06-17 08:22:54 +02:00
parent 1071e63d1c
commit b905b45525
28 changed files with 219 additions and 7331 deletions

View File

@ -1,12 +1,12 @@
# Package
version = "0.1.2"
version = "0.2.0"
author = "Emery Hemingway"
description = "Sets of named blobs"
license = "AGPLv3"
srcDir = "src"
requires "nim >= 0.18.0", "cbor >= 0.5.2", "siphash", "spryvm", "toxcore"
requires "nim >= 0.18.0", "base32", "cbor >= 0.5.2", "siphash", "tiger >= 0.2.1"
bin = @["blobset", "blobserver"]
bin = @["blobingest", "blobset", "blobserver"]
skipFiles = @["blobset.nim", "blobserver.nim"]

View File

@ -5,11 +5,18 @@ stdenv.mkDerivation {
src = ./.;
base32 = fetchFromGitHub {
owner = "ehmry";
repo = "base32.nim";
rev = "c557fd9e1d09d103f3781b6eba5fa22330579425";
sha256 = "081rlflad99f4krlsfgll6f5l09w3a2i4zgfwncxya5hn6jhfg32";
};
cbor = fetchFromGitHub {
owner = "ehmry";
repo = "nim-cbor";
rev = "v0.5.2";
sha256 = "0fh8vriad6nvjl3fxl2b62bk7y4z1hx90527a530nln5g1cj9z8f";
rev = "v0.6.0";
sha256 = "175h3vk0qccmzymlbqdwni645d7v5zz0fn6zdjsy1pd88kg5v66h";
};
siphash = fetchFromGitHub {
@ -19,13 +26,20 @@ stdenv.mkDerivation {
sha256 = "1z4xm3ckygw8pmn9b6axdk65ib1y5bgwa3v1dbxamvhjmyfr62w4";
};
tiger = fetchFromGitHub {
owner = "ehmry";
repo = "tiger";
rev = "v0.2";
sha256 = "0hn3ccmmfgkmiz5q2mvlyhgc22054i54m211ai2a9k9k37w7w2hz";
};
buildInputs = [ nim pcre ];
NIX_LDFLAGS = [ "-lpcre" ];
buildPhase = ''
HOME=$TMPDIR
nim c -p:$cbor/src -p:$siphash/src -d:release src/blobset.nim
nim c -p:$base32 -p:$cbor/src -p:$siphash/src -p:$tiger -d:release src/blobset.nim
'';
installPhase = "install -Dt $out/bin src/blobset";

View File

@ -6,19 +6,6 @@ import cbor
import ./blobsets, ./blobsets/filestores,
./blobsets/httpservers, ./blobsets/httpstores
when defined(tox):
import toxcore
# Basic Spry
when defined(spry):
import spryvm/spryvm
# Spry extra modules
import spryvm/sprycore, spryvm/spryextend, spryvm/sprymath, spryvm/spryos, spryvm/spryio,
spryvm/spryoo, spryvm/sprystring, spryvm/sprymodules, spryvm/spryreflect, spryvm/sprymemfile,
spryvm/spryblock,
./blobsets/spryblobs
import os, strutils
when defined(readLine):
import rdstdin, linenoise
@ -34,115 +21,6 @@ proc openStore(): BlobStore =
else:
newFileStore(url)
when defined(spry):
proc newSpry(store: BlobStore): Interpreter =
result = newInterpreter()
result.addCore()
result.addExtend()
result.addMath()
result.addOS()
result.addIO()
result.addOO()
result.addString()
result.addModules()
result.addReflect()
result.addMemfile()
result.addBlock()
result.addBlobSets(store)
discard result.evalRoot("""[loadFile: "blobs.sy"]""")
when defined(tox) and defined(spry):
type IngestTransfer = object
name: string
stream: IngestStream
size, pos: uint64
proc process(
t: var IngestTransfer; tox: Tox; friend: Friend; file: FileTransfer;
pos: uint64; data: pointer; size: int): bool =
## Process transfer data, return true if transfer is complete
if t.pos != pos:
cancel t.stream
tox.control(friend, file, TOX_FILE_CONTROL_CANCEL)
discard tox.send(friend, """stream is at position $# but you sent $#""" % [$t.pos, $pos])
result = true
else:
waitFor t.stream.ingest(data, size)
t.pos.inc size
if t.pos >= t.size:
let blobId, blobSize = waitFor t.stream.finish()
discard tox.send(friend, """$# $# $#""" % [t.name, $blobId, $blobSize])
result = true
type Transfer = uint64
proc `+`(friend: Friend; file: FileTransfer): Transfer =
(friend.Transfer shl 32) or file.Transfer
proc setupCallbacks(tox: Tox) =
tox.onSelfConnectionStatus do (status: TOX_CONNECTION):
echo "self status is ", status
tox.onFriendRequest do (key: PublicKey; msg: string):
echo "friend request from ", key, ", ", msg
discard tox.addFriendNoRequest(key)
block:
let
store = openStore()
spry = newSpry(store)
transfers = newTable[Transfer, IngestTransfer](16)
tox.onFriendMessage do (friend: Friend; msg: string; kind: TOX_MESSAGE_TYPE):
try:
if kind == TOX_MESSAGE_TYPE_NORMAL:
tox.typing(friend, true)
let res = spry.evalRoot("[" & msg & "]")
tox.typing(friend, false)
discard tox.send(friend, $res, TOX_MESSAGE_TYPE_ACTION)
except:
discard tox.send(friend, getCurrentExceptionMsg())
tox.onFileRecv do (friend: Friend; file: FileTransfer; kind: uint32; size: uint64; filename: string):
case kind
of (uint32)TOX_FILE_KIND_AVATAR:
tox.control(friend, file, TOX_FILE_CONTROL_CANCEL)
else:
if transfers.len > 16:
tox.control(friend, file, TOX_FILE_CONTROL_CANCEL)
discard tox.send(friend, "too many transfers are pending")
else:
let msg = """you are trying to send me "$#", type $#, size $#""" %
[filename, $kind, $size]
discard tox.send(friend, msg)
transfers[friend+file] = IngestTransfer(
name: filename,
stream: store.openIngestStream(size.BiggestInt),
size: size)
tox.control(friend, file, TOX_FILE_CONTROL_RESUME)
tox.onFileRecvChunk do (friend: Friend; file: FileTransfer; pos: uint64; data: pointer; size: int):
try:
if transfers[friend+file].process(tox, friend, file, pos, data, size):
transfers.del(friend+file)
except:
discard tox.send(friend, getCurrentExceptionMsg(), TOX_MESSAGE_TYPE_ACTION)
tox.name = "blobbot"
echo "/connect 127.0.0.1 ", tox.udpPort, " ", tox.dhtId
echo "/add ", tox.address
proc toxMain() {.async.} =
let tox = newTox do (o: Options):
o.ipv6Enabled = false
o.localDiscoveryEnabled = true
o.holePunchingEnabled = false
var saveData = ""
try: saveData = readFile "tox.save"
except: discard
if saveData != "":
o.saveData = saveData
o.saveDataType = TOX_SAVEDATA_TYPE_TOX_SAVE
writeFile "tox.save", tox.saveData
setupCallbacks(tox)
while not tox.isClosed:
iterate tox
await sleepAsync(tox.iterationInterval)
proc serverMain(): Future[void] =
let
store = newFileStore("/tmp/blobs")
@ -943,67 +821,6 @@ proc getLine(prompt: string): string =
stdout.write(prompt)
result = stdin.readline()
when defined(spry):
proc spryMain() =
let spry = newSpry(openStore())
var
lines, stashed, fileLines = newSeq[string]()
suspended: bool = true
echo "Welcome to interactive Spry!"
echo "An empty line will evaluate previous lines, so hit enter twice."
# We collect lines until an empty line is entered, easy way to enter
# multiline code.
while true:
var line: string
if suspended:
line = getLine(Prompt)
else:
if fileLines.len == 0:
quit 0
# Read a line, eh, would be nice with removeFirst or popFirst...
line = fileLines[0]
fileLines.delete(0)
# Logic for pausing
if line.strip() == "# pause":
var enter = getLine(" <enter = eval, s = suspend>")
if enter.strip() == "s":
stdout.write(" <suspended, c = continue>\n")
stashed = lines
lines = newSeq[string]()
suspended = true
continue
else:
stdout.write(line & "\n")
# Logic to start the script again
if suspended and line.strip() == "c":
lines = stashed
suspended = false
continue
# Finally time to eval
if line.strip().len() == 0:
let code = lines.join("\n")
lines = newSeq[string]()
try:
# Let the interpreter eval the code. We need to eval whatever we
# get (ispry acting as a func). The surrounding block is just because we only
# want to pass one Node.
var result = spry.evalRoot("[" & code & "]")
#discard spry.setBinding(newEvalWord("@"), result)
var output = $result
# Print any result
if output.isNil:
output = if suspended: "nil" else: ""
stdout.write(output & "\n")
except:
echo "Oops, sorry about that: " & getCurrentExceptionMsg() & "\n"
echo getStackTrace()
else:
lines.add(line)
when isMainModule:
var cmd = ""
for kind, key, val in getopt():
@ -1017,17 +834,6 @@ when isMainModule:
of "dump": dumpMain()
of "ingest": waitFor ingestMain()
of "server": waitFor serverMain()
of "spry":
when defined(spry):
spryMain()
else:
quit "not compiled with Spry interpreter"
of "check": waitFor checkMain()
of "replicate": waitFor replicateMain()
of "tox":
when defined(tox) and defined(spry):
#waitFor toxReplicateMain()
waitFor toxMain()
else:
quit "not compiled with Tox node"
else: quit("no such subcommand " & cmd)

View File

@ -1,5 +1,2 @@
# Disable this to use only primitive stdin
-d:readLine
--nilseqs:on
-d:spry
-d:tox

View File

@ -1,53 +1,41 @@
import std/asyncdispatch, std/asyncstreams
import std/hashes, std/streams, std/strutils, std/bitops, std/unicode, std/endians
import std/streams, std/strutils, std/random
import cbor, siphash
import ./blobsets/priv/hex
import base32, cbor, siphash, tiger
import ./blobsets/priv/hex, ./blobsets/priv/nimcrypto, ./blobsets/priv/nimcrypto/blake2
import std/asyncdispatch, std/asyncstreams
import std/hashes, std/streams, std/strutils, std/bitops, std/unicode, std/endians, std/random
const
digestLen* = 32
digestSize* = 24
## Length of a chunk digest.
cidSize* = digestLen
## Size of CID object in memory
blobLeafSize* = 1 shl 14
## Size of blob leaves.
blobLeafSizeMask* = not(not(0) shl 14)
blobHexLen* = 32 * 2
blobVisualLen* = 32 * 3
blobLeafSize* = 1 shl 10
## Size of blob hash leaves (THEX/ADC).
blobLeafSizeMask* = blobLeafSize - 1
blobHexLen* = digestSize * 2
blobBase32Len* = (digestSize * 5 div 3) - 1
blobVisualLen* = digestSize * 3
type
Blake2b256* = Blake2bContext[256]
BlobId* = MDigest[Blake2b256.bits]
BlobId* = TigerDigest
## Blob Identifier
SetId* = MDigest[Blake2b256.bits]
SetId* = TigerDigest
## Set Identifier
Cid* {.deprecated} = BlobId
func `$`*(bh: BlobId): string =
## Convert a blob hash to a visual representation.
const baseRune = 0x2800
result = newString(blobVisualLen)
var pos = 0
for b in bh.data.items:
let r = (Rune)baseRune or b.int
fastToUTF8Copy(r, result, pos, true)
func parseStringId[T](s: string): T =
case s.len
of blobHexLen:
hex.decode s, result.data
of blobBase32Len:
var tmp = base32.decode(s)
copyMem(result.data[0].addr, tmp[0].addr, digestSize)
of blobVisualLen:
var
pos: int
r: Rune
for b in result.data.mitems:
fastRuneAt(s, pos, r, true)
b = r.byte
b = byte(r.int and 0xff)
else:
raise newException(ValueError, "invalid blobset id encoding")
raise newException(ValueError, "invalid blobset id encoding of len " & $s.len)
func parseCborId[T](c: CborNode): T =
## Parse a CBOR node to binary.
@ -59,10 +47,6 @@ func toBlobId*(s: string): BlobId =
## Parse a visual blob hash to binary.
parseStringId[BlobId] s
func toBlobId(c: CborNode): BlobId =
## Parse a CBOR blob hash to binary.
parseCborId[BlobId] c
func toSetId*(s: string): SetId =
## Parse a visual set hash to binary.
parseStringId[SetId] s
@ -77,7 +61,7 @@ proc `==`*(x, y: BlobId): bool = x.data == y.data
proc `==`*(cbor: CborNode; cid: BlobId): bool =
## Compare a CBOR node with a BlobId.
if cbor.kind == cborBytes:
for i in 0..<digestLen:
for i in 0..<digestSize:
if cid.data[i] != cbor.bytes[i].uint8:
return false
result = true
@ -87,24 +71,34 @@ proc hash*(cid: BlobId): Hash =
var zeroKey: Key
result = cast[Hash](sipHash(cid.data, zeroKey))
proc toCbor*(cid: BlobId): CborNode = newCborBytes cid.data
proc toCbor*(id: BlobId): CborNode = newCborBytes id.data
## Generate a CBOR representation of a BlobId.
proc toBlobId*(cbor: CborNode): BlobId =
## Generate a CBOR representation of a BlobId.
assert(cbor.bytes.len == digestLen)
for i in 0..<digestLen:
assert(cbor.bytes.len == digestSize)
for i in 0..<digestSize:
result.data[i] = cbor.bytes[i].uint8
func `$`*(bh: BlobId): string =
## Convert a blob hash to a visual representation.
const baseRune = 0x2800
result = newString(blobVisualLen)
var pos = 0
for b in bh.data.items:
let r = (Rune)baseRune or b.int
fastToUTF8Copy(r, result, pos, true)
proc toHex*(id: BlobId|SetId): string = hex.encode(id.data)
## Return BlobId encoded in hexidecimal.
proc verify*(cid: BlobId; data: string): bool =
func toBase32*(bh: BlobId): string =
## Encode a blob hash into base32
base32.encode(cast[array[digestSize,char]](bh.data), pad=false)
proc verify*(id: BlobId; data: string): bool =
## Verify that a string of data corresponds to a BlobId.
var b: Blake2b256
init(b)
update(b, data)
finish(b) == cid
id == tiger(data)
func isNonZero*(bh: BlobId): bool =
## Test if a blob hash is not zeroed.
@ -208,7 +202,7 @@ proc openIngestStream*(s: BlobStore; size = 0.BiggestInt; kind = dataBlob): Inge
proc ingest*(store: BlobStore; buf: string): Future[BlobId] {.async.} =
let stream = store.openIngestStream(buf.len.BiggestInt, dataBlob)
await stream.ingest(buf[0].unsafeAddr, buf.len)
let (id, size) = await stream.finish()
let (id, _) = await stream.finish()
return id
type Key* = distinct uint64
@ -314,11 +308,15 @@ iterator dumpBlob*(store: BlobStore; id: BlobId): string =
proc loadSet(store: BlobStore; id: SetId; depth: int): Future[BlobSet] {.async.} =
assert(isNonZero id)
assert((not Key(0)) shr depth != Key(0), "loadSet trie is too deep")
var
let
stream = store.openBlobStream(id, kind=metaBlob)
buf = newString(blobLeafSize)
streamSize = stream.size
defer:
close stream
var buf = if streamSize == 0:
newString(4 shl 10)
else:
newString(stream.size)
let n = await stream.read(buf[0].addr, buf.len)
assert(n != 0, "read zero of set " & $id)
buf.setLen(n)
@ -360,7 +358,6 @@ proc randomApply*(store: BlobStore; trie: BlobSet; rng: var Rand;
f: proc(id: BlobId; size: BiggestInt)) =
## Apply to random leaf if the set is not empty.
var
retry = 0
trie = trie
i = rng.rand(max(1, countSetBits(trie.bitmap))-1)
while trie.bitmap != 0:
@ -433,27 +430,6 @@ func leafCount(bs: BlobSet): int =
else:
result.inc n.leafCount
#[
proc search*(store: BlobStore; trie: BlobSet; name: string): Future[BlobId] {.async.} =
let key = name.toKey
var
n = trie
k = key
level = 0
while k != Key(0) and n.masked(k):
let i = n.compactIndex(k)
if n.table[i].isCold:
n.table[i] = await store.load(n.table[i])
n = n.table[i]
if n.kind == leafNode:
if n.key == key:
return n.blob
break
k = k shr keyChunkBits
inc level
raise newException(KeyError, "key not in blob set")
]#
func apply(bs: BlobSet; cb: proc (leaf: BlobSet)) =
## Apply a callback to each set element.
for node in bs.table:
@ -581,45 +557,37 @@ func leafCount*(size: Natural): int = (size+blobLeafSize-1) div blobLeafSize
func compressTree*(leaves: var openArray[BlobId]) =
var
ctx: Blake2b256
nodeOffset = 0
nodeDepth = 0
ctx: TigerState
len = leaves.len
while len > 1:
nodeOffset = 0
inc nodeDepth
while 1 < len:
var pos, next: int
while pos < len:
ctx.init do (params: var Blake2bParams):
params.fanout = 2
params.depth = 255
params.leafLength = blobLeafSize
params.nodeOffset = nodeOffset
params.nodeDepth = nodeDepth
inc nodeOffset
ctx.update(leaves[pos].data)
inc pos
if pos < len:
ctx.update(leaves[pos].data)
inc pos
while pos+1 < len:
init ctx
ctx.update [1'u8]
ctx.update leaves[pos+0].data
ctx.update leaves[pos+1].data
pos.inc 2
leaves[next] = ctx.finish()
inc next
if pos < len:
leaves[next] = leaves[pos]
inc next
len = next
# TODO: BLAKE2 tree finalization flags
proc blobHash*(s: string): BlobId =
doAssert(s.len <= blobLeafSize)
func blobHash*(s: string): BlobId =
var
ctx: Blake2b256
leaves: array[1, BlobId]
ctx.init do (params: var Blake2bParams):
params.fanout = 2
params.depth = 255
params.leafLength = blobLeafSize
params.nodeOffset = 0
if s.len > 0:
ctx.update(unsafeAddr s[0], s.len)
leaves[0] = finish ctx
ctx: TigerState
leaves = newSeqOfCap[BlobId](leafCount s.len)
off: int
while true:
init ctx
ctx.update [0'u8]
let n = min(blobLeafSize, s.len - off)
if 0 < n:
ctx.update(unsafeAddr s[off], n)
off.inc n
leaves.add(finish ctx)
if off == s.len: break
compressTree(leaves)
leaves[0]
@ -651,12 +619,15 @@ proc commit*(store: BlobStore; bs: BlobSet): Future[BlobSet] {.async.} =
type
NullIngestStream = ref NullIngestStreamObj
NullIngestStreamObj = object of IngestStreamObj
ctx: Blake2b256
ctx: TigerState
leaves: seq[BlobId]
pos, nodeOffset: BiggestInt
pos: BiggestInt
proc nullBlobClose(s: BlobStream) = discard
proc nullBlobSize(s: BlobStream): BiggestInt =
discard
proc setPosNull(s: BlobStream; pos: BiggestInt) = discard
proc getPosNull(s: BlobStream): BiggestInt = discard
@ -667,13 +638,15 @@ proc nullBlobRead(s: BlobStream; buffer: pointer; len: Natural): Future[int] =
proc nullOpenBlobStream(s: BlobStore; id: BlobId; size: BiggestInt; kind: BlobKind): BlobStream =
BlobStream(
closeImpl: nullBlobClose,
sizeImpl: nullBlobSize,
setPosImpl: setPosNull,
getPosImpl: getPosNull,
readImpl: nullBlobRead)
proc nullFinish(s: IngestStream): Future[tuple[id: BlobId, size: BiggestInt]] =
var s = NullIngestStream(s)
s.leaves.add finish(s.ctx)
if s.pos == 0 or s.pos mod blobLeafSize != 0:
s.leaves.add finish(s.ctx)
compressTree(s.leaves)
var pair: tuple[id: BlobId, size: BiggestInt]
pair.id = s.leaves[0]
@ -681,34 +654,39 @@ proc nullFinish(s: IngestStream): Future[tuple[id: BlobId, size: BiggestInt]] =
result = newFuture[tuple[id: BlobId, size: BiggestInt]]()
complete result, pair
proc nullIngest(s: IngestStream; buf: pointer; len: Natural): Future[void] =
var
proc appendLeaf(s: NullIngestStream) =
s.leaves.add(finish s.ctx)
init s.ctx
s.ctx.update [0'u8]
proc nullIngest(s: IngestStream; data: pointer; size: Natural): Future[void] =
let
s = NullIngestStream(s)
off = 0
buf = cast[ptr array[blobLeafSize, byte]](buf)
while off < len:
var n = min(blobLeafSize, len-off)
let leafOff = int(s.pos and blobLeafSizeMask)
if leafOff == 0:
if s.pos > 0:
s.leaves.add finish(s.ctx)
s.ctx.init do (params: var Blake2bParams):
params.fanout = 2
params.depth = 255
params.leafLength = blobLeafSize
params.nodeOffset = s.nodeOffset
inc s.nodeOffset
else:
n = min(n, blobLeafSize-leafOff)
s.ctx.update(buf[off].addr, n)
off.inc n
s.pos.inc n
buf = cast[ptr UncheckedArray[byte]](data)
var dataOff: int
let leafOff = s.pos.int mod blobLeafSize
if leafOff != 0:
let leafFill = min(blobLeafSize - leafOff, size)
s.ctx.update(buf[0].addr, leafFill)
dataOff.inc leafFill
if leafFill < size:
appendLeaf s
while dataOff+blobLeafSize <= size:
s.ctx.update(buf[dataOff].addr, blobLeafSize)
dataOff.inc blobLeafSize
appendLeaf s
if dataOff != size:
s.ctx.update(buf[dataOff].addr, size - dataOff)
s.pos.inc size
result = newFuture[void]()
complete result
proc nullOpenIngestStream(s: BlobStore; size: BiggestInt; kind: BlobKind): IngestStream =
NullIngestStream(
let s = NullIngestStream(
finishImpl: nullFinish, ingestImpl: nullIngest, leaves: newSeq[BlobId]())
result = s
init s.ctx
s.ctx.update [0'u8]
proc newNullStore*(): BlobStore =
BlobStore(

View File

@ -1,9 +1,7 @@
import ../blobsets
import tiger
import std/asyncfile, std/asyncdispatch, std/os
import ./priv/nimcrypto/blake2
proc ingestFile*(store: BlobStore; path: string): Future[tuple[id: BlobId, size: BiggestInt]] {.async.} =
## Ingest a file and return blob metadata.
let
@ -13,7 +11,7 @@ proc ingestFile*(store: BlobStore; path: string): Future[tuple[id: BlobId, size:
close file
let stream = store.openIngestStream(fileSize, dataBlob)
if fileSize > 0:
var buf = newString(min(blobLeafSize, fileSize))
var buf = newString(min(8 shl 10, fileSize))
while true:
let n = await file.readBuffer(buf[0].addr, buf.len)
if n == 0: break
@ -28,7 +26,7 @@ type
FsIngestStream = ref FsIngestStreamObj
FsIngestStreamObj = object of IngestStreamObj
ctx: Blake2b256
ctx: TigerState
leaves: seq[BlobId]
path: string
file: AsyncFile
@ -43,6 +41,10 @@ proc fsBlobClose(s: BlobStream) =
var s = FsBlobStream(s)
close s.file
proc fsBlobSize(s: BlobStream): BiggestInt =
var s = FsBlobStream(s)
s.file.getFileSize.BiggestInt
proc setPosFs(s: BlobStream; pos: BiggestInt) =
var s = FsBlobStream(s)
s.file.setFilePos (int64)pos
@ -59,10 +61,11 @@ proc fsOpenBlobStream(s: BlobStore; id: BlobId; size: BiggestInt; kind: BlobKind
var fs = FileStore(s)
try:
let
path = fs.root / $kind / id.toHex
path = fs.root / $kind / id.toBase32
file = openAsync(path, fmRead)
result = FsBlobStream(
closeImpl: fsBlobClose,
sizeImpl: fsBlobSize,
setPosImpl: setPosFs,
getPosImpl: getPosFs,
readImpl: fsBlobRead,
@ -76,11 +79,12 @@ proc fsFinish(s: IngestStream): Future[tuple[id: BlobId, size: BiggestInt]] =
s = FsIngestStream(s)
pair: tuple[id: BlobId, size: BiggestInt]
close s.file
s.leaves.add finish(s.ctx)
if s.pos == 0 or s.pos mod blobLeafSize != 0:
s.leaves.add finish(s.ctx)
compressTree(s.leaves)
pair.id = s.leaves[0]
pair.size = s.pos
let finalPath = s.path.parentDir / pair.id.toHex
let finalPath = s.path.parentDir / pair.id.toBase32
if fileExists finalPath:
removeFile s.path
else:
@ -88,29 +92,31 @@ proc fsFinish(s: IngestStream): Future[tuple[id: BlobId, size: BiggestInt]] =
result = newFuture[tuple[id: BlobId, size: BiggestInt]]()
complete result, pair
proc fsIngest(s: IngestStream; buf: pointer; len: Natural) {.async.} =
var
proc appendLeaf(s: FsIngestStream) =
s.leaves.add(finish s.ctx)
init s.ctx
s.ctx.update [0'u8]
proc fsIngest(s: IngestStream; data: pointer; size: Natural): Future[void] =
let
s = FsIngestStream(s)
off = 0
buf = cast[ptr array[blobLeafSize, byte]](buf)
while off < len:
var n = min(blobLeafSize, len-off)
let leafOff = int(s.pos and blobLeafSizeMask)
if leafOff == 0:
if s.pos > 0:
s.leaves.add finish(s.ctx)
s.ctx.init do (params: var Blake2bParams):
params.fanout = 2
params.depth = 255
params.leafLength = blobLeafSize
params.nodeOffset = s.nodeOffset
inc s.nodeOffset
else:
n = min(n, blobLeafSize-leafOff)
s.ctx.update(buf[off].addr, n)
await s.file.writeBuffer(buf[off].addr, n)
off.inc n
s.pos.inc n
buf = cast[ptr UncheckedArray[byte]](data)
result = s.file.writeBuffer(data, size)
var dataOff: int
let leafOff = s.pos.int mod blobLeafSize
if leafOff != 0:
let leafFill = min(blobLeafSize - leafOff, size)
s.ctx.update(buf[0].addr, leafFill)
dataOff.inc leafFill
if leafFill < size:
appendLeaf s
while dataOff+blobLeafSize <= size:
s.ctx.update(buf[dataOff].addr, blobLeafSize)
dataOff.inc blobLeafSize
appendLeaf s
if dataOff != size:
s.ctx.update(buf[dataOff].addr, size - dataOff)
s.pos.inc size
proc fsOpenIngestStream(s: BlobStore; size: BiggestInt; kind: BlobKind): IngestStream =
var fs = FileStore(s)
@ -127,12 +133,14 @@ proc fsOpenIngestStream(s: BlobStore; size: BiggestInt; kind: BlobKind): IngestS
stream.leaves = newSeqOfCap[BlobId](leafCount size)
else:
stream.leaves = newSeq[BlobId]()
init stream.ctx
stream.ctx.update [0'u8]
stream
proc fsContains(s: BlobStore; id: BlobId; kind: BlobKind): Future[bool] =
var fs = FileStore(s)
result = newFuture[bool]("blobsets.filestores.fsContains")
let path = fs.root / $kind / id.toHex
let path = fs.root / $kind / id.toBase32
try:
close(openAsync(path, fmRead))
result.complete(true)

View File

@ -1,377 +0,0 @@
import strutils, streams, tables, cbor, os, math, asyncfile, asyncdispatch
import ../blobsets, ./stores
type EntryKey = enum
typeKey = 1,
dataKey = 2,
sizeKey = 3
type FsType* = enum
fsFileList = 0,
fsDirChunk = 1,
fsFileChunk = 2,
type FsKind* = enum
fileNode,
dirNode,
shallowDirChunk,
shallowFileList,
type
FileLink* = object
cid*: Cid
size*: int
FsNode* = ref object
cid: Cid
case kind*: FsKind
of fileNode:
links*: seq[FileLink]
of dirNode:
entries: OrderedTable[string, FsNode]
of shallowFileList, shallowDirChunk:
discard
size: BiggestInt
proc isRaw*(file: FsNode): bool =
(file.kind == fileNode) and (file.links.len == 0)
proc cid*(u: FsNode): Cid =
assert u.cid.isValid
u.cid
proc isFile*(u: FsNode): bool = u.kind in { fileNode, shallowFileList }
proc isDir*(u: FsNode): bool = u.kind in { dirNode, shallowDirChunk }
proc size*(u: FsNode): BiggestInt =
if u.kind == dirNode: u.entries.len.BiggestInt
else: u.size
proc newFsRoot*(): FsNode =
FsNode(
kind: dirNode,
entries: initOrderedTable[string, FsNode](8))
proc newUnixfsFile*(): FsNode =
FsNode(kind: fileNode)
proc newUnixfsDir*(cid: Cid): FsNode =
FsNode(cid: cid, kind: dirNode)
proc add*(root: var FsNode; name: string; node: FsNode) =
root.entries[name] = node
proc addDir*(root: var FsNode; name: string; cid: Cid) {.deprecated.} =
assert cid.isValid
root.add name, FsNode(kind: dirNode, cid: cid)
proc addFile*(root: var FsNode; name: string; cid: Cid; size: BiggestInt) {.deprecated.} =
assert cid.isValid
root.add name, FsNode(kind: fileNode, cid: cid, size: size)
proc del*(dir: var FsNode; name: string) =
dir.entries.del name
const
DirTag* = 0xda3c80 ## CBOR tag for UnixFS directories
FileTag* = 0xda3c81 ## CBOR tag for UnixFS files
proc isUnixfs*(bin: string): bool =
## Check if a string contains a UnixFS node
## in CBOR form.
var
s = newStringStream bin
c: CborParser
try:
c.open s
c.next
if c.kind == CborEventKind.cborTag:
result = c.tag == DirTag or c.tag == FileTag
except ValueError: discard
close s
proc toCbor*(u: FsNode): CborNode =
case u.kind
of fileNode:
let array = newCborArray()
array.seq.setLen u.links.len
for i in 0..u.links.high:
let L = newCborMap()
# typeEntry is reserved but not in use
L[dataKey.int] = u.links[i].cid.newCborBytes
L[sizeKey.int] = u.links[i].size.newCborInt
array.seq[i] = L
result = newCborTag(FileTag, array)
of dirNode:
let map = newCborMap()
for name, node in u.entries:
var entry = newCborMap()
case node.kind
of fileNode, shallowFileList:
if node.isRaw:
entry[typeKey.int] = fsFileChunk.int.newCborInt
else:
entry[typeKey.int] = fsFileList.int.newCborInt
entry[dataKey.int] = node.cid.newCborBytes
entry[sizeKey.int] = node.size.newCborInt
of dirNode:
entry[typeKey.int] = fsDirChunk.int.newCborInt
entry[dataKey.int] = node.cid.newCborBytes
entry[sizeKey.int] = node.entries.len.newCborInt
of shallowDirChunk:
entry[typeKey.int] = fsDirChunk.int.newCborInt
entry[dataKey.int] = node.cid.newCborBytes
entry[sizeKey.int] = node.size.int.newCborInt
map[name] = entry
# TODO: the CBOR maps must be sorted
result = newCborTag(DirTag, map)
else:
raiseAssert "shallow FsNodes can not be encoded"
template parseAssert(cond: bool; msg = "") =
if not cond: raise newException(
ValueError,
if msg == "": "invalid UnixFS CBOR" else: "invalid UnixFS CBOR, " & msg)
proc parseFs*(raw: string; cid: Cid): FsNode =
## Parse a string containing CBOR data into a FsNode.
new result
result.cid = cid
var
c: CborParser
buf = ""
open(c, newStringStream(raw))
next c
parseAssert(c.kind == CborEventKind.cborTag, "data not tagged")
let tag = c.tag
if tag == FileTag:
result.kind = fileNode
next c
parseAssert(c.kind == CborEventKind.cborArray, "file data not an array")
let nLinks = c.arrayLen
result.links = newSeq[FileLink](nLinks)
for i in 0..<nLinks:
next c
parseAssert(c.kind == CborEventKind.cborMap, "file array does not contain maps")
let nAttrs = c.mapLen
for _ in 1..nAttrs:
next c
parseAssert(c.kind == CborEventKind.cborPositive, "link map key not an integer")
let key = c.readInt.EntryKey
next c
case key
of typeKey:
parseAssert(false, "type file links are not supported")
of dataKey:
parseAssert(c.kind == CborEventKind.cborBytes, "CID not encoded as bytes")
c.readBytes buf
result.links[i].cid.take buf
of sizeKey:
parseAssert(c.kind == CborEventKind.cborPositive, "link size not encoded properly")
result.links[i].size = c.readInt
result.size.inc result.links[i].size
elif tag == DirTag:
result.kind = dirNode
next c
parseAssert(c.kind == CborEventKind.cborMap)
let dirLen = c.mapLen
parseAssert(dirLen != -1, raw)
result.entries = initOrderedTable[string, FsNode](dirLen.nextPowerOfTwo)
for i in 1 .. dirLen:
next c
parseAssert(c.kind == CborEventKind.cborText, raw)
c.readText buf
parseAssert(not buf.contains({ '/', '\0'}), raw)
next c
parseAssert(c.kind == CborEventKind.cborMap)
let nAttrs = c.mapLen
parseAssert(nAttrs > 1, raw)
let entry = new FsNode
result.entries[buf] = entry
for i in 1 .. nAttrs:
next c
parseAssert(c.kind == CborEventKind.cborPositive)
case c.readInt.EntryKey
of typeKey:
next c
case c.readInt.FsType
of fsFileList: entry.kind = shallowFileList
of fsDirChunk: entry.kind = shallowDirChunk
of fsFileChunk:
entry.kind = fileNode
entry.links = newSeq[FileLink](0)
of dataKey:
next c
c.readBytes buf
entry.cid.take buf
of sizeKey:
next c
entry.size = c.readInt
else:
parseAssert(false, raw)
next c
parseAssert(c.kind == cborEof, "trailing data")
proc toStream*(node: FsNode; s: Stream) =
let c = node.toCbor()
c.toStream s
iterator items*(dir: FsNode): (string, FsNode) =
assert(dir.kind == dirNode)
for k, v in dir.entries.pairs:
yield (k, v)
proc containsFile*(dir: FsNode; name: string): bool =
doAssert(dir.kind == dirNode)
dir.entries.contains name
proc `[]`*(dir: FsNode; name: string): FsNode =
if dir.kind == dirNode:
result = dir.entries.getOrDefault name
proc `[]`*(dir: FsNode; index: int): (string, FsNode) =
result[0] = ""
if dir.kind == dirNode:
var i = 0
for name, node in dir.entries.pairs:
if i == index:
result = (name, node)
break
inc i
proc lookupFile*(dir: FsNode; name: string): tuple[cid: Cid, size: BiggestInt] =
doAssert(dir.kind == dirNode)
let f = dir.entries[name]
if f.kind == fileNode:
result.cid = f.cid
result.size = f.size
proc addFile*(store: BlobStore; path: string): FsNode =
## Add a file to the store and a FsNode.
let
file = openAsync(path, fmRead)
fileSize = file.getFileSize
u = newUnixfsFile()
u.links = newSeqOfCap[FileLink](1)
var
buf = newString(min(maxChunKSize, fileSize))
pos = 0
let shortLen = fileSize mod maxChunKSize
if 0 < shortLen:
buf.setLen shortLen
# put the short chunck first
while true:
let n = waitFor file.readBuffer(buf[0].addr, buf.len)
buf.setLen n
let cid = store.put(buf)
u.links.add FileLink(cid: cid, size: buf.len)
u.size.inc buf.len
pos.inc n
if pos >= fileSize: break
buf.setLen maxChunkSize
close file
if u.size == 0:
# return the CID for a raw nothing
u.cid = dagHash("")
else:
if u.links.len == 1:
# take a shortcut use the raw chunk CID
u.cid = u.links[0].cid
u.links.setLen 0
else:
u.cid = store.putDag(u.toCbor)
result = u
proc addDir*(store: BlobStore; dirPath: string): FsNode =
var dRoot = newFsRoot()
for kind, path in walkDir dirPath:
var child: FsNode
case kind
of pcFile, pcLinkToFile:
child = store.addFile path
of pcDir, pcLinkToDir:
child = store.addDir(path)
else: continue
dRoot.add path.extractFilename, child
let
dag = dRoot.toCbor
cid = store.putDag(dag)
result = newUnixfsDir(cid)
proc open*(store: BlobStore; cid: Cid): FsNode =
assert cid.isValid
let raw = store.get(cid)
result = parseFs(raw, cid)
proc openDir*(store: BlobStore; cid: Cid): FsNode =
assert cid.isValid
var raw = ""
try: store.get(cid, raw)
except MissingChunk: raiseMissing cid
# this sucks
result = parseFs(raw, cid)
assert(result.kind == dirNode)
proc walk*(store: BlobStore; dir: FsNode; path: string; cache = true): FsNode =
## Walk a path down a root.
assert(dir.kind == dirNode)
result = dir
var raw = ""
for name in split(path, DirSep):
if name == "": continue
if result.kind == fileNode:
result = nil
break
var next = result[name]
if next.isNil:
result = nil
break
if (next.kind in {shallowFileList, shallowDirChunk}):
store.get(next.cid, raw)
next = parseFs(raw, next.cid)
if cache:
result.entries[name] = next
result = next
#[
iterator fileChunks*(store: BlobStore; file: FsNode): string =
## Iterate over the links in a file and return futures for link data.
if file.cid.isRaw:
yield store.get(file.cid)
else:
var
i = 0
chunk = ""
while i < file.links.len:
store.get(file.links[i].cid, chunk)
yield chunk
inc i
]#
proc readBuffer*(store: BlobStore; file: FsNode; pos: BiggestInt;
buf: pointer; size: int): int =
## Read a UnixFS file into a buffer. May return zero for any failure.
assert(pos > -1)
var
filePos = 0
chunk = ""
if pos < file.size:
if file.isRaw:
let pos = pos.int
store.get(file.cid, chunk)
if pos < chunk.high:
copyMem(buf, chunk[pos].addr, min(chunk.len - pos, size))
result = size
else:
for i in 0..file.links.high:
let linkSize = file.links[i].size
if filePos <= pos and pos < filePos+linkSize:
store.get(file.links[i].cid, chunk)
let
chunkPos = int(pos - filePos)
n = min(chunk.len-chunkPos, size)
copyMem(buf, chunk[chunkPos].addr, n)
result = n
break
filePos.inc linkSize

View File

@ -12,7 +12,7 @@ type
# TODO: tables must be purged periodically
rng: Rand
proc newHttpStoreServer*(backend: BlobStore; seed = 0'i64): HttpStoreServer =
proc newHttpStoreServer*(backend: BlobStore; seed = 1'i64): HttpStoreServer =
## Create a new HTTP server for a given store.
randomize()
HttpStoreServer(
@ -62,8 +62,8 @@ proc get(hss: HttpStoreServer; req: Request) {.async.} =
if range != "":
let
(startPos, endPos) = parseRange range
pos = startPos
len = endPos - startPos
pos = startPos
len = endPos - startPos
stream.pos = pos
var body = newString(len)
len = await stream.read(body[0].addr, len)

View File

@ -1,5 +1,6 @@
import std/asyncdispatch, std/httpclient, std/strutils, std/uri
import ../blobsets
import tiger
import std/asyncdispatch, std/httpclient, std/strutils, std/uri
type
HttpBlobStream = ref HttpBlobStreamObj
@ -12,7 +13,7 @@ type
HttpIngestStreamObj = object of IngestStreamObj
client: AsyncHttpClient
url: string
ctx: Blake2b256
ctx: TigerState
leaves: seq[BlobId]
leaf: string
buffOff: int
@ -27,6 +28,10 @@ type
proc httpBlobClose(s: BlobStream) = discard
proc httpBlobSize(s: BlobStream): BiggestInt =
var s = HttpBlobStream(s)
discard
proc setPosHttp(s: BlobStream; pos: BiggestInt) =
var s = (HttpBlobStream)s
s.rangePos = pos
@ -52,6 +57,7 @@ proc httpOpenBlobStream(store: BlobStore; id: BlobId; size: BiggestInt; kind: Bl
let stream = HttpBlobStream(
client: store.client,
closeImpl: httpBlobClose,
sizeImpl: httpBlobSize,
setPosImpl: setPosHttp,
getPosImpl: getPosHttp,
readImpl: httpBlobRead,

View File

@ -1,190 +0,0 @@
import std/bitops, std/endians
type
Blake2b* = object
hash: array[8, uint64]
offset: array[2, uint64]
buffer: array[128, uint8]
buffer_idx: uint8
hash_size: uint8
Blake2bParams* = object
b: array[64, byte]
Blake2sParams* = object
b: array[32, byte]
Blake2Params* = Blake2bParams | Blake2sParams
proc params(c: var Blake2b): ptr Blake2bParams =
cast[ptr Blake2bParams](c.hash.addr)
proc `digestLen=`*(p: ptr Blake2bParams; x: range[1..64]) =
p.b[0] = (uint8)x
proc `digestLen=`*(p: ptr Blake2sParams; x: range[1..32]) =
p.b[0] = (uint8)x
proc `keyLen=`*(p: ptr Blake2bParams; x: range[0..64]) =
p.b[1] = (uint8)x
proc `keyLen=`*(p: ptr Blake2sParams; x: range[0..32]) =
p.b[1] = (uint8)x
proc `fanout=`*(p: ptr Blake2Params; x: Natural) =
p.b[2] = (uint8)x
proc `depth=`*(p: ptr Blake2Params; x: Natural) =
p.b[3] = (uint8)x
proc `leafLength=`*(p: ptr Blake2Params; x: Natural) =
var x = x; littleEndian32(p.b[4].addr, x.addr)
proc `nodeOffset=`*(p: ptr Blake2bParams; x: Natural) =
var x = x; littleEndian64(p.b[8].addr, x.addr)
proc `nodeOffset=`*(p: ptr 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: ptr Blake2bParams; x: Natural) =
p.b[16] = (uint8)x
proc `nodeDepth=`*(p: ptr Blake2sParams; x: Natural) =
p.b[14] = (uint8)x
proc `innerLength=`*(p: ptr Blake2bParams; x: Natural) =
p.b[17] = (uint8)x
proc `innerLength=`*(p: ptr Blake2sParams; x: Natural) =
p.b[15] = (uint8)x
proc `salt=`*(p: ptr Blake2bParams; salt: pointer; len: Natural) =
copyMem(p.b[32].addr, salt, min(len, 16))
proc `salt=`*(p: ptr Blake2sParams; salt: pointer; len: Natural) =
copyMem(p.b[16].addr, salt, min(len, 8))
proc `personal=`*(p: ptr Blake2bParams; salt: pointer; len: Natural) =
copyMem(p.b[48].addr, salt, min(len, 16))
proc `personal=`*(p: ptr Blake2sParams; salt: pointer; len: Natural) =
copyMem(p.b[24].addr, salt, min(len, 8))
proc init(p: ptr Blake2Params) =
when p is Blake2bParams:
p.digestLen = 64
else:
p.digestLen = 32
p.fanout = 1
p.depth = 1
const Blake2bIV =
[ 0x6a09e667f3bcc908'u64, 0xbb67ae8584caa73b'u64,
0x3c6ef372fe94f82b'u64, 0xa54ff53a5f1d36f1'u64,
0x510e527fade682d1'u64, 0x9b05688c2b3e6c1f'u64,
0x1f83d9abfb41bd6b'u64, 0x5be0cd19137e2179'u64 ]
const Sigma = [
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
[ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ],
[ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ],
[ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ],
[ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ],
[ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ],
[ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ],
[ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ],
[ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ],
[ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
[ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] ]
proc inc(a: var array[2, uint64], b: uint8) =
a[0] = a[0] + b
if (a[0] < b): inc(a[1])
proc padding(a: var array[128, uint8], b: uint8) =
for i in b..127: a[i] = 0
proc G (v: var array[16, uint64],
a,b,c,d: int, x,y: uint64)
{.inline.} =
v[a] = v[a] + v[b] + x
v[d] = rotateRightBits(v[d] xor v[a], 32)
v[c] = v[c] + v[d]
v[b] = rotateRightBits(v[b] xor v[c], 24)
v[a] = v[a] + v[b] + y
v[d] = rotateRightBits(v[d] xor v[a], 16)
v[c] = v[c] + v[d]
v[b] = rotateRightBits(v[b] xor v[c], 63)
proc compress(c: var Blake2b, last: int = 0) =
var input, v: array[16, uint64]
for i in 0..15:
input[i] = cast[ptr uint64](addr(c.buffer[i*8]))[]
for i in 0..7:
v[i] = c.hash[i]
v[i+8] = Blake2bIV[i]
v[12] = v[12] xor c.offset[0]
v[13] = v[13] xor c.offset[1]
if (last == 1): v[14] = not(v[14])
for i in 0..11:
G(v, 0, 4, 8, 12, input[Sigma[i][0]], input[Sigma[i][1]])
G(v, 1, 5, 9, 13, input[Sigma[i][2]], input[Sigma[i][3]])
G(v, 2, 6, 10, 14, input[Sigma[i][4]], input[Sigma[i][5]])
G(v, 3, 7, 11, 15, input[Sigma[i][6]], input[Sigma[i][7]])
G(v, 0, 5, 10, 15, input[Sigma[i][8]], input[Sigma[i][9]])
G(v, 1, 6, 11, 12, input[Sigma[i][10]], input[Sigma[i][11]])
G(v, 2, 7, 8, 13, input[Sigma[i][12]], input[Sigma[i][13]])
G(v, 3, 4, 9, 14, input[Sigma[i][14]], input[Sigma[i][15]])
for i in 0..7:
c.hash[i] = c.hash[i] xor v[i] xor v[i+8]
c.buffer_idx = 0
{.push boundChecks: off.}
proc update*(c: var Blake2b, buf: pointer, data_size: int) =
var data = cast[ptr array[0, uint8]](buf)
for i in 0..<data_size:
if c.buffer_idx == 128:
inc(c.offset, c.buffer_idx)
compress(c)
c.buffer[c.buffer_idx] = data[i]
inc(c.buffer_idx)
{.pop.}
proc update*(c: var Blake2b, data: cstring|string|seq|uint8, data_size: int) =
for i in 0..<data_size:
if c.buffer_idx == 128:
inc(c.offset, c.buffer_idx)
compress(c)
when data is cstring or data is string:
c.buffer[c.buffer_idx] = data[i].uint8
elif data is seq:
c.buffer[c.buffer_idx] = data[i]
else:
c.buffer[c.buffer_idx] = data
inc(c.buffer_idx)
proc initBlake2b*(key: pointer = nil, key_size: range[0..64] = 0): Blake2b =
init(result.params)
result.hash_size = result.params.b[0]
result.params.keyLen = keySize
for i in 0..7:
result.hash[i] = Blake2bIV[i]
if key_size > 0:
update(result, key, key_size)
padding(result.buffer, result.buffer_idx)
result.buffer_idx = 128
proc initBlake2b*(customize: proc(params: ptr Blake2bParams)): Blake2b =
let p = result.params
init(p)
customize(p)
result.hash_size = p.b[0]
for i in 0..7:
result.hash[0] = result.hash[0] xor Blake2bIV[i]
proc finish*(c: var Blake2b): seq[uint8] =
result = newSeq[uint8](c.hash_size)
inc(c.offset, c.buffer_idx)
padding(c.buffer, c.buffer_idx)
compress(c, 1)
for i in 0'u8..<c.hash_size:
result[i.int] = cast[uint8]((c.hash[i div 8] shr (8'u8 * (i and 7)) and 0xFF))
proc `$`(d: seq[uint8]): string =
const digits = "0123456789abcdef"
result = ""
for i in 0..high(d):
add(result, digits[(d[i].int shr 4) and 0xF])
add(result, digits[d[i].int and 0xF])

View File

@ -45,20 +45,23 @@ proc nibbleToChar(nibble: int): char =
if nibble < byteMapLen:
return byteMap[nibble];
template encodeTmpl(str: untyped): typed =
let length = (len(str))
proc encode*(bin: string): string =
let length = (len(bin))
result = newString(length * 2)
for i in str.low..str.high:
let a = ord(str[i]) shr 4
let b = ord(str[i]) and ord(0x0f)
for i in bin.low..bin.high:
let a = ord(bin[i]) shr 4
let b = ord(bin[i]) and ord(0x0f)
result[i * 2] = nibbleToChar(a)
result[i * 2 + 1] = nibbleToChar(b)
proc encode*(bin: string): string =
encodeTmpl(bin)
proc encode*(bin: openarray[char|int8|uint8]): string =
encodeTmpl(bin)
let length = (len(bin))
result = newString(length * 2)
for i in bin.low..bin.high:
let a = ord(bin[i]) shr 4
let b = ord(bin[i]) and ord(0x0f)
result[i * 2] = nibbleToChar(a)
result[i * 2 + 1] = nibbleToChar(b)
when isMainModule:
assert encode("The sun so bright it leaves no shadows") == "5468652073756e20736f20627269676874206974206c6561766573206e6f20736861646f7773"

View File

@ -1,19 +0,0 @@
#
#
# 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

View File

@ -1,21 +0,0 @@
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.

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,481 +0,0 @@
#
#
# 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])

View File

@ -1,150 +0,0 @@
#
#
# 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

View File

@ -1,289 +0,0 @@
#
#
# 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..<int(sizeBlock):
opad[i] = 0x5C'u8 xor k[i]
ipad[i] = 0x36'u8 xor k[i]
init(hmctx.mdctx)
update(hmctx.mdctx, addr ipad[0], sizeBlock)
update(hmctx.opadctx, addr opad[0], sizeBlock)
proc init*[T](hmctx: var HMAC[T], key: openarray[byte]) {.inline.} =
## Initialize HMAC context ``hmctx`` with key using ``key`` array.
##
## ``key`` can be zero-length array.
if len(key) == 0:
init(hmctx, nil, 0'u)
else:
init(hmctx, unsafeAddr key[0], cast[uint](len(key)))
proc init*[T](hmctx: var HMAC[T], key: openarray[char]) {.inline.} =
## Initialize HMAC context ``hmctx`` with key using ``key`` string/array.
##
## ``key`` can be zero-length array.
if len(key) == 0:
init(hmctx, nil, 0'u)
else:
init(hmctx, cast[ptr byte](unsafeAddr key[0]), cast[uint](len(key)))
proc clear*(hmctx: var HMAC) =
## Clear HMAC context ``hmctx``.
burnMem(hmctx)
proc update*(hmctx: var HMAC, data: ptr byte, ulen: uint) =
## Update HMAC context ``hmctx`` with data pointed by ``data`` and length
## ``ulen``. Repeated calls are equivalent to a single call with the
## concatenation of all ``data`` arguments.
##
## ``data`` can be ``nil``, but ``ulen`` must be ``0`` in such case.
mixin update
assert((not isNil(data)) or (isNil(data) and ulen == 0'u))
update(hmctx.mdctx, data, ulen)
proc update*[T: bchar](hmctx: var HMAC, data: openarray[T]) {.inline.} =
## Update HMAC context ``hmctx`` with data array ``data``. Repeated calls are
## equivalent to a single call with the concatenation of all ``data``
## arguments.
##
## ``data`` can be zero-length array.
if len(data) == 0:
update(hmctx, nil, 0'u)
else:
update(hmctx, cast[ptr byte](unsafeAddr data[0]), cast[uint](len(data)))
proc finish*(hmctx: var HMAC, data: ptr byte, ulen: uint): uint =
## Finalize HMAC context ``hmctx`` and store calculated digest in data pointed
## by ``data`` and length ``ulen``. ``data`` must be able to hold
assert((not isNil(data)) or (isNil(data) and ulen == 0'u))
mixin update, finish
var buffer: array[hmctx.sizeDigest, byte]
let size = finish(hmctx.mdctx, addr buffer[0], cast[uint](hmctx.sizeDigest))
hmctx.opadctx.update(addr buffer[0], size)
result = hmctx.opadctx.finish(data, ulen)
proc finish*[T: bchar](hmctx: var HMAC,
data: var openarray[T]): uint {.inline.} =
## Finalize HMAC context ``hmctx`` and store calculated digest in array
## ``data``. ``data`` length must be at least ``hmctx.sizeDigest`` octets
## (bytes).
let ulen = cast[uint](len(data))
assert(ulen >= 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()

View File

@ -1,324 +0,0 @@
#
#
# 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)))

View File

@ -1,67 +0,0 @@
#
#
# 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..<c:
ctx.init(pwd)
ctx.update(md)
discard ctx.finish(md)
for k in 0..<len(work):
work[k] = work[k] xor md[k]
bytesWrite = min(olength - glength, int(ctx.sizeDigest))
copyMem(addr output[glength], addr work[0], bytesWrite)
glength += bytesWrite
ctr = ctr + 1
ctx.clear()
result = glength

File diff suppressed because it is too large Load Diff

View File

@ -1,750 +0,0 @@
#
#
# 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)))

View File

@ -1,572 +0,0 @@
#
#
# 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)))

View File

@ -1,289 +0,0 @@
#
#
# 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: "<unistd.h>".}
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 <unistd.h>
#include <sys/syscall.h>""", 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)

View File

@ -1,449 +0,0 @@
#
#
# 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..<k:
Me[i] = BSWAP(GET_DWORD(key, 2 * i))
Mo[i] = BSWAP(GET_DWORD(key, 2 * i + 1))
for i in 0..<k:
for j in 0..<4:
vector[j] = bn(Me[i], j.uint32)
vector[j + 4] = bn(Mo[i], j.uint32)
S[k - i - 1] = rsMatrixMultiply(vector)
for i in 0..<20:
A = h(uint32(2 * i * RHO), Me, k.uint32)
B = ROL(h(uint32(2 * i * RHO + RHO), Mo, k.uint32), 8)
ctx.K[2 * i] = A + B
ctx.K[2 * i + 1] = ROL(uint32(A + 2'u32 * B), 9)
fullKey(S, k.int32, ctx.S)
template sizeKey*(ctx: TwofishContext): int =
(ctx.bits div 8)
template sizeBlock*(ctx: TwofishContext): int =
(16)
template sizeKey*(r: typedesc[twofish]): int =
when r is twofish128:
(16)
elif r is twofish192:
(24)
elif r is twofish256:
(32)
template sizeBlock*(r: typedesc[twofish]): int =
(16)
proc init*(ctx: var TwofishContext, key: ptr byte, nkey: int = 0) {.inline.} =
initTwofishContext(ctx, ctx.bits, key)
proc init*(ctx: var TwofishContext, key: openarray[byte]) {.inline.} =
assert(len(key) >= 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])

View File

@ -1,227 +0,0 @@
#
#
# 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))

View File

@ -42,12 +42,11 @@ suite "store":
let
name = $i
blob = waitFor client.ingest(newString(i))
echo "insert ", blob, " ", i
bs = waitFor insert(client, bs, name, blob, i)
setId = (waitFor commit(client, bs)).setId
test "load":
bs = waitFor load(client, setId)
bs = waitFor client.load(setId)
for i in 1..count:
let
name = $i
@ -69,7 +68,6 @@ suite "store":
test "random":
for i in 1..count:
store.randomApply(bs, rng) do (id: BlobId; size: BiggestInt):
echo "randomApply: ", id, " ", size
let stream = store.openBlobStream(id, size, dataBlob)
close stream
@ -79,7 +77,6 @@ suite "store":
let stream = newMemberStream()
asyncCheck stream.streamMembers(store, bs)
var
val: tuple[key: Key; id: BlobId; size: BiggestInt]
found = false
count = 0
while not found:
@ -91,5 +88,4 @@ suite "store":
inc count
check(count > 0)
check(found)
echo "found ", i, " after ", count
waitFor findAll()

View File

@ -1,16 +1,44 @@
import base32
import ../src/blobsets, ../src/blobsets/filestores
import std/asyncdispatch, std/unittest, std/os, std/parseopt
import ../src/blobsets
suite "Encoding":
var empty: BlobId
test $empty:
check empty.toBase32 == base32.encode(cast[array[digestSize,char]](empty.data), pad=false)
check toBlobId($empty).data == empty.data
check empty.toBase32.toBlobId.data == empty.data
check empty.toHex.toBlobId.data == empty.data
suite "THEX":
let store = newNullStore()
proc testThex(data: string): string =
writeFile "tmp", data
let (id, _) = waitFor store.ingestFile("tmp")
removeFile "tmp"
id.toBase32
test "The empty (zero-length) file":
check testThex("") == "LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ"
test "A file with a single zero byte":
check testThex("\0") == "VK54ZIEEVTWNAUI5D5RDFIL37LX2IQNSTAXFKSA"
test "A file with 1024 'A' characters":
var s = newString(1024)
for c in s.mitems: c = 'A'
check testThex(s) == "L66Q4YVNAFWVS23X2HJIRA5ZJ7WXR3F26RSASFA"
test "A file with 1025 'A' characters":
var s = newString(1025)
for c in s.mitems: c = 'A'
check testThex(s) == "PZMRYHGY6LTBEH63ZWAHDORHSYTLO4LEFUIKHWY"
suite "Blob set tests":
var
store = newNullStore()
randomCid = blobHash("")
# test "zero blob":
# check(randomCid == zeroChunk)
proc randomize() =
randomCid = blobHash(randomCid.toHex)