commit 3ea90b786b0bc86c04f433a850fa82c595a4a96c Author: Miguel Oliveira Date: Tue Mar 1 20:08:55 2022 -0300 Initial commit diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..eb1af71 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,50 @@ +{ + "Lua.diagnostics.disable": [ + "err-esc", + "lowercase-global", + "deprecated", + "redefined-local" + ], + "Lua.diagnostics.severity": { + "redefined-local": "Warning" + }, + "Lua.diagnostics.globals": [ + "printError", + "sleep", + "read", + "write", + "print", + "colours", + "colors", + "commands", + "disk", + "fs", + "gps", + "help", + "http", + "paintutils", + "parallel", + "peripheral", + "rednet", + "redstone", + "keys", + "settings", + "shell", + "multishell", + "term", + "textutils", + "turtle", + "pocket", + "vector", + "bit32", + "window", + "_CC_DEFAULT_SETTINGS", + "_HOST", + "_VERSION", + "_", + "_ENV", + "ccemux", + "wordlib" + ], + "Lua.runtime.version": "Lua 5.1" +} diff --git a/aead.lua b/aead.lua new file mode 100644 index 0000000..ee640eb --- /dev/null +++ b/aead.lua @@ -0,0 +1,67 @@ +local expect = require "cc.expect".expect + +local chacha20 = require "ecnet.primitives.chacha20" +local poly1305 = require "ecnet.primitives.poly1305" + +local bxor = bit32.bxor +local bor = bit32.bor + +local function encrypt(key, nonce, message, aad, rounds) + expect(1, key, "string") + assert(#key == 32, "key length must be 32") + expect(2, nonce, "string") + assert(#nonce == 12, "nonce length must be 12") + expect(3, message, "string") + expect(4, aad, "string") + expect(5, rounds, "number", "nil") + rounds = rounds or 20 + + -- Generate auth key and encrypt. + local msgLong = ("\0"):rep(64) .. message + local ctxLong = chacha20.crypt(key, nonce, msgLong, rounds, 0) + local authKey = ctxLong:sub(1, 32) + local ciphertext = ctxLong:sub(65) + + -- Authenticate. + local pad1 = ("\0"):rep(-#aad % 16) + local pad2 = ("\0"):rep(-#ciphertext % 16) + local aadLen = (" 0 then + -- Root is a parent, digest last block now and merge parents. + local stateFlags = flags + stateStart + CHUNK_END + local mergeCv = compress(stateCv, last, stateT, lastLen, stateFlags) + for i = #stateCvs, 2, -1 do + local block = merge(stateCvs[i], mergeCv) + mergeCv = compress(iv, block, 0, 64, flags + PARENT) + end + + -- Set output state. + outCv = iv + outBlock = merge(stateCvs[1], mergeCv) + outLen = 64 + outFlags = flags + ROOT + PARENT + else + -- Root block is in the first chunk, set output state. + outCv = stateCv + outBlock = last + outLen = lastLen + outFlags = flags + stateStart + CHUNK_END + ROOT + end + + -- Expand output. + local out = {} + for i = 0, len / 64 do + local md = compress(outCv, outBlock, i, outLen, outFlags, true) + out[i + 1] = ("= 1, "length must be a positive integer") + + return blake3(IV, 0, message, len) +end + +function mod.digestKeyed(key, message, len) + expect(1, key, "string") + assert(#key == 32, "key length must be 32") + expect(2, message, "string") + expect(3, len, "number", "nil") + len = len or 32 + assert(len % 1 == 0 and len >= 1, "length must be a positive integer") + + return blake3({("= 1, "length must be a positive integer") + + return blake3(iv, DERIVE_KEY_MATERIAL, material, len) + end +end + +return mod diff --git a/chacha20.lua b/chacha20.lua new file mode 100644 index 0000000..5041bfc --- /dev/null +++ b/chacha20.lua @@ -0,0 +1,111 @@ +local expect = require "cc.expect".expect + +local bxor = bit32.bxor +local rol = bit32.lrotate + +local mod = {} + +function mod.crypt(key, nonce, message, rounds, offset) + expect(1, key, "string") + assert(#key == 32, "key length must be 32") + expect(2, nonce, "string") + assert(#nonce == 12, "nonce length must be 12") + expect(3, message, "string") + expect(4, rounds, "number", "nil") + rounds = rounds or 20 + assert(rounds % 2 == 0, "round number must be even") + assert(rounds >= 8 and rounds <= 20, "round number must be in 8..20") + expect(5, offset, "number", "nil") + offset = offset or 1 + assert(offset % 1 == 0 and offset >= 0, "offset must be an integer >= 0") + assert(#message + 64 * offset < 2 ^ 37, "offset too large") + + -- Build the state block. + local i0, i1, i2, i3 = 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 + local k0, k1, k2, k3, k4, k5, k6, k7 = ("= 2 ^ 22 - 19 + then + a11 = 0 + a10 = 0 + a09 = 0 + a08 = 0 + a07 = 0 + a06 = 0 + a05 = 0 + a04 = 0 + a03 = 0 + a02 = 0 + a01 = 0 + a00 = a00 - (2 ^ 22 - 19) + end + + -- Encode. + -- TODO this can be improved. + local bytes = {} + local acc = a00 + local function putBytes(n) + for _ = 1, n do + local byte = acc % 256 + bytes[#bytes + 1] = byte + acc = (acc - byte) / 256 + end + end + + putBytes(2) acc = acc + a01 / 2 ^ 16 + putBytes(3) acc = acc + a02 / 2 ^ 40 + putBytes(3) acc = acc + a03 / 2 ^ 64 + putBytes(2) acc = acc + a04 / 2 ^ 80 + putBytes(3) acc = acc + a05 / 2 ^ 104 + putBytes(3) acc = acc + a06 / 2 ^ 128 + putBytes(2) acc = acc + a07 / 2 ^ 144 + putBytes(3) acc = acc + a08 / 2 ^ 168 + putBytes(3) acc = acc + a09 / 2 ^ 192 + putBytes(2) acc = acc + a10 / 2 ^ 208 + putBytes(3) acc = acc + a11 / 2 ^ 232 + putBytes(3) + + return string.char(unpack(bytes)) +end + +local function decode(b) + local w00, w01, w02, w03, w04, w05, w06, w07, w08, w09, w10, w11 = + (" Q[i] then + break + end + end + + for i = 1, 11 do + c[i] = c[i] - Q[i] + end + + -- c >= q means c - q >= 0. + -- Since q < 2²⁸⁸, c < 2 * q means c - q < q < 2²⁸⁸ = 2^(24 * (11 + 1)). + -- c's limbs fit in [-2²⁵..2²⁵], since subtraction adds at most one bit. + local cc = carry(c) + cc[12] = nil -- cc < q implies that cc[12] = 0. + return cc +end + +--- Adds two scalars mod q. +-- +-- If the two operands are in Montgomery form, returns the correct result also +-- in Montgomery form, since (2²⁶⁴ * a) + (2²⁶⁴ * b) ≡ 2²⁶⁴ * (a + b) (mod q). +-- +-- @tparam {number...} a A number a < q as 11 limbs in [0..2²⁴). +-- @tparam {number...} b A number b < q as 11 limbs in [0..2²⁴). +-- @treturn {number...} a + b mod q as 11 limbs in [0..2²⁴). +-- +local function add(a, b) + return reduce(intAdd(a, b)) +end + +--- Negates a scalar mod q. +-- +-- @tparam {number...} a A number a < q as 11 limbs in [0..2²⁴). +-- @treturn {number...} -a mod q as 11 limbs in [0..2²⁴). +-- +local function neg(a) + local c = {} + for i = 1, 11 do + c[i] = Q[i] - a[i] + end + + -- 0 < c < q implies 0 < q - c < q < 2²⁸⁸ = 2^(24 * (11 + 1)). + -- c's limbs fit in [-2²⁵..2²⁵], since subtraction adds at most one bit. + -- q - c < q also implies q - c < 2 * q. + return reduce(carry(c)) +end + +--- Given a scalar a, computes 2⁻²⁶⁴ a mod q. +-- +-- @tparam {number...} a A number a < 2²⁶⁴ * q as 22 limbs in [0..2²⁴). +-- @treturn {number...} 2⁻²⁶⁴ * a mod q as 11 limbs in [0..2²⁴). +-- +local function redc(a) + local al = {unpack(a, 1, 11)} + local mm = intMul(al, T0) + local m = {unpack(mm, 1, 11)} + local mr = intMul(m, Q) + local t = intAdd(a, mr) + return reduce({unpack(t, 12, 23)}) +end + +--- Converts a scalar a into its Montgomery form 2²⁶⁴ a mod q. +-- +-- @tparam {number...} a A number a as 11 limbs in [0..2²⁴). +-- @treturn {number...} 2²⁶⁴ * a mod q as 11 limbs in [0..2²⁴). +-- +local function montgomery(a) + -- a < 2²⁶⁴ and T1 < q imply that a * T1 < 2²⁶⁴ * q. + return redc(intMul(a, T1)) +end + +--- Converts a scalar a from its Montgomery form 2²⁶⁴ a mod q. +-- +-- @tparam {number...} a A number a < q as 11 limbs in [0..2²⁴). +-- @treturn {number...} 2⁻²⁶⁴ * a mod q as 11 limbs in [0..2²⁴). +-- +local function demontgomery(a) + a = {unpack(a)} + for i = 12, 22 do a[i] = 0 end + -- a < q < 2²⁶⁴ * q. + return redc(a) +end + +--- Converts a Lua number to a scalar. +-- +-- @tparam number n A number n in [0..2²⁴). +-- @treturn {number...} 2²⁶⁴ * n mod q as 11 limbs in [0..2²⁴). +-- +local function num(n) + return montgomery({n, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) +end + +--- Multiplies two scalars in Montgomery form mod q. +-- +-- @tparam {number...} a 2²⁶⁴ * a' mod q as 11 limbs in [0..2²⁴). +-- @tparam {number...} b 2²⁶⁴ * b' mod q as 11 limbs in [0..2²⁴). +-- @treturn {number...} 2²⁶⁴ * a' * b' mod q as 11 limbs in [0..2²⁴). +-- +local function mul(a, b) + -- {a, b} < q so a * b < q² < 2²⁶⁴ * q. + return redc(intMul(a, b)) +end + +--- Inverts a scalar mod q. +-- +-- Computation of the inverse requires several multiplications. +-- +-- @tparam {number...} a A number 2²⁶⁴ * a mod q as 11 limbs in [0..2²⁴). +-- @treturn[1] {number...} 2²⁶⁴ * a⁻¹ mod q as 11 limbs in [0..2²⁴). +-- @treturn[2] {number...} 0 if the argument is 0, which has no inverse. +-- +local function invert(a) + local r = num(1) + for i = 1, #INVEXP_BITS do + if INVEXP_BITS[i] == 1 then + r = mul(r, a) + end + a = mul(a, a) + end + return r +end + +--- Encodes a scalar. +-- +-- @tparam {number...} a A number 2²⁶⁴ * a mod q as 11 limbs in [0..2²⁴). +-- @treturn string The 32-byte string encoding of a. +-- +local function encode(a) + return ("= 2 ^ 22 - 5 + then + h5 = 0 + h4 = 0 + h3 = 0 + h2 = 0 + h1 = 0 + h0 = h0 - (2 ^ 22 - 5) + end + + -- Decode s. + local s0, s1, s2, s3, s4, s5 = ("