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:
parent
1071e63d1c
commit
b905b45525
|
@ -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"]
|
||||
|
|
20
default.nix
20
default.nix
|
@ -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";
|
||||
|
|
194
src/blobset.nim
194
src/blobset.nim
|
@ -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)
|
||||
|
|
|
@ -1,5 +1,2 @@
|
|||
# Disable this to use only primitive stdin
|
||||
-d:readLine
|
||||
--nilseqs:on
|
||||
-d:spry
|
||||
-d:tox
|
||||
|
|
226
src/blobsets.nim
226
src/blobsets.nim
|
@ -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,12 +638,14 @@ 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)
|
||||
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]
|
||||
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
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)
|
||||
|
|
|
@ -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
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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])
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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
|
@ -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)
|
|
@ -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])
|
|
@ -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
|
|
@ -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()
|
|
@ -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)))
|
|
@ -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
|
@ -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)))
|
|
@ -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)))
|
|
@ -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)
|
|
@ -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])
|
|
@ -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))
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue