From 336a4b082ff7b4c31f5c912b40e17204c20002dc Mon Sep 17 00:00:00 2001 From: cheatfate Date: Mon, 22 Dec 2025 23:31:54 +0200 Subject: [PATCH 01/13] Initial commit. --- nimcrypto/bcmode.nim | 38 +- tests/testbcmode.nim | 1551 +++++++++++++++++++++--------------------- 2 files changed, 807 insertions(+), 782 deletions(-) diff --git a/nimcrypto/bcmode.nim b/nimcrypto/bcmode.nim index 0cca060..4a160c6 100644 --- a/nimcrypto/bcmode.nim +++ b/nimcrypto/bcmode.nim @@ -72,6 +72,7 @@ type buf: array[16, byte] aadlen: uint64 datalen: uint64 + coffset: uint8 ## ECB (Electronic Code Book) Mode @@ -1138,16 +1139,25 @@ func encrypt*[T]( var length = len(input) var offset = 0 - ctx.datalen += uint64(length) + while length > 0: - let uselen = if length < 16: length else: 16 - inc128(ctx.y) + let uselen = + if int(ctx.coffset) + length < 16: + length + else: + 16 - int(ctx.coffset) + if ctx.coffset == 0: + inc128(ctx.y) ctx.cipher.encrypt(ctx.y, ectr) - for i in 0.. 0: - pt = fromHex(stripSpaces(gcmP[i])) - ptcheck = newSeq[byte](len(pt)) - ctcheck = fromHex(stripSpaces(gcm192E[i])) - else: - pt = newSeq[byte]() - ptcheck = newSeq[byte]() - ctcheck = newSeq[byte]() - if len(gcmAads) > 0: - aad = fromHex(stripSpaces(gcmAads[i])) - else: - aad = newSeq[byte]() - ctx1.init(key, iv, aad) - ctx2.init(key, iv, aad) - var etagbuf = newSeq[byte](ctx1.sizeBlock) - var dtagbuf = newSeq[byte](ctx2.sizeBlock) - if len(pt) > 0: - var ct = newSeq[byte](len(pt)) - ctx1.encrypt(pt, ct) - ctx2.decrypt(ct, ptcheck) - check: - ct == ctcheck - pt == ptcheck - ctx1.getTag(etagbuf) - ctx2.getTag(dtagbuf) - check: - dtagbuf == etagbuf - etagbuf == fromHex(stripSpaces(gcm192Tags[i])) - ctx1.clear() - ctx2.clear() - check: - ctx1.isFullZero() == true - ctx2.isFullZero() == true + # test "AES-192-GCM test vectors": + # block: + # var ctx1: GCM[aes192] + # var ctx2: GCM[aes192] + # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + # for i in 0.. 0: + # pt = fromHex(stripSpaces(gcmP[i])) + # ptcheck = newSeq[byte](len(pt)) + # ctcheck = fromHex(stripSpaces(gcm192E[i])) + # else: + # pt = newSeq[byte]() + # ptcheck = newSeq[byte]() + # ctcheck = newSeq[byte]() + # if len(gcmAads) > 0: + # aad = fromHex(stripSpaces(gcmAads[i])) + # else: + # aad = newSeq[byte]() + # ctx1.init(key, iv, aad) + # ctx2.init(key, iv, aad) + # var etagbuf = newSeq[byte](ctx1.sizeBlock) + # var dtagbuf = newSeq[byte](ctx2.sizeBlock) + # if len(pt) > 0: + # var ct = newSeq[byte](len(pt)) + # ctx1.encrypt(pt, ct) + # ctx2.decrypt(ct, ptcheck) + # check: + # ct == ctcheck + # pt == ptcheck + # ctx1.getTag(etagbuf) + # ctx2.getTag(dtagbuf) + # check: + # dtagbuf == etagbuf + # etagbuf == fromHex(stripSpaces(gcm192Tags[i])) + # ctx1.clear() + # ctx2.clear() + # check: + # ctx1.isFullZero() == true + # ctx2.isFullZero() == true - block: - var ctx1: GCM[aes192] - var ctx2: GCM[aes192] - var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] - for i in 0.. 0: - pt = fromHex(stripSpaces(gcmP[i])) - ptcheck = newSeq[byte](len(pt)) - ctcheck = fromHex(stripSpaces(gcm192E[i])) - else: - pt = newSeq[byte]() - ptcheck = newSeq[byte]() - ctcheck = newSeq[byte]() - if len(gcmAads) > 0: - aad = fromHex(stripSpaces(gcmAads[i])) - else: - aad = newSeq[byte]() - ctx1.init(key, iv, aad) - ctx2.init(key, iv, aad) - var tag = newSeq[byte](ctx1.sizeBlock) - if len(pt) > 0: - var ct = newSeq[byte](len(pt)) - ctx1.encrypt(pt, ct, tag) - check: - ctx2.decrypt(ct, ptcheck, tag) == true - ct == ctcheck - pt == ptcheck - tag == fromHex(stripSpaces(gcm192Tags[i])) - ctx1.clear() - ctx2.clear() - check: - ctx1.isFullZero() == true - ctx2.isFullZero() == true + # block: + # var ctx1: GCM[aes192] + # var ctx2: GCM[aes192] + # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + # for i in 0.. 0: + # pt = fromHex(stripSpaces(gcmP[i])) + # ptcheck = newSeq[byte](len(pt)) + # ctcheck = fromHex(stripSpaces(gcm192E[i])) + # else: + # pt = newSeq[byte]() + # ptcheck = newSeq[byte]() + # ctcheck = newSeq[byte]() + # if len(gcmAads) > 0: + # aad = fromHex(stripSpaces(gcmAads[i])) + # else: + # aad = newSeq[byte]() + # ctx1.init(key, iv, aad) + # ctx2.init(key, iv, aad) + # var tag = newSeq[byte](ctx1.sizeBlock) + # if len(pt) > 0: + # var ct = newSeq[byte](len(pt)) + # ctx1.encrypt(pt, ct, tag) + # check: + # ctx2.decrypt(ct, ptcheck, tag) == true + # ct == ctcheck + # pt == ptcheck + # tag == fromHex(stripSpaces(gcm192Tags[i])) + # ctx1.clear() + # ctx2.clear() + # check: + # ctx1.isFullZero() == true + # ctx2.isFullZero() == true - test "AES-256-GCM test vectors": - block: - var ctx1: GCM[aes256] - var ctx2: GCM[aes256] - var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] - for i in 0.. 0: - pt = fromHex(stripSpaces(gcmP[i])) - ptcheck = newSeq[byte](len(pt)) - ctcheck = fromHex(stripSpaces(gcm256E[i])) - else: - pt = newSeq[byte]() - ptcheck = newSeq[byte]() - ctcheck = newSeq[byte]() - if len(gcmAads) > 0: - aad = fromHex(stripSpaces(gcmAads[i])) - else: - aad = newSeq[byte]() - ctx1.init(key, iv, aad) - ctx2.init(key, iv, aad) - var etagbuf = newSeq[byte](ctx1.sizeBlock) - var dtagbuf = newSeq[byte](ctx1.sizeBlock) - if len(pt) > 0: - var ct = newSeq[byte](len(pt)) - ctx1.encrypt(pt, ct) - ctx2.decrypt(ct, ptcheck) - check: - ct == ctcheck - pt == ptcheck - ctx1.getTag(etagbuf) - ctx2.getTag(dtagbuf) - check: - dtagbuf == etagbuf - etagbuf == fromHex(stripSpaces(gcm256Tags[i])) - ctx1.clear() - ctx2.clear() - check: - ctx1.isFullZero() == true - ctx2.isFullZero() == true + # test "AES-256-GCM test vectors": + # block: + # var ctx1: GCM[aes256] + # var ctx2: GCM[aes256] + # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + # for i in 0.. 0: + # pt = fromHex(stripSpaces(gcmP[i])) + # ptcheck = newSeq[byte](len(pt)) + # ctcheck = fromHex(stripSpaces(gcm256E[i])) + # else: + # pt = newSeq[byte]() + # ptcheck = newSeq[byte]() + # ctcheck = newSeq[byte]() + # if len(gcmAads) > 0: + # aad = fromHex(stripSpaces(gcmAads[i])) + # else: + # aad = newSeq[byte]() + # ctx1.init(key, iv, aad) + # ctx2.init(key, iv, aad) + # var etagbuf = newSeq[byte](ctx1.sizeBlock) + # var dtagbuf = newSeq[byte](ctx1.sizeBlock) + # if len(pt) > 0: + # var ct = newSeq[byte](len(pt)) + # ctx1.encrypt(pt, ct) + # ctx2.decrypt(ct, ptcheck) + # check: + # ct == ctcheck + # pt == ptcheck + # ctx1.getTag(etagbuf) + # ctx2.getTag(dtagbuf) + # check: + # dtagbuf == etagbuf + # etagbuf == fromHex(stripSpaces(gcm256Tags[i])) + # ctx1.clear() + # ctx2.clear() + # check: + # ctx1.isFullZero() == true + # ctx2.isFullZero() == true - block: - var ctx1: GCM[aes256] - var ctx2: GCM[aes256] - var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] - for i in 0.. 0: - pt = fromHex(stripSpaces(gcmP[i])) - ptcheck = newSeq[byte](len(pt)) - ctcheck = fromHex(stripSpaces(gcm256E[i])) - else: - pt = newSeq[byte]() - ptcheck = newSeq[byte]() - ctcheck = newSeq[byte]() - if len(gcmAads) > 0: - aad = fromHex(stripSpaces(gcmAads[i])) - else: - aad = newSeq[byte]() - ctx1.init(key, iv, aad) - ctx2.init(key, iv, aad) - var tag = newSeq[byte](ctx1.sizeBlock) - if len(pt) > 0: - var ct = newSeq[byte](len(pt)) - ctx1.encrypt(pt, ct, tag) - check: - ctx2.decrypt(ct, ptcheck, tag) == true - ct == ctcheck - pt == ptcheck - tag == fromHex(stripSpaces(gcm256Tags[i])) - ctx1.clear() - ctx2.clear() - check: - ctx1.isFullZero() == true - ctx2.isFullZero() == true + # block: + # var ctx1: GCM[aes256] + # var ctx2: GCM[aes256] + # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + # for i in 0.. 0: + # pt = fromHex(stripSpaces(gcmP[i])) + # ptcheck = newSeq[byte](len(pt)) + # ctcheck = fromHex(stripSpaces(gcm256E[i])) + # else: + # pt = newSeq[byte]() + # ptcheck = newSeq[byte]() + # ctcheck = newSeq[byte]() + # if len(gcmAads) > 0: + # aad = fromHex(stripSpaces(gcmAads[i])) + # else: + # aad = newSeq[byte]() + # ctx1.init(key, iv, aad) + # ctx2.init(key, iv, aad) + # var tag = newSeq[byte](ctx1.sizeBlock) + # if len(pt) > 0: + # var ct = newSeq[byte](len(pt)) + # ctx1.encrypt(pt, ct, tag) + # check: + # ctx2.decrypt(ct, ptcheck, tag) == true + # ct == ctcheck + # pt == ptcheck + # tag == fromHex(stripSpaces(gcm256Tags[i])) + # ctx1.clear() + # ctx2.clear() + # check: + # ctx1.isFullZero() == true + # ctx2.isFullZero() == true From 29b1096ed9db865d2c61200a7556ee3f161e84e7 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Wed, 24 Dec 2025 03:35:47 +0200 Subject: [PATCH 02/13] Complete fix with correct TAG calculation. Add tests for both GCM and CTR stream mode. --- nimcrypto/bcmode.nim | 77 +- tests/testbcmode.nim | 1800 ++++++++++++++++++++++++------------------ 2 files changed, 1064 insertions(+), 813 deletions(-) diff --git a/nimcrypto/bcmode.nim b/nimcrypto/bcmode.nim index 4a160c6..28c1ff7 100644 --- a/nimcrypto/bcmode.nim +++ b/nimcrypto/bcmode.nim @@ -70,6 +70,7 @@ type y: array[16, byte] basectr: array[16, byte] buf: array[16, byte] + hbuf: array[16, byte] aadlen: uint64 datalen: uint64 coffset: uint8 @@ -1104,8 +1105,8 @@ func init*[T]( ## You can see examples of usage GCM mode here ``examples/gcm.nim``. mixin init # GCM supports only 128bit block ciphers - assert(ctx.sizeBlock() == (128 div 8)) - assert(len(key) >= ctx.sizeKey()) + doAssert(ctx.sizeBlock() == (128 div 8)) + doAssert(len(key) >= ctx.sizeKey()) burnMem(ctx) ctx.cipher.init(key) ctx.cipher.encrypt(ctx.h, ctx.h) @@ -1113,10 +1114,10 @@ func init*[T]( ctx.y[0 ..< 12] = iv.toOpenArray(0, 11) inc128(ctx.y) else: - var tmp: array[16, byte] + var tmp: array[ctx.sizeBlock(), byte] ghash(ctx.y, ctx.h, iv) beStore32(tmp, 12, uint32(len(iv) shl 3)) - ghash(ctx.y, ctx.h, tmp.toOpenArray(0, 15)) + ghash(ctx.y, ctx.h, tmp.toOpenArray(0, ctx.sizeBlock() - 1)) ctx.cipher.encrypt(ctx.y, ctx.basectr) ctx.aadlen = uint64(len(aad)) ctx.datalen = 0 @@ -1134,30 +1135,33 @@ func encrypt*[T]( ## Note that length of ``input`` must be less or equal to length of ## ``output``. Length of ``input`` must not be zero. mixin encrypt - var ectr: array[16, byte] - assert(len(input) <= len(output)) + doAssert(len(input) <= len(output)) - var length = len(input) - var offset = 0 + var + ectr: array[ctx.sizeBlock(), byte] + length = len(input) + offset = 0 while length > 0: let uselen = - if int(ctx.coffset) + length < 16: + if int(ctx.coffset) + length < ctx.sizeBlock(): length else: - 16 - int(ctx.coffset) + ctx.sizeBlock() - int(ctx.coffset) if ctx.coffset == 0: inc128(ctx.y) ctx.cipher.encrypt(ctx.y, ectr) for i in 0 ..< uselen: - output[offset + i] = ectr[int(ctx.coffset) + i] xor input[offset + i] - debugEcho "output[", offset, ", ", offset + uselen - 1, "] = ", output.toHex() - ghash(ctx.buf, ctx.h, output.toOpenArray(offset, offset + uselen - 1)) + let ch = ectr[int(ctx.coffset) + i] xor input[offset + i] + output[offset + i] = ch + ctx.hbuf[int(ctx.coffset) + i] = ch length -= uselen offset += uselen - ctx.coffset = (ctx.coffset + uint8(uselen)) and 15'u8 + ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(ctx.sizeBlock() - 1) + if ctx.coffset == 0: + ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, ctx.sizeBlock - 1)) - ctx.datalen += uint64(length) + ctx.datalen += uint64(len(input)) func decrypt*[T]( ctx: var GCM[T], @@ -1170,29 +1174,33 @@ func decrypt*[T]( ## Note that length of ``input`` must be less or equal to length of ## ``output``. Length of ``input`` must not be zero. mixin encrypt - var ectr: array[16, byte] - assert(len(input) <= len(output)) + doAssert(len(input) <= len(output)) - var length = len(input) - var offset = 0 + var + ectr: array[ctx.sizeBlock(), byte] + length = len(input) + offset = 0 while length > 0: let uselen = - if int(ctx.coffset) + length < 16: + if int(ctx.coffset) + length < ctx.sizeBlock(): length else: - 16 - int(ctx.coffset) + ctx.sizeBlock() - int(ctx.coffset) if ctx.coffset == 0: inc128(ctx.y) ctx.cipher.encrypt(ctx.y, ectr) for i in 0 ..< uselen: - output[offset + i] = ectr[int(ctx.coffset) + i] xor input[offset + i] - ghash(ctx.buf, ctx.h, input.toOpenArray(offset, offset + uselen - 1)) + let ch = ectr[int(ctx.coffset) + i] xor input[offset + i] + output[offset + i] = ch + ctx.hbuf[int(ctx.coffset) + i] = input[offset + i] length -= uselen offset += uselen - ctx.coffset = (ctx.coffset + uint8(uselen)) and 15'u8 + ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(ctx.sizeBlock() - 1) + if ctx.coffset == 0: + ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, ctx.sizeBlock - 1)) - ctx.datalen += uint64(length) + ctx.datalen += uint64(len(input)) func getTag*[T]( ctx: var GCM[T], @@ -1202,18 +1210,23 @@ func getTag*[T]( ## ``tag``. ## ## Note that maximum size of ``tag`` is 128 bits (16 bytes). - let taglen = len(tag) - let uselen = if taglen < 16: taglen else: 16 - var workbuf: array[16, byte] + var workbuf: array[ctx.sizeBlock(), byte] + let + taglen = len(tag) + uselen = if taglen < ctx.sizeBlock(): taglen else: ctx.sizeBlock() + + if ctx.coffset != 0: + ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, int(ctx.coffset) - 1)) + if taglen > 0: copyMem(tag, 0, ctx.basectr, 0, uselen) beStore64(workbuf, 0, ctx.aadlen shl 3) beStore64(workbuf, 8, ctx.datalen shl 3) ghash(ctx.buf, ctx.h, workbuf) - for i in 0.. 0: + for pch in plain: + var rch: array[1, uint8] + rch[0] = 0x00'u8 + ctx1.encrypt([pch], rch) + ecrypt.add(rch[0]) + let ech = rch[0] + rch[0] = 0x00'u8 + ctx2.decrypt([ech], rch) + dcrypt.add(rch[0]) + check: + toHex(ecrypt) == ctr128E[i] + toHex(dcrypt) == allP[i] + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true - # test "AES-256-CFB test vectors": - # var key = fromHex(all256K) - # var iv = fromHex(cfbIV) - # var ctx1, ctx2, ctx3, ctx4: CFB[aes256] - # ctx1.init(addr key[0], addr iv[0]) - # ctx2.init(addr key[0], addr iv[0]) - # ctx3.init(key, iv) - # ctx4.init(key, iv) - # for i in 0..3: - # var plain = fromHex(allP[i]) - # let length = len(plain) - # var ecrypt = newSeq[uint8](length) - # var dcrypt = newSeq[uint8](length) - # ctx1.encrypt(addr plain[0], addr ecrypt[0], uint(length)) - # ctx2.decrypt(addr ecrypt[0], addr dcrypt[0], uint(length)) - # check: - # toHex(ecrypt) == cfb256E[i] - # toHex(dcrypt) == allP[i] - # burnMem(ecrypt) - # burnMem(dcrypt) - # ctx3.encrypt(plain, ecrypt) - # ctx4.decrypt(ecrypt, dcrypt) - # check: - # toHex(ecrypt) == cfb256E[i] - # toHex(dcrypt) == allP[i] - # ctx1.clear() - # ctx2.clear() - # ctx3.clear() - # ctx4.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true - # ctx3.isFullZero() == true - # ctx4.isFullZero() == true + test "AES-192-CTR test vectors": + var key = fromHex(all192K) + var iv = fromHex(ctrIV) + var ctx1, ctx2, ctx3, ctx4: CTR[aes192] + ctx1.init(addr key[0], addr iv[0]) + ctx2.init(addr key[0], addr iv[0]) + ctx3.init(key, iv) + ctx4.init(key, iv) + for i in 0 .. 3: + var plain = fromHex(allP[i]) + let length = len(plain) + var ecrypt = newSeq[uint8](length) + var dcrypt = newSeq[uint8](length) + ctx1.encrypt(addr plain[0], addr ecrypt[0], uint(length)) + ctx2.decrypt(addr ecrypt[0], addr dcrypt[0], uint(length)) + check: + toHex(ecrypt) == ctr192E[i] + toHex(dcrypt) == allP[i] + burnMem(ecrypt) + burnMem(dcrypt) + ctx3.encrypt(plain, ecrypt) + ctx4.decrypt(ecrypt, dcrypt) + check: + toHex(ecrypt) == ctr192E[i] + toHex(dcrypt) == allP[i] + ctx1.clear() + ctx2.clear() + ctx3.clear() + ctx4.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true + ctx3.isFullZero() == true + ctx4.isFullZero() == true - # test "AES-128-CTR test vectors": - # var key = fromHex(all128K) - # var iv = fromHex(ctrIV) - # var ctx1, ctx2, ctx3, ctx4: CTR[aes128] - # ctx1.init(addr key[0], addr iv[0]) - # ctx2.init(addr key[0], addr iv[0]) - # ctx3.init(key, iv) - # ctx4.init(key, iv) - # for i in 0..3: - # var plain = fromHex(allP[i]) - # let length = len(plain) - # var ecrypt = newSeq[uint8](length) - # var dcrypt = newSeq[uint8](length) - # ctx1.encrypt(addr plain[0], addr ecrypt[0], uint(length)) - # ctx2.decrypt(addr ecrypt[0], addr dcrypt[0], uint(length)) - # check: - # toHex(ecrypt) == ctr128E[i] - # toHex(dcrypt) == allP[i] - # burnMem(ecrypt) - # burnMem(dcrypt) - # ctx3.encrypt(plain, ecrypt) - # ctx4.encrypt(ecrypt, dcrypt) - # check: - # toHex(ecrypt) == ctr128E[i] - # toHex(dcrypt) == allP[i] - # ctx1.clear() - # ctx2.clear() - # ctx3.clear() - # ctx4.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true - # ctx3.isFullZero() == true - # ctx4.isFullZero() == true + test "AES-192-CTR test vectors (byte by byte)": + var + key = fromHex(all192K) + iv = fromHex(ctrIV) + ctx1, ctx2: CTR[aes192] + ctx1.init(key, iv) + ctx2.init(key, iv) + for i in 0 .. 3: + var + plain = fromHex(allP[i]) + ecrypt: seq[uint8] + dcrypt: seq[uint8] + if len(plain) > 0: + for pch in plain: + var rch: array[1, uint8] + rch[0] = 0x00'u8 + ctx1.encrypt([pch], rch) + ecrypt.add(rch[0]) + let ech = rch[0] + rch[0] = 0x00'u8 + ctx2.decrypt([ech], rch) + dcrypt.add(rch[0]) + check: + toHex(ecrypt) == ctr192E[i] + toHex(dcrypt) == allP[i] + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true - # test "AES-192-CTR test vectors": - # var key = fromHex(all192K) - # var iv = fromHex(ctrIV) - # var ctx1, ctx2, ctx3, ctx4: CTR[aes192] - # ctx1.init(addr key[0], addr iv[0]) - # ctx2.init(addr key[0], addr iv[0]) - # ctx3.init(key, iv) - # ctx4.init(key, iv) - # for i in 0..3: - # var plain = fromHex(allP[i]) - # let length = len(plain) - # var ecrypt = newSeq[uint8](length) - # var dcrypt = newSeq[uint8](length) - # ctx1.encrypt(addr plain[0], addr ecrypt[0], uint(length)) - # ctx2.decrypt(addr ecrypt[0], addr dcrypt[0], uint(length)) - # check: - # toHex(ecrypt) == ctr192E[i] - # toHex(dcrypt) == allP[i] - # burnMem(ecrypt) - # burnMem(dcrypt) - # ctx3.encrypt(plain, ecrypt) - # ctx4.decrypt(ecrypt, dcrypt) - # check: - # toHex(ecrypt) == ctr192E[i] - # toHex(dcrypt) == allP[i] - # ctx1.clear() - # ctx2.clear() - # ctx3.clear() - # ctx4.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true - # ctx3.isFullZero() == true - # ctx4.isFullZero() == true + test "AES-256-CTR test vectors": + var key = fromHex(all256K) + var iv = fromHex(ctrIV) + var ctx1, ctx2, ctx3, ctx4: CTR[aes256] + ctx1.init(addr key[0], addr iv[0]) + ctx2.init(addr key[0], addr iv[0]) + ctx3.init(key, iv) + ctx4.init(key, iv) + for i in 0 .. 3: + var plain = fromHex(allP[i]) + let length = len(plain) + var ecrypt = newSeq[uint8](length) + var dcrypt = newSeq[uint8](length) + ctx1.encrypt(addr plain[0], addr ecrypt[0], uint(length)) + ctx2.decrypt(addr ecrypt[0], addr dcrypt[0], uint(length)) + check: + toHex(ecrypt) == ctr256E[i] + toHex(dcrypt) == allP[i] + burnMem(ecrypt) + burnMem(dcrypt) + ctx3.encrypt(plain, ecrypt) + ctx4.decrypt(ecrypt, dcrypt) + check: + toHex(ecrypt) == ctr256E[i] + toHex(dcrypt) == allP[i] + ctx1.clear() + ctx2.clear() + ctx3.clear() + ctx4.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true + ctx3.isFullZero() == true + ctx4.isFullZero() == true - # test "AES-256-CTR test vectors": - # var key = fromHex(all256K) - # var iv = fromHex(ctrIV) - # var ctx1, ctx2, ctx3, ctx4: CTR[aes256] - # ctx1.init(addr key[0], addr iv[0]) - # ctx2.init(addr key[0], addr iv[0]) - # ctx3.init(key, iv) - # ctx4.init(key, iv) - # for i in 0..3: - # var plain = fromHex(allP[i]) - # let length = len(plain) - # var ecrypt = newSeq[uint8](length) - # var dcrypt = newSeq[uint8](length) - # ctx1.encrypt(addr plain[0], addr ecrypt[0], uint(length)) - # ctx2.decrypt(addr ecrypt[0], addr dcrypt[0], uint(length)) - # check: - # toHex(ecrypt) == ctr256E[i] - # toHex(dcrypt) == allP[i] - # burnMem(ecrypt) - # burnMem(dcrypt) - # ctx3.encrypt(plain, ecrypt) - # ctx4.decrypt(ecrypt, dcrypt) - # check: - # toHex(ecrypt) == ctr256E[i] - # toHex(dcrypt) == allP[i] - # ctx1.clear() - # ctx2.clear() - # ctx3.clear() - # ctx4.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true - # ctx3.isFullZero() == true - # ctx4.isFullZero() == true + test "AES-256-CTR test vectors (byte by byte)": + var + key = fromHex(all256K) + iv = fromHex(ctrIV) + ctx1, ctx2: CTR[aes256] + ctx1.init(key, iv) + ctx2.init(key, iv) + for i in 0 .. 3: + var + plain = fromHex(allP[i]) + ecrypt: seq[uint8] + dcrypt: seq[uint8] + if len(plain) > 0: + for pch in plain: + var rch: array[1, uint8] + rch[0] = 0x00'u8 + ctx1.encrypt([pch], rch) + ecrypt.add(rch[0]) + let ech = rch[0] + rch[0] = 0x00'u8 + ctx2.decrypt([ech], rch) + dcrypt.add(rch[0]) + check: + toHex(ecrypt) == ctr256E[i] + toHex(dcrypt) == allP[i] + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true - # test "CTR/ECB equality test": - # # This test is based on statement that ECB[T](key) = CTR[T](key, iv) - # # where IV is fullzero, and CTR counter is also zero. - # var ctx1: CTR[aes128] - # var ctx2: ECB[aes128] - # var ctx3: CTR[aes256] - # var ctx4: ECB[aes256] - # var key128: array[aes128.sizeKey, byte] - # var key256: array[aes256.sizeKey, byte] - # var iv: array[aes128.sizeBlock, byte] - # var data: array[aes128.sizeBlock, byte] - # var output1: array[aes128.sizeBlock, byte] - # var output2: array[aes128.sizeBlock, byte] - # ctx1.init(key128, iv) - # ctx2.init(key128) - # ctx3.init(key256, iv) - # ctx4.init(key256) - # ctx1.encrypt(data, output1) - # ctx2.encrypt(data, output2) - # check: - # output1 == output2 - # isFullZero(output1) == false - # burnMem(output1) - # burnMem(output2) - # check: - # output1 == output2 - # ctx3.encrypt(data, output1) - # ctx4.encrypt(data, output2) - # check: - # output1 == output2 - # isFullZero(output1) == false + test "CTR/ECB equality test": + # This test is based on statement that ECB[T](key) = CTR[T](key, iv) + # where IV is fullzero, and CTR counter is also zero. + var ctx1: CTR[aes128] + var ctx2: ECB[aes128] + var ctx3: CTR[aes256] + var ctx4: ECB[aes256] + var key128: array[aes128.sizeKey, byte] + var key256: array[aes256.sizeKey, byte] + var iv: array[aes128.sizeBlock, byte] + var data: array[aes128.sizeBlock, byte] + var output1: array[aes128.sizeBlock, byte] + var output2: array[aes128.sizeBlock, byte] + ctx1.init(key128, iv) + ctx2.init(key128) + ctx3.init(key256, iv) + ctx4.init(key256) + ctx1.encrypt(data, output1) + ctx2.encrypt(data, output2) + check: + output1 == output2 + isFullZero(output1) == false + burnMem(output1) + burnMem(output2) + check: + output1 == output2 + ctx3.encrypt(data, output1) + ctx4.encrypt(data, output2) + check: + output1 == output2 + isFullZero(output1) == false test "AES-128-GCM test vectors": block: @@ -896,8 +989,6 @@ suite "Block cipher modes Tests": for i in 0.. 0: - # pt = fromHex(stripSpaces(gcmP[i])) - # ptcheck = newSeq[byte](len(pt)) - # ctcheck = fromHex(stripSpaces(gcm192E[i])) - # else: - # pt = newSeq[byte]() - # ptcheck = newSeq[byte]() - # ctcheck = newSeq[byte]() - # if len(gcmAads) > 0: - # aad = fromHex(stripSpaces(gcmAads[i])) - # else: - # aad = newSeq[byte]() - # ctx1.init(key, iv, aad) - # ctx2.init(key, iv, aad) - # var etagbuf = newSeq[byte](ctx1.sizeBlock) - # var dtagbuf = newSeq[byte](ctx2.sizeBlock) - # if len(pt) > 0: - # var ct = newSeq[byte](len(pt)) - # ctx1.encrypt(pt, ct) - # ctx2.decrypt(ct, ptcheck) - # check: - # ct == ctcheck - # pt == ptcheck - # ctx1.getTag(etagbuf) - # ctx2.getTag(dtagbuf) - # check: - # dtagbuf == etagbuf - # etagbuf == fromHex(stripSpaces(gcm192Tags[i])) - # ctx1.clear() - # ctx2.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true + test "AES-128-GCM test vectors (byte by byte)": + block: + var ctx1: GCM[aes128] + var ctx2: GCM[aes128] + var key, pt, iv, aad, ctcheck: seq[byte] + for i in 0 ..< len(gcm128Keys): + key = fromHex(stripSpaces(gcm128Keys[i])) + iv = fromHex(stripSpaces(gcmIvs[i])) + if len(gcmP) > 0: + pt = fromHex(stripSpaces(gcmP[i])) + ctcheck = fromHex(stripSpaces(gcm128E[i])) + else: + pt = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var + etagbuf = newSeq[byte](ctx1.sizeBlock) + dtagbuf = newSeq[byte](ctx2.sizeBlock) + if len(pt) > 0: + var + ct: seq[byte] + et: seq[byte] + for pch in pt: + var rch: array[1, byte] + rch[0] = 0x00'u8 + ctx1.encrypt([pch], rch) + ct.add(rch[0]) + let ech = rch[0] + rch[0] = 0x00'u8 + ctx2.decrypt([ech], rch) + et.add(rch[0]) + check: + ct == ctcheck + et == pt + ctx1.getTag(etagbuf) + ctx2.getTag(dtagbuf) + check: + dtagbuf == etagbuf + etagbuf == fromHex(stripSpaces(gcm128Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true + + test "AES-192-GCM test vectors": + block: + var ctx1: GCM[aes192] + var ctx2: GCM[aes192] + var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + for i in 0.. 0: + pt = fromHex(stripSpaces(gcmP[i])) + ptcheck = newSeq[byte](len(pt)) + ctcheck = fromHex(stripSpaces(gcm192E[i])) + else: + pt = newSeq[byte]() + ptcheck = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var + etagbuf = newSeq[byte](ctx1.sizeBlock) + dtagbuf = newSeq[byte](ctx2.sizeBlock) + if len(pt) > 0: + var ct = newSeq[byte](len(pt)) + ctx1.encrypt(pt, ct) + ctx2.decrypt(ct, ptcheck) + check: + ct == ctcheck + pt == ptcheck + ctx1.getTag(etagbuf) + ctx2.getTag(dtagbuf) + check: + dtagbuf == etagbuf + etagbuf == fromHex(stripSpaces(gcm192Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true + + block: + var ctx1: GCM[aes192] + var ctx2: GCM[aes192] + var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + for i in 0.. 0: + pt = fromHex(stripSpaces(gcmP[i])) + ptcheck = newSeq[byte](len(pt)) + ctcheck = fromHex(stripSpaces(gcm192E[i])) + else: + pt = newSeq[byte]() + ptcheck = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var tag = newSeq[byte](ctx1.sizeBlock) + if len(pt) > 0: + var ct = newSeq[byte](len(pt)) + ctx1.encrypt(pt, ct, tag) + check: + ctx2.decrypt(ct, ptcheck, tag) == true + ct == ctcheck + pt == ptcheck + tag == fromHex(stripSpaces(gcm192Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true + + test "AES-192-GCM test vectors (byte by byte)": + block: + var ctx1: GCM[aes192] + var ctx2: GCM[aes192] + var key, pt, iv, aad, ctcheck: seq[byte] + for i in 0.. 0: + pt = fromHex(stripSpaces(gcmP[i])) + ctcheck = fromHex(stripSpaces(gcm192E[i])) + else: + pt = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var + etagbuf = newSeq[byte](ctx1.sizeBlock) + dtagbuf = newSeq[byte](ctx2.sizeBlock) + if len(pt) > 0: + var + ct: seq[byte] + et: seq[byte] + for pch in pt: + var rch: array[1, byte] + rch[0] = 0x00'u8 + ctx1.encrypt([pch], rch) + ct.add(rch[0]) + let ech = rch[0] + rch[0] = 0x00'u8 + ctx2.decrypt([ech], rch) + et.add(rch[0]) + check: + ct == ctcheck + et == pt + ctx1.getTag(etagbuf) + ctx2.getTag(dtagbuf) + check: + dtagbuf == etagbuf + etagbuf == fromHex(stripSpaces(gcm192Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true - # block: - # var ctx1: GCM[aes192] - # var ctx2: GCM[aes192] - # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] - # for i in 0.. 0: - # pt = fromHex(stripSpaces(gcmP[i])) - # ptcheck = newSeq[byte](len(pt)) - # ctcheck = fromHex(stripSpaces(gcm192E[i])) - # else: - # pt = newSeq[byte]() - # ptcheck = newSeq[byte]() - # ctcheck = newSeq[byte]() - # if len(gcmAads) > 0: - # aad = fromHex(stripSpaces(gcmAads[i])) - # else: - # aad = newSeq[byte]() - # ctx1.init(key, iv, aad) - # ctx2.init(key, iv, aad) - # var tag = newSeq[byte](ctx1.sizeBlock) - # if len(pt) > 0: - # var ct = newSeq[byte](len(pt)) - # ctx1.encrypt(pt, ct, tag) - # check: - # ctx2.decrypt(ct, ptcheck, tag) == true - # ct == ctcheck - # pt == ptcheck - # tag == fromHex(stripSpaces(gcm192Tags[i])) - # ctx1.clear() - # ctx2.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true + test "AES-256-GCM test vectors": + block: + var ctx1: GCM[aes256] + var ctx2: GCM[aes256] + var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + for i in 0.. 0: + pt = fromHex(stripSpaces(gcmP[i])) + ptcheck = newSeq[byte](len(pt)) + ctcheck = fromHex(stripSpaces(gcm256E[i])) + else: + pt = newSeq[byte]() + ptcheck = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var etagbuf = newSeq[byte](ctx1.sizeBlock) + var dtagbuf = newSeq[byte](ctx1.sizeBlock) + if len(pt) > 0: + var ct = newSeq[byte](len(pt)) + ctx1.encrypt(pt, ct) + ctx2.decrypt(ct, ptcheck) + check: + ct == ctcheck + pt == ptcheck + ctx1.getTag(etagbuf) + ctx2.getTag(dtagbuf) + check: + dtagbuf == etagbuf + etagbuf == fromHex(stripSpaces(gcm256Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true - # test "AES-256-GCM test vectors": - # block: - # var ctx1: GCM[aes256] - # var ctx2: GCM[aes256] - # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] - # for i in 0.. 0: - # pt = fromHex(stripSpaces(gcmP[i])) - # ptcheck = newSeq[byte](len(pt)) - # ctcheck = fromHex(stripSpaces(gcm256E[i])) - # else: - # pt = newSeq[byte]() - # ptcheck = newSeq[byte]() - # ctcheck = newSeq[byte]() - # if len(gcmAads) > 0: - # aad = fromHex(stripSpaces(gcmAads[i])) - # else: - # aad = newSeq[byte]() - # ctx1.init(key, iv, aad) - # ctx2.init(key, iv, aad) - # var etagbuf = newSeq[byte](ctx1.sizeBlock) - # var dtagbuf = newSeq[byte](ctx1.sizeBlock) - # if len(pt) > 0: - # var ct = newSeq[byte](len(pt)) - # ctx1.encrypt(pt, ct) - # ctx2.decrypt(ct, ptcheck) - # check: - # ct == ctcheck - # pt == ptcheck - # ctx1.getTag(etagbuf) - # ctx2.getTag(dtagbuf) - # check: - # dtagbuf == etagbuf - # etagbuf == fromHex(stripSpaces(gcm256Tags[i])) - # ctx1.clear() - # ctx2.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true + block: + var ctx1: GCM[aes256] + var ctx2: GCM[aes256] + var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] + for i in 0.. 0: + pt = fromHex(stripSpaces(gcmP[i])) + ptcheck = newSeq[byte](len(pt)) + ctcheck = fromHex(stripSpaces(gcm256E[i])) + else: + pt = newSeq[byte]() + ptcheck = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var tag = newSeq[byte](ctx1.sizeBlock) + if len(pt) > 0: + var ct = newSeq[byte](len(pt)) + ctx1.encrypt(pt, ct, tag) + check: + ctx2.decrypt(ct, ptcheck, tag) == true + ct == ctcheck + pt == ptcheck + tag == fromHex(stripSpaces(gcm256Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true - # block: - # var ctx1: GCM[aes256] - # var ctx2: GCM[aes256] - # var key, pt, iv, aad, ptcheck, ctcheck: seq[byte] - # for i in 0.. 0: - # pt = fromHex(stripSpaces(gcmP[i])) - # ptcheck = newSeq[byte](len(pt)) - # ctcheck = fromHex(stripSpaces(gcm256E[i])) - # else: - # pt = newSeq[byte]() - # ptcheck = newSeq[byte]() - # ctcheck = newSeq[byte]() - # if len(gcmAads) > 0: - # aad = fromHex(stripSpaces(gcmAads[i])) - # else: - # aad = newSeq[byte]() - # ctx1.init(key, iv, aad) - # ctx2.init(key, iv, aad) - # var tag = newSeq[byte](ctx1.sizeBlock) - # if len(pt) > 0: - # var ct = newSeq[byte](len(pt)) - # ctx1.encrypt(pt, ct, tag) - # check: - # ctx2.decrypt(ct, ptcheck, tag) == true - # ct == ctcheck - # pt == ptcheck - # tag == fromHex(stripSpaces(gcm256Tags[i])) - # ctx1.clear() - # ctx2.clear() - # check: - # ctx1.isFullZero() == true - # ctx2.isFullZero() == true + test "AES-256-GCM test vectors (byte by byte)": + block: + var ctx1: GCM[aes256] + var ctx2: GCM[aes256] + var key, pt, iv, aad, ctcheck: seq[byte] + for i in 0.. 0: + pt = fromHex(stripSpaces(gcmP[i])) + ctcheck = fromHex(stripSpaces(gcm256E[i])) + else: + pt = newSeq[byte]() + ctcheck = newSeq[byte]() + if len(gcmAads) > 0: + aad = fromHex(stripSpaces(gcmAads[i])) + else: + aad = newSeq[byte]() + ctx1.init(key, iv, aad) + ctx2.init(key, iv, aad) + var + etagbuf = newSeq[byte](ctx1.sizeBlock) + dtagbuf = newSeq[byte](ctx1.sizeBlock) + if len(pt) > 0: + var + ct: seq[byte] + et: seq[byte] + for pch in pt: + var rch: array[1, byte] + rch[0] = 0x00'u8 + ctx1.encrypt([pch], rch) + ct.add(rch[0]) + let ech = rch[0] + rch[0] = 0x00'u8 + ctx2.decrypt([ech], rch) + et.add(rch[0]) + check: + ct == ctcheck + et == pt + ctx1.getTag(etagbuf) + ctx2.getTag(dtagbuf) + check: + dtagbuf == etagbuf + etagbuf == fromHex(stripSpaces(gcm256Tags[i])) + ctx1.clear() + ctx2.clear() + check: + ctx1.isFullZero() == true + ctx2.isFullZero() == true From 329da00494e7f4ee46ab1820b971f4bb94049be8 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Wed, 24 Dec 2025 04:00:41 +0200 Subject: [PATCH 03/13] Fix bootstrap.sh. --- tests/bootstrap.sh | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/tests/bootstrap.sh b/tests/bootstrap.sh index 3aea5ba..0d3cef8 100755 --- a/tests/bootstrap.sh +++ b/tests/bootstrap.sh @@ -14,19 +14,8 @@ function build_nim { echo "Building Nim [${NIM_BRANCH}] in ${NIM_DIR}" git clone https://github.com/nim-lang/Nim.git ${NIM_DIR} cd "${NIM_DIR}" - if [ "${NIM_BRANCH}" = "version-1-6" ]; then - git checkout "${NIM_BRANCH}" - git clone --depth 1 https://github.com/nim-lang/csources_v1 - cd csources_v1 && sh build.sh - else - git checkout devel - git clone --depth 1 https://github.com/nim-lang/csources_v2 - cd csources_v2 && sh build.sh - fi - cd .. - bin/nim c --skipParentCfg --noNimblePath --skipUserCfg -d:release koch - ./koch boot -d:release - ./koch nimble -d:release + git checkout "${NIM_BRANCH}" + ./build_all.sh cd .. } From 4c9db33bbc89d0ec8b3219aa50d82cd9907192ed Mon Sep 17 00:00:00 2001 From: cheatfate Date: Wed, 24 Dec 2025 04:04:02 +0200 Subject: [PATCH 04/13] Fix bootstrap.bat. --- tests/bootstrap.bat | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/bootstrap.bat b/tests/bootstrap.bat index b30e9bf..87ebd2e 100644 --- a/tests/bootstrap.bat +++ b/tests/bootstrap.bat @@ -28,22 +28,8 @@ EXIT /B 0 ECHO Building Nim [%NIM_BRANCH%] (%NIM_ARCH%) in %NIM_DIR% git clone https://github.com/nim-lang/Nim.git "%CD%\%NIM_DIR%" CD "%CD%\%NIM_DIR%" -IF "%NIM_BRANCH%" == "version-1-6" ( - git checkout "%NIM_BRANCH%" - git clone --depth 1 https://github.com/nim-lang/csources_v1 - CD csources_v1 -) ELSE ( - git checkout devel - git clone --depth 1 https://github.com/nim-lang/csources_v2 - CD csources_v2 -) - -IF "%NIM_ARCH%" == "amd64" (CALL build64.bat) ELSE (CALL build32.bat) -CD .. -ECHO CSOURCES NIM DONE -bin\nim c --skipParentCfg --noNimblePath --skipUserCfg -d:release koch -koch boot -d:release --skipParentCfg -koch nimble --skipParentCfg +git checkout "%NIM_BRANCH%" +CALL build_all.bat CD .. EXIT /B 0 From 43a5ce592e8bb4cf4fa2a7f8fcc00f3535260645 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Wed, 24 Dec 2025 04:13:17 +0200 Subject: [PATCH 05/13] Disable fail-fast. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bebb505..6c8863a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: build: strategy: - fail-fast: true + fail-fast: false max-parallel: 20 matrix: branch: [master] From 9169f6fafd9df278128b0857e351571ed4da8781 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 12:40:38 +0200 Subject: [PATCH 06/13] Recover 2.0 and 1.6 Nim version compatibility. --- nimcrypto/bcmode.nim | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/nimcrypto/bcmode.nim b/nimcrypto/bcmode.nim index 28c1ff7..d4dedba 100644 --- a/nimcrypto/bcmode.nim +++ b/nimcrypto/bcmode.nim @@ -969,6 +969,9 @@ func decrypt*[T]( # of decent BearSSL project . # Copyright (c) 2016 Thomas Pornin +const + GCMBlockSize = 128 div 8 + func bmul64(x, y: uint64): uint64 = var x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3: uint64 x0 = x and 0x1111111111111111'u64 @@ -1105,7 +1108,7 @@ func init*[T]( ## You can see examples of usage GCM mode here ``examples/gcm.nim``. mixin init # GCM supports only 128bit block ciphers - doAssert(ctx.sizeBlock() == (128 div 8)) + doAssert(ctx.sizeBlock() == GCMBlockSize) doAssert(len(key) >= ctx.sizeKey()) burnMem(ctx) ctx.cipher.init(key) @@ -1114,10 +1117,10 @@ func init*[T]( ctx.y[0 ..< 12] = iv.toOpenArray(0, 11) inc128(ctx.y) else: - var tmp: array[ctx.sizeBlock(), byte] + var tmp: array[GCMBlockSize, byte] ghash(ctx.y, ctx.h, iv) beStore32(tmp, 12, uint32(len(iv) shl 3)) - ghash(ctx.y, ctx.h, tmp.toOpenArray(0, ctx.sizeBlock() - 1)) + ghash(ctx.y, ctx.h, tmp.toOpenArray(0, GCMBlockSize - 1)) ctx.cipher.encrypt(ctx.y, ctx.basectr) ctx.aadlen = uint64(len(aad)) ctx.datalen = 0 @@ -1138,16 +1141,16 @@ func encrypt*[T]( doAssert(len(input) <= len(output)) var - ectr: array[ctx.sizeBlock(), byte] + ectr: array[GCMBlockSize, byte] length = len(input) offset = 0 while length > 0: let uselen = - if int(ctx.coffset) + length < ctx.sizeBlock(): + if int(ctx.coffset) + length < GCMBlockSize: length else: - ctx.sizeBlock() - int(ctx.coffset) + GCMBlockSize - int(ctx.coffset) if ctx.coffset == 0: inc128(ctx.y) ctx.cipher.encrypt(ctx.y, ectr) @@ -1157,9 +1160,9 @@ func encrypt*[T]( ctx.hbuf[int(ctx.coffset) + i] = ch length -= uselen offset += uselen - ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(ctx.sizeBlock() - 1) + ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(GCMBlockSize - 1) if ctx.coffset == 0: - ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, ctx.sizeBlock - 1)) + ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, GCMBlockSize - 1)) ctx.datalen += uint64(len(input)) @@ -1177,16 +1180,16 @@ func decrypt*[T]( doAssert(len(input) <= len(output)) var - ectr: array[ctx.sizeBlock(), byte] + ectr: array[GCMBlockSize, byte] length = len(input) offset = 0 while length > 0: let uselen = - if int(ctx.coffset) + length < ctx.sizeBlock(): + if int(ctx.coffset) + length < GCMBlockSize: length else: - ctx.sizeBlock() - int(ctx.coffset) + GCMBlockSize - int(ctx.coffset) if ctx.coffset == 0: inc128(ctx.y) ctx.cipher.encrypt(ctx.y, ectr) @@ -1196,9 +1199,9 @@ func decrypt*[T]( ctx.hbuf[int(ctx.coffset) + i] = input[offset + i] length -= uselen offset += uselen - ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(ctx.sizeBlock() - 1) + ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(GCMBlockSize - 1) if ctx.coffset == 0: - ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, ctx.sizeBlock - 1)) + ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, GCMBlockSize - 1)) ctx.datalen += uint64(len(input)) @@ -1210,10 +1213,10 @@ func getTag*[T]( ## ``tag``. ## ## Note that maximum size of ``tag`` is 128 bits (16 bytes). - var workbuf: array[ctx.sizeBlock(), byte] + var workbuf: array[GCMBlockSize, byte] let taglen = len(tag) - uselen = if taglen < ctx.sizeBlock(): taglen else: ctx.sizeBlock() + uselen = if taglen < GCMBlockSize: taglen else: GCMBlockSize if ctx.coffset != 0: ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, int(ctx.coffset) - 1)) @@ -1226,7 +1229,7 @@ func getTag*[T]( for i in 0 ..< uselen: tag[i] = tag[i] xor ctx.buf[i] -func getTag*[T](ctx: var GCM[T]): array[ctx.sizeBlock(), byte] {.noinit.} = +func getTag*[T](ctx: var GCM[T]): array[GCMBlockSize, byte] {.noinit.} = ## Obtain authentication tag from ``GCM[T]`` context ``ctx`` and return it as ## result array. getTag(ctx, result) @@ -1260,8 +1263,8 @@ func decrypt*[T]( ## ## Note that length of ``input`` must be less or equal to length of ## ``output``. Length of ``input`` must not be zero. - var dataTag: array[ctx.sizeBlock(), byte] - let uselen = min(len(tag), ctx.sizeBlock) + var dataTag: array[GCMBlockSize, byte] + let uselen = min(len(tag), GCMBlockSize) ctx.decrypt(input, output) ctx.getTag(dataTag.toOpenArray(0, uselen - 1)) equalMemFull( From 3d757f1b958a49e6c90c10aa5e20c96e8c11c14e Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 15:19:33 +0200 Subject: [PATCH 07/13] Attempt to fix x86 Windows builds. --- tests/bootstrap.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bootstrap.bat b/tests/bootstrap.bat index 87ebd2e..50af9c8 100644 --- a/tests/bootstrap.bat +++ b/tests/bootstrap.bat @@ -29,6 +29,7 @@ ECHO Building Nim [%NIM_BRANCH%] (%NIM_ARCH%) in %NIM_DIR% git clone https://github.com/nim-lang/Nim.git "%CD%\%NIM_DIR%" CD "%CD%\%NIM_DIR%" git checkout "%NIM_BRANCH%" +SET ARCH=%NIM_ARCH% CALL build_all.bat CD .. EXIT /B 0 From d174a1a776824bbe8cb71f2df63bfe52dee74557 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 15:23:02 +0200 Subject: [PATCH 08/13] One more environment variable change. --- tests/bootstrap.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bootstrap.bat b/tests/bootstrap.bat index 50af9c8..f1242f8 100644 --- a/tests/bootstrap.bat +++ b/tests/bootstrap.bat @@ -30,6 +30,7 @@ git clone https://github.com/nim-lang/Nim.git "%CD%\%NIM_DIR%" CD "%CD%\%NIM_DIR%" git checkout "%NIM_BRANCH%" SET ARCH=%NIM_ARCH% +SET PROCESSOR_ARCHITECTURE=%NIM_ARCH% CALL build_all.bat CD .. EXIT /B 0 From 4874af8dd7388a74b11e18ee147bcb5b9e57b3a7 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 15:32:04 +0200 Subject: [PATCH 09/13] Proper variable values. --- tests/bootstrap.bat | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/bootstrap.bat b/tests/bootstrap.bat index f1242f8..af63aa6 100644 --- a/tests/bootstrap.bat +++ b/tests/bootstrap.bat @@ -30,7 +30,13 @@ git clone https://github.com/nim-lang/Nim.git "%CD%\%NIM_DIR%" CD "%CD%\%NIM_DIR%" git checkout "%NIM_BRANCH%" SET ARCH=%NIM_ARCH% -SET PROCESSOR_ARCHITECTURE=%NIM_ARCH% +IF "%NIM_ARCH%" == "amd64" ( + SET ARCH=64 + SET PROCESSOR_ARCHITECTURE="amd64" +) ELSE ( + SET ARCH=32 + SET PROCESSOR_ARCHITECTURE="x86" +) CALL build_all.bat CD .. EXIT /B 0 From 4fa47f4385f4c8bfd70f4efd96aa270772cc26e9 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 18:19:03 +0200 Subject: [PATCH 10/13] Fix Linux i386. --- tests/bootstrap.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/bootstrap.sh b/tests/bootstrap.sh index 0d3cef8..1599a71 100755 --- a/tests/bootstrap.sh +++ b/tests/bootstrap.sh @@ -15,7 +15,14 @@ function build_nim { git clone https://github.com/nim-lang/Nim.git ${NIM_DIR} cd "${NIM_DIR}" git checkout "${NIM_BRANCH}" - ./build_all.sh + if [ "${NIM_ARCH}" = "i386" ]; then + NIM_CPU="i386" + elif [ "${NIM_ARCH}" = "arm64" ]; then + NIM_CPU="arm64" + else + NIM_CPU="amd64" + fi + ./build_all.sh ucpu=${NIM_CPU} cd .. } From da8ecc9fcd7c21302d2d2223d3888708f07b9379 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 20:33:23 +0200 Subject: [PATCH 11/13] Update Linux i386. --- .github/workflows/ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c8863a..0d1f01b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,25 @@ jobs: path: nimcrypto submodules: false + - name: Install build dependencies (Linux i386) + if: runner.os == 'Linux' && matrix.target.cpu == 'i386' + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update -qq + sudo DEBIAN_FRONTEND='noninteractive' apt-get install \ + --no-install-recommends -yq gcc-multilib g++-multilib libssl-dev:i386 + mkdir -p external/bin + cat << EOF > external/bin/gcc + #!/bin/bash + exec $(which gcc) -m32 -mno-adx "\$@" + EOF + cat << EOF > external/bin/g++ + #!/bin/bash + exec $(which g++) -m32 -mno-adx "\$@" + EOF + chmod 755 external/bin/gcc external/bin/g++ + echo '${{ github.workspace }}/external/bin' >> $GITHUB_PATH + - name: Restore MinGW-W64 (Windows) from cache if: runner.os == 'Windows' id: windows-mingw-cache From ca3e509f4c57e17df9d8eb00c217b4a8d7c30dba Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 26 Dec 2025 23:12:03 +0200 Subject: [PATCH 12/13] Add CC environment variable. --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d1f01b..9313a47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,6 +127,8 @@ jobs: - name: Build Nim and associated tools shell: bash + env: + CC: gcc run: | pwd ls -la From e7e1a9dd3aafa0b5f408e46488d2aa7a475d03b8 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Sat, 27 Dec 2025 01:45:11 +0200 Subject: [PATCH 13/13] Temporarily disable x86/orc/1.6 tests. --- nimcrypto.nimble | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nimcrypto.nimble b/nimcrypto.nimble index 3b4fa40..a92aa67 100644 --- a/nimcrypto.nimble +++ b/nimcrypto.nimble @@ -21,8 +21,15 @@ task test, "Runs the test suite": nimc & " c -f -d:danger -r tests/", nimc & " c -f -d:danger --threads:on -r tests/", nimc & " c -f --passC=\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" --passL:\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" -r tests/", - nimc & " c -f --mm:orc --threads:on -r tests/" ] + + # Nim version 1.6 compiler crashes with `out of memory` on i386. + when defined(cpu64): + testCommands.add nimc & " c -f --mm:orc --threads:on -r tests/" + else: + when (NimMajor, NimMinor) >= (2, 0): + testCommands.add nimc & " c -f --mm:orc --threads:on -r tests/" + when (NimMajor, NimMinor) >= (2, 0): testCommands.add nimc & " c -f --mm:refc --threads:off --passC=\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" --passL:\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" -r tests/" testCommands.add nimc & " c -f --mm:refc --threads:on --passC=\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" --passL:\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" -r tests/"