Initial commit
This commit is contained in:
commit
3ea90b786b
50
.vscode/settings.json
vendored
Normal file
50
.vscode/settings.json
vendored
Normal file
|
@ -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"
|
||||
}
|
67
aead.lua
Normal file
67
aead.lua
Normal file
|
@ -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 = ("<I8"):pack(#aad)
|
||||
local ctxLen = ("<I8"):pack(#ciphertext)
|
||||
local combined = aad .. pad1 .. ciphertext .. pad2 .. aadLen .. ctxLen
|
||||
local tag = poly1305.mac(authKey, combined)
|
||||
|
||||
return ciphertext, tag
|
||||
end
|
||||
|
||||
local function decrypt(key, nonce, tag, ciphertext, 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, ciphertext, "string")
|
||||
expect(4, aad, "string")
|
||||
expect(5, rounds, "number", "nil")
|
||||
rounds = rounds or 20
|
||||
|
||||
-- Generate auth key and decrypt.
|
||||
local ctxLong = ("\0"):rep(64) .. ciphertext
|
||||
local msgLong = chacha20.crypt(key, nonce, ctxLong, rounds, 0)
|
||||
local authKey = msgLong:sub(1, 32)
|
||||
local message = msgLong:sub(65)
|
||||
|
||||
-- Check tag.
|
||||
local pad1 = ("\0"):rep(-#aad % 16)
|
||||
local pad2 = ("\0"):rep(-#ciphertext % 16)
|
||||
local aadLen = ("<I8"):pack(#aad)
|
||||
local ctxLen = ("<I8"):pack(#ciphertext)
|
||||
local combined = aad .. pad1 .. ciphertext .. pad2 .. aadLen .. ctxLen
|
||||
local t1, t2, t3, t4 = ("<I4I4I4I4"):unpack(tag)
|
||||
local u1, u2, u3, u4 = ("<I4I4I4I4"):unpack(poly1305.mac(authKey, combined))
|
||||
local eq = bor(bxor(t1, u1), bxor(t2, u2), bxor(t3, u3), bxor(t4, u4))
|
||||
if eq == 0 then return message end
|
||||
end
|
||||
|
||||
return {
|
||||
encrypt = encrypt,
|
||||
decrypt = decrypt,
|
||||
}
|
236
blake3.lua
Normal file
236
blake3.lua
Normal file
|
@ -0,0 +1,236 @@
|
|||
local expect = require "cc.expect".expect
|
||||
|
||||
local unpack = unpack or table.unpack
|
||||
local bxor = bit32.bxor
|
||||
local rol = bit32.lrotate
|
||||
|
||||
local CHUNK_START = 0x01
|
||||
local CHUNK_END = 0x02
|
||||
local PARENT = 0x04
|
||||
local ROOT = 0x08
|
||||
local KEYED_HASH = 0x10
|
||||
local DERIVE_KEY_CONTEXT = 0x20
|
||||
local DERIVE_KEY_MATERIAL = 0x40
|
||||
|
||||
local IV = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
}
|
||||
|
||||
local function compress(h, msg, t, v14, v15, full)
|
||||
local h00, h01, h02, h03, h04, h05, h06, h07 = unpack(h)
|
||||
local v00, v01, v02, v03 = h00, h01, h02, h03
|
||||
local v04, v05, v06, v07 = h04, h05, h06, h07
|
||||
local v08, v09, v10, v11 = 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a
|
||||
local v12 = t % 2 ^ 32
|
||||
local v13 = (t - v12) * 2 ^ -32
|
||||
|
||||
local m00, m01, m02, m03, m04, m05, m06, m07,
|
||||
m08, m09, m10, m11, m12, m13, m14, m15 = unpack(msg)
|
||||
|
||||
local tmp
|
||||
for i = 1, 7 do
|
||||
v00 = v00 + v04 + m00 v12 = rol(bxor(v12, v00), 16)
|
||||
v08 = v08 + v12 v04 = rol(bxor(v04, v08), 20)
|
||||
v00 = v00 + v04 + m01 v12 = rol(bxor(v12, v00), 24)
|
||||
v08 = v08 + v12 v04 = rol(bxor(v04, v08), 25)
|
||||
|
||||
v01 = v01 + v05 + m02 v13 = rol(bxor(v13, v01), 16)
|
||||
v09 = v09 + v13 v05 = rol(bxor(v05, v09), 20)
|
||||
v01 = v01 + v05 + m03 v13 = rol(bxor(v13, v01), 24)
|
||||
v09 = v09 + v13 v05 = rol(bxor(v05, v09), 25)
|
||||
|
||||
v02 = v02 + v06 + m04 v14 = rol(bxor(v14, v02), 16)
|
||||
v10 = v10 + v14 v06 = rol(bxor(v06, v10), 20)
|
||||
v02 = v02 + v06 + m05 v14 = rol(bxor(v14, v02), 24)
|
||||
v10 = v10 + v14 v06 = rol(bxor(v06, v10), 25)
|
||||
|
||||
v03 = v03 + v07 + m06 v15 = rol(bxor(v15, v03), 16)
|
||||
v11 = v11 + v15 v07 = rol(bxor(v07, v11), 20)
|
||||
v03 = v03 + v07 + m07 v15 = rol(bxor(v15, v03), 24)
|
||||
v11 = v11 + v15 v07 = rol(bxor(v07, v11), 25)
|
||||
|
||||
v00 = v00 + v05 + m08 v15 = rol(bxor(v15, v00), 16)
|
||||
v10 = v10 + v15 v05 = rol(bxor(v05, v10), 20)
|
||||
v00 = v00 + v05 + m09 v15 = rol(bxor(v15, v00), 24)
|
||||
v10 = v10 + v15 v05 = rol(bxor(v05, v10), 25)
|
||||
|
||||
v01 = v01 + v06 + m10 v12 = rol(bxor(v12, v01), 16)
|
||||
v11 = v11 + v12 v06 = rol(bxor(v06, v11), 20)
|
||||
v01 = v01 + v06 + m11 v12 = rol(bxor(v12, v01), 24)
|
||||
v11 = v11 + v12 v06 = rol(bxor(v06, v11), 25)
|
||||
|
||||
v02 = v02 + v07 + m12 v13 = rol(bxor(v13, v02), 16)
|
||||
v08 = v08 + v13 v07 = rol(bxor(v07, v08), 20)
|
||||
v02 = v02 + v07 + m13 v13 = rol(bxor(v13, v02), 24)
|
||||
v08 = v08 + v13 v07 = rol(bxor(v07, v08), 25)
|
||||
|
||||
v03 = v03 + v04 + m14 v14 = rol(bxor(v14, v03), 16)
|
||||
v09 = v09 + v14 v04 = rol(bxor(v04, v09), 20)
|
||||
v03 = v03 + v04 + m15 v14 = rol(bxor(v14, v03), 24)
|
||||
v09 = v09 + v14 v04 = rol(bxor(v04, v09), 25)
|
||||
|
||||
if i ~= 7 then
|
||||
tmp = m02
|
||||
m02 = m03
|
||||
m03 = m10
|
||||
m10 = m12
|
||||
m12 = m09
|
||||
m09 = m11
|
||||
m11 = m05
|
||||
m05 = m00
|
||||
m00 = tmp
|
||||
|
||||
tmp = m06
|
||||
m06 = m04
|
||||
m04 = m07
|
||||
m07 = m13
|
||||
m13 = m14
|
||||
m14 = m15
|
||||
m15 = m08
|
||||
m08 = m01
|
||||
m01 = tmp
|
||||
end
|
||||
end
|
||||
|
||||
if full then
|
||||
return {
|
||||
bxor(v00, v08), bxor(v01, v09), bxor(v02, v10), bxor(v03, v11),
|
||||
bxor(v04, v12), bxor(v05, v13), bxor(v06, v14), bxor(v07, v15),
|
||||
bxor(v08, h00), bxor(v09, h01), bxor(v10, h02), bxor(v11, h03),
|
||||
bxor(v12, h04), bxor(v13, h05), bxor(v14, h06), bxor(v15, h07),
|
||||
}
|
||||
else
|
||||
return {
|
||||
bxor(v00, v08), bxor(v01, v09), bxor(v02, v10), bxor(v03, v11),
|
||||
bxor(v04, v12), bxor(v05, v13), bxor(v06, v14), bxor(v07, v15),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local function merge(cvl, cvr)
|
||||
for i = 1, 8 do cvl[i + 8] = cvr[i] end
|
||||
return cvl
|
||||
end
|
||||
|
||||
local function blake3(iv, flags, msg, len)
|
||||
-- Set up the state.
|
||||
local stateCvs = {}
|
||||
local stateCv = iv
|
||||
local stateT = 0
|
||||
local stateN = 0
|
||||
local stateStart = CHUNK_START
|
||||
local stateEnd = 0
|
||||
|
||||
-- Digest complete blocks.
|
||||
for i = 1, #msg - 64, 64 do
|
||||
-- Compress the block.
|
||||
local block = {("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4"):unpack(msg, i)}
|
||||
local stateFlags = flags + stateStart + stateEnd
|
||||
stateCv = compress(stateCv, block, stateT, 64, stateFlags)
|
||||
stateStart = 0
|
||||
stateN = stateN + 1
|
||||
|
||||
if stateN == 15 then
|
||||
-- Last block in chunk.
|
||||
stateEnd = CHUNK_END
|
||||
elseif stateN == 16 then
|
||||
-- Chunk complete, merge.
|
||||
local mergeCv = stateCv
|
||||
local mergeAmt = stateT + 1
|
||||
while mergeAmt % 2 == 0 do
|
||||
local block = merge(table.remove(stateCvs), mergeCv)
|
||||
mergeCv = compress(iv, block, 0, 64, flags + PARENT)
|
||||
mergeAmt = mergeAmt / 2
|
||||
end
|
||||
|
||||
-- Push back.
|
||||
table.insert(stateCvs, mergeCv)
|
||||
|
||||
-- Update state back to next chunk.
|
||||
stateCv = iv
|
||||
stateT = stateT + 1
|
||||
stateN = 0
|
||||
stateStart = CHUNK_START
|
||||
stateEnd = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- Pad the last message block.
|
||||
local lastLen = #msg == 0 and 0 or (#msg - 1) % 64 + 1
|
||||
local padded = msg:sub(-lastLen) .. ("\0"):rep(64)
|
||||
local last = {("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4"):unpack(padded)}
|
||||
|
||||
-- Prepare output expansion state.
|
||||
local outCv, outBlock, outLen, outFlags
|
||||
if stateT > 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] = ("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4"):pack(unpack(md))
|
||||
end
|
||||
|
||||
return table.concat(out):sub(1, len)
|
||||
end
|
||||
|
||||
local mod = {}
|
||||
|
||||
function mod.digest(message, len)
|
||||
expect(1, message, "string")
|
||||
expect(2, len, "number", "nil")
|
||||
len = len or 32
|
||||
assert(len % 1 == 0 and len >= 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({("<I4I4I4I4I4I4I4I4"):unpack(key)}, KEYED_HASH, message, len)
|
||||
end
|
||||
|
||||
function mod.deriveKey(context)
|
||||
expect(1, context, "string")
|
||||
|
||||
local hash = blake3(IV, DERIVE_KEY_CONTEXT, context, 32)
|
||||
local iv = {("<I4I4I4I4I4I4I4I4"):unpack(hash)}
|
||||
|
||||
return function(material, len)
|
||||
expect(1, material, "string")
|
||||
expect(2, len, "number", "nil")
|
||||
len = len or 32
|
||||
assert(len % 1 == 0 and len >= 1, "length must be a positive integer")
|
||||
|
||||
return blake3(iv, DERIVE_KEY_MATERIAL, material, len)
|
||||
end
|
||||
end
|
||||
|
||||
return mod
|
111
chacha20.lua
Normal file
111
chacha20.lua
Normal file
|
@ -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 = ("<I4I4I4I4I4I4I4I4"):unpack(key)
|
||||
local cr, n0, n1, n2 = offset, ("<I4I4I4"):unpack(nonce)
|
||||
|
||||
-- Pad the message.
|
||||
local padded = message .. ("\0"):rep(-#message % 64)
|
||||
|
||||
-- Expand and combine.
|
||||
local out = {}
|
||||
local idx = 1
|
||||
for i = 1, #padded / 64 do
|
||||
-- Copy the block.
|
||||
local s00, s01, s02, s03 = i0, i1, i2, i3
|
||||
local s04, s05, s06, s07 = k0, k1, k2, k3
|
||||
local s08, s09, s10, s11 = k4, k5, k6, k7
|
||||
local s12, s13, s14, s15 = cr, n0, n1, n2
|
||||
|
||||
-- Iterate.
|
||||
for _ = 1, rounds, 2 do
|
||||
s00 = s00 + s04 s12 = rol(bxor(s12, s00), 16)
|
||||
s08 = s08 + s12 s04 = rol(bxor(s04, s08), 12)
|
||||
s00 = s00 + s04 s12 = rol(bxor(s12, s00), 8)
|
||||
s08 = s08 + s12 s04 = rol(bxor(s04, s08), 7)
|
||||
|
||||
s01 = s01 + s05 s13 = rol(bxor(s13, s01), 16)
|
||||
s09 = s09 + s13 s05 = rol(bxor(s05, s09), 12)
|
||||
s01 = s01 + s05 s13 = rol(bxor(s13, s01), 8)
|
||||
s09 = s09 + s13 s05 = rol(bxor(s05, s09), 7)
|
||||
|
||||
s02 = s02 + s06 s14 = rol(bxor(s14, s02), 16)
|
||||
s10 = s10 + s14 s06 = rol(bxor(s06, s10), 12)
|
||||
s02 = s02 + s06 s14 = rol(bxor(s14, s02), 8)
|
||||
s10 = s10 + s14 s06 = rol(bxor(s06, s10), 7)
|
||||
|
||||
s03 = s03 + s07 s15 = rol(bxor(s15, s03), 16)
|
||||
s11 = s11 + s15 s07 = rol(bxor(s07, s11), 12)
|
||||
s03 = s03 + s07 s15 = rol(bxor(s15, s03), 8)
|
||||
s11 = s11 + s15 s07 = rol(bxor(s07, s11), 7)
|
||||
|
||||
s00 = s00 + s05 s15 = rol(bxor(s15, s00), 16)
|
||||
s10 = s10 + s15 s05 = rol(bxor(s05, s10), 12)
|
||||
s00 = s00 + s05 s15 = rol(bxor(s15, s00), 8)
|
||||
s10 = s10 + s15 s05 = rol(bxor(s05, s10), 7)
|
||||
|
||||
s01 = s01 + s06 s12 = rol(bxor(s12, s01), 16)
|
||||
s11 = s11 + s12 s06 = rol(bxor(s06, s11), 12)
|
||||
s01 = s01 + s06 s12 = rol(bxor(s12, s01), 8)
|
||||
s11 = s11 + s12 s06 = rol(bxor(s06, s11), 7)
|
||||
|
||||
s02 = s02 + s07 s13 = rol(bxor(s13, s02), 16)
|
||||
s08 = s08 + s13 s07 = rol(bxor(s07, s08), 12)
|
||||
s02 = s02 + s07 s13 = rol(bxor(s13, s02), 8)
|
||||
s08 = s08 + s13 s07 = rol(bxor(s07, s08), 7)
|
||||
|
||||
s03 = s03 + s04 s14 = rol(bxor(s14, s03), 16)
|
||||
s09 = s09 + s14 s04 = rol(bxor(s04, s09), 12)
|
||||
s03 = s03 + s04 s14 = rol(bxor(s14, s03), 8)
|
||||
s09 = s09 + s14 s04 = rol(bxor(s04, s09), 7)
|
||||
end
|
||||
|
||||
-- Decode message block.
|
||||
local m00, m01, m02, m03, m04, m05, m06, m07
|
||||
local m08, m09, m10, m11, m12, m13, m14, m15
|
||||
|
||||
m00, m01, m02, m03, m04, m05, m06, m07,
|
||||
m08, m09, m10, m11, m12, m13, m14, m15, idx =
|
||||
("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4"):unpack(padded, idx)
|
||||
|
||||
-- Feed-forward and combine.
|
||||
out[i] = ("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4"):pack(
|
||||
bxor(m00, s00 + i0), bxor(m01, s01 + i1),
|
||||
bxor(m02, s02 + i2), bxor(m03, s03 + i3),
|
||||
bxor(m04, s04 + k0), bxor(m05, s05 + k1),
|
||||
bxor(m06, s06 + k2), bxor(m07, s07 + k3),
|
||||
bxor(m08, s08 + k4), bxor(m09, s09 + k5),
|
||||
bxor(m10, s10 + k6), bxor(m11, s11 + k7),
|
||||
bxor(m12, s12 + cr), bxor(m13, s13 + n0),
|
||||
bxor(m14, s14 + n1), bxor(m15, s15 + n2)
|
||||
)
|
||||
|
||||
-- Increment counter.
|
||||
cr = cr + 1
|
||||
end
|
||||
|
||||
return table.concat(out):sub(1, #message)
|
||||
end
|
||||
|
||||
return mod
|
508
fp.lua
Normal file
508
fp.lua
Normal file
|
@ -0,0 +1,508 @@
|
|||
local unpack = unpack or table.unpack
|
||||
|
||||
local function add(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11 = unpack(b)
|
||||
return {
|
||||
a00 + b00,
|
||||
a01 + b01,
|
||||
a02 + b02,
|
||||
a03 + b03,
|
||||
a04 + b04,
|
||||
a05 + b05,
|
||||
a06 + b06,
|
||||
a07 + b07,
|
||||
a08 + b08,
|
||||
a09 + b09,
|
||||
a10 + b10,
|
||||
a11 + b11,
|
||||
}
|
||||
end
|
||||
|
||||
local function sub(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11 = unpack(b)
|
||||
return {
|
||||
a00 - b00,
|
||||
a01 - b01,
|
||||
a02 - b02,
|
||||
a03 - b03,
|
||||
a04 - b04,
|
||||
a05 - b05,
|
||||
a06 - b06,
|
||||
a07 - b07,
|
||||
a08 - b08,
|
||||
a09 - b09,
|
||||
a10 - b10,
|
||||
a11 - b11,
|
||||
}
|
||||
end
|
||||
|
||||
local function kmul(a, k)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11
|
||||
|
||||
-- Multiply.
|
||||
c00 = a00 * k
|
||||
c01 = a01 * k
|
||||
c02 = a02 * k
|
||||
c03 = a03 * k
|
||||
c04 = a04 * k
|
||||
c05 = a05 * k
|
||||
c06 = a06 * k
|
||||
c07 = a07 * k
|
||||
c08 = a08 * k
|
||||
c09 = a09 * k
|
||||
c10 = a10 * k
|
||||
c11 = a11 * k
|
||||
|
||||
-- Carry and reduce.
|
||||
a11 = c11 % 2 ^ 255 c00 = c00 + (c11 - a11) * (19 / 2 ^ 255)
|
||||
|
||||
a00 = c00 % 2 ^ 22 c01 = c01 + (c00 - a00)
|
||||
a01 = c01 % 2 ^ 43 c02 = c02 + (c01 - a01)
|
||||
a02 = c02 % 2 ^ 64 c03 = c03 + (c02 - a02)
|
||||
a03 = c03 % 2 ^ 85 c04 = c04 + (c03 - a03)
|
||||
a04 = c04 % 2 ^ 107 c05 = c05 + (c04 - a04)
|
||||
a05 = c05 % 2 ^ 128 c06 = c06 + (c05 - a05)
|
||||
a06 = c06 % 2 ^ 149 c07 = c07 + (c06 - a06)
|
||||
a07 = c07 % 2 ^ 170 c08 = c08 + (c07 - a07)
|
||||
a08 = c08 % 2 ^ 192 c09 = c09 + (c08 - a08)
|
||||
a09 = c09 % 2 ^ 213 c10 = c10 + (c09 - a09)
|
||||
a10 = c10 % 2 ^ 234 c11 = a11 + (c10 - a10)
|
||||
|
||||
a11 = c11 % 2 ^ 255 a00 = a00 + (c11 - a11) * (19 / 2 ^ 255)
|
||||
|
||||
return {a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11}
|
||||
end
|
||||
|
||||
local function mul(a, b)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11 = unpack(b)
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11
|
||||
|
||||
-- Multiply high half.
|
||||
c00 = a11 * b01
|
||||
+ a10 * b02
|
||||
+ a09 * b03
|
||||
+ a08 * b04
|
||||
+ a07 * b05
|
||||
+ a06 * b06
|
||||
+ a05 * b07
|
||||
+ a04 * b08
|
||||
+ a03 * b09
|
||||
+ a02 * b10
|
||||
+ a01 * b11
|
||||
c01 = a11 * b02
|
||||
+ a10 * b03
|
||||
+ a09 * b04
|
||||
+ a08 * b05
|
||||
+ a07 * b06
|
||||
+ a06 * b07
|
||||
+ a05 * b08
|
||||
+ a04 * b09
|
||||
+ a03 * b10
|
||||
+ a02 * b11
|
||||
c02 = a11 * b03
|
||||
+ a10 * b04
|
||||
+ a09 * b05
|
||||
+ a08 * b06
|
||||
+ a07 * b07
|
||||
+ a06 * b08
|
||||
+ a05 * b09
|
||||
+ a04 * b10
|
||||
+ a03 * b11
|
||||
c03 = a11 * b04
|
||||
+ a10 * b05
|
||||
+ a09 * b06
|
||||
+ a08 * b07
|
||||
+ a07 * b08
|
||||
+ a06 * b09
|
||||
+ a05 * b10
|
||||
+ a04 * b11
|
||||
c04 = a11 * b05
|
||||
+ a10 * b06
|
||||
+ a09 * b07
|
||||
+ a08 * b08
|
||||
+ a07 * b09
|
||||
+ a06 * b10
|
||||
+ a05 * b11
|
||||
c05 = a11 * b06
|
||||
+ a10 * b07
|
||||
+ a09 * b08
|
||||
+ a08 * b09
|
||||
+ a07 * b10
|
||||
+ a06 * b11
|
||||
c06 = a11 * b07
|
||||
+ a10 * b08
|
||||
+ a09 * b09
|
||||
+ a08 * b10
|
||||
+ a07 * b11
|
||||
c07 = a11 * b08
|
||||
+ a10 * b09
|
||||
+ a09 * b10
|
||||
+ a08 * b11
|
||||
c08 = a11 * b09
|
||||
+ a10 * b10
|
||||
+ a09 * b11
|
||||
c09 = a11 * b10
|
||||
+ a10 * b11
|
||||
c10 = a11 * b11
|
||||
|
||||
-- Multiply low half with reduction.
|
||||
c00 = c00 * (19 / 2 ^ 255)
|
||||
+ a00 * b00
|
||||
c01 = c01 * (19 / 2 ^ 255)
|
||||
+ a01 * b00
|
||||
+ a00 * b01
|
||||
c02 = c02 * (19 / 2 ^ 255)
|
||||
+ a02 * b00
|
||||
+ a01 * b01
|
||||
+ a00 * b02
|
||||
c03 = c03 * (19 / 2 ^ 255)
|
||||
+ a03 * b00
|
||||
+ a02 * b01
|
||||
+ a01 * b02
|
||||
+ a00 * b03
|
||||
c04 = c04 * (19 / 2 ^ 255)
|
||||
+ a04 * b00
|
||||
+ a03 * b01
|
||||
+ a02 * b02
|
||||
+ a01 * b03
|
||||
+ a00 * b04
|
||||
c05 = c05 * (19 / 2 ^ 255)
|
||||
+ a05 * b00
|
||||
+ a04 * b01
|
||||
+ a03 * b02
|
||||
+ a02 * b03
|
||||
+ a01 * b04
|
||||
+ a00 * b05
|
||||
c06 = c06 * (19 / 2 ^ 255)
|
||||
+ a06 * b00
|
||||
+ a05 * b01
|
||||
+ a04 * b02
|
||||
+ a03 * b03
|
||||
+ a02 * b04
|
||||
+ a01 * b05
|
||||
+ a00 * b06
|
||||
c07 = c07 * (19 / 2 ^ 255)
|
||||
+ a07 * b00
|
||||
+ a06 * b01
|
||||
+ a05 * b02
|
||||
+ a04 * b03
|
||||
+ a03 * b04
|
||||
+ a02 * b05
|
||||
+ a01 * b06
|
||||
+ a00 * b07
|
||||
c08 = c08 * (19 / 2 ^ 255)
|
||||
+ a08 * b00
|
||||
+ a07 * b01
|
||||
+ a06 * b02
|
||||
+ a05 * b03
|
||||
+ a04 * b04
|
||||
+ a03 * b05
|
||||
+ a02 * b06
|
||||
+ a01 * b07
|
||||
+ a00 * b08
|
||||
c09 = c09 * (19 / 2 ^ 255)
|
||||
+ a09 * b00
|
||||
+ a08 * b01
|
||||
+ a07 * b02
|
||||
+ a06 * b03
|
||||
+ a05 * b04
|
||||
+ a04 * b05
|
||||
+ a03 * b06
|
||||
+ a02 * b07
|
||||
+ a01 * b08
|
||||
+ a00 * b09
|
||||
c10 = c10 * (19 / 2 ^ 255)
|
||||
+ a10 * b00
|
||||
+ a09 * b01
|
||||
+ a08 * b02
|
||||
+ a07 * b03
|
||||
+ a06 * b04
|
||||
+ a05 * b05
|
||||
+ a04 * b06
|
||||
+ a03 * b07
|
||||
+ a02 * b08
|
||||
+ a01 * b09
|
||||
+ a00 * b10
|
||||
c11 = a11 * b00
|
||||
+ a10 * b01
|
||||
+ a09 * b02
|
||||
+ a08 * b03
|
||||
+ a07 * b04
|
||||
+ a06 * b05
|
||||
+ a05 * b06
|
||||
+ a04 * b07
|
||||
+ a03 * b08
|
||||
+ a02 * b09
|
||||
+ a01 * b10
|
||||
+ a00 * b11
|
||||
|
||||
-- Carry and reduce.
|
||||
a10 = c10 % 2 ^ 234 c11 = c11 + (c10 - a10)
|
||||
a11 = c11 % 2 ^ 255 c00 = c00 + (c11 - a11) * (19 / 2 ^ 255)
|
||||
|
||||
a00 = c00 % 2 ^ 22 c01 = c01 + (c00 - a00)
|
||||
a01 = c01 % 2 ^ 43 c02 = c02 + (c01 - a01)
|
||||
a02 = c02 % 2 ^ 64 c03 = c03 + (c02 - a02)
|
||||
a03 = c03 % 2 ^ 85 c04 = c04 + (c03 - a03)
|
||||
a04 = c04 % 2 ^ 107 c05 = c05 + (c04 - a04)
|
||||
a05 = c05 % 2 ^ 128 c06 = c06 + (c05 - a05)
|
||||
a06 = c06 % 2 ^ 149 c07 = c07 + (c06 - a06)
|
||||
a07 = c07 % 2 ^ 170 c08 = c08 + (c07 - a07)
|
||||
a08 = c08 % 2 ^ 192 c09 = c09 + (c08 - a08)
|
||||
a09 = c09 % 2 ^ 213 c10 = a10 + (c09 - a09)
|
||||
a10 = c10 % 2 ^ 234 c11 = a11 + (c10 - a10)
|
||||
|
||||
a11 = c11 % 2 ^ 255 a00 = a00 + (c11 - a11) * (19 / 2 ^ 255)
|
||||
|
||||
return {a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11}
|
||||
end
|
||||
|
||||
local function square(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
local d00, d01, d02, d03, d04, d05, d06, d07, d08, d09, d10
|
||||
local c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11
|
||||
|
||||
-- Compute 2a.
|
||||
d00 = a00 + a00
|
||||
d01 = a01 + a01
|
||||
d02 = a02 + a02
|
||||
d03 = a03 + a03
|
||||
d04 = a04 + a04
|
||||
d05 = a05 + a05
|
||||
d06 = a06 + a06
|
||||
d07 = a07 + a07
|
||||
d08 = a08 + a08
|
||||
d09 = a09 + a09
|
||||
d10 = a10 + a10
|
||||
|
||||
-- Multiply high half.
|
||||
c00 = a11 * d01
|
||||
+ a10 * d02
|
||||
+ a09 * d03
|
||||
+ a08 * d04
|
||||
+ a07 * d05
|
||||
+ a06 * a06
|
||||
c01 = a11 * d02
|
||||
+ a10 * d03
|
||||
+ a09 * d04
|
||||
+ a08 * d05
|
||||
+ a07 * d06
|
||||
c02 = a11 * d03
|
||||
+ a10 * d04
|
||||
+ a09 * d05
|
||||
+ a08 * d06
|
||||
+ a07 * a07
|
||||
c03 = a11 * d04
|
||||
+ a10 * d05
|
||||
+ a09 * d06
|
||||
+ a08 * d07
|
||||
c04 = a11 * d05
|
||||
+ a10 * d06
|
||||
+ a09 * d07
|
||||
+ a08 * a08
|
||||
c05 = a11 * d06
|
||||
+ a10 * d07
|
||||
+ a09 * d08
|
||||
c06 = a11 * d07
|
||||
+ a10 * d08
|
||||
+ a09 * a09
|
||||
c07 = a11 * d08
|
||||
+ a10 * d09
|
||||
c08 = a11 * d09
|
||||
+ a10 * a10
|
||||
c09 = a11 * d10
|
||||
c10 = a11 * a11
|
||||
|
||||
-- Multiply low half with reduction.
|
||||
c00 = c00 * (19 / 2 ^ 255)
|
||||
+ a00 * a00
|
||||
c01 = c01 * (19 / 2 ^ 255)
|
||||
+ a01 * d00
|
||||
c02 = c02 * (19 / 2 ^ 255)
|
||||
+ a02 * d00
|
||||
+ a01 * a01
|
||||
c03 = c03 * (19 / 2 ^ 255)
|
||||
+ a03 * d00
|
||||
+ a02 * d01
|
||||
c04 = c04 * (19 / 2 ^ 255)
|
||||
+ a04 * d00
|
||||
+ a03 * d01
|
||||
+ a02 * a02
|
||||
c05 = c05 * (19 / 2 ^ 255)
|
||||
+ a05 * d00
|
||||
+ a04 * d01
|
||||
+ a03 * d02
|
||||
c06 = c06 * (19 / 2 ^ 255)
|
||||
+ a06 * d00
|
||||
+ a05 * d01
|
||||
+ a04 * d02
|
||||
+ a03 * a03
|
||||
c07 = c07 * (19 / 2 ^ 255)
|
||||
+ a07 * d00
|
||||
+ a06 * d01
|
||||
+ a05 * d02
|
||||
+ a04 * d03
|
||||
c08 = c08 * (19 / 2 ^ 255)
|
||||
+ a08 * d00
|
||||
+ a07 * d01
|
||||
+ a06 * d02
|
||||
+ a05 * d03
|
||||
+ a04 * a04
|
||||
c09 = c09 * (19 / 2 ^ 255)
|
||||
+ a09 * d00
|
||||
+ a08 * d01
|
||||
+ a07 * d02
|
||||
+ a06 * d03
|
||||
+ a05 * d04
|
||||
c10 = c10 * (19 / 2 ^ 255)
|
||||
+ a10 * d00
|
||||
+ a09 * d01
|
||||
+ a08 * d02
|
||||
+ a07 * d03
|
||||
+ a06 * d04
|
||||
+ a05 * a05
|
||||
c11 = a11 * d00
|
||||
+ a10 * d01
|
||||
+ a09 * d02
|
||||
+ a08 * d03
|
||||
+ a07 * d04
|
||||
+ a06 * d05
|
||||
|
||||
-- Carry and reduce.
|
||||
a10 = c10 % 2 ^ 234 c11 = c11 + (c10 - a10)
|
||||
a11 = c11 % 2 ^ 255 c00 = c00 + (c11 - a11) * (19 / 2 ^ 255)
|
||||
|
||||
a00 = c00 % 2 ^ 22 c01 = c01 + (c00 - a00)
|
||||
a01 = c01 % 2 ^ 43 c02 = c02 + (c01 - a01)
|
||||
a02 = c02 % 2 ^ 64 c03 = c03 + (c02 - a02)
|
||||
a03 = c03 % 2 ^ 85 c04 = c04 + (c03 - a03)
|
||||
a04 = c04 % 2 ^ 107 c05 = c05 + (c04 - a04)
|
||||
a05 = c05 % 2 ^ 128 c06 = c06 + (c05 - a05)
|
||||
a06 = c06 % 2 ^ 149 c07 = c07 + (c06 - a06)
|
||||
a07 = c07 % 2 ^ 170 c08 = c08 + (c07 - a07)
|
||||
a08 = c08 % 2 ^ 192 c09 = c09 + (c08 - a08)
|
||||
a09 = c09 % 2 ^ 213 c10 = a10 + (c09 - a09)
|
||||
a10 = c10 % 2 ^ 234 c11 = a11 + (c10 - a10)
|
||||
|
||||
a11 = c11 % 2 ^ 255 a00 = a00 + (c11 - a11) * (19 / 2 ^ 255)
|
||||
|
||||
return {a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11}
|
||||
end
|
||||
|
||||
local function nsquare(a, n)
|
||||
for _ = 1, n do a = square(a) end
|
||||
return a
|
||||
end
|
||||
|
||||
local function invert(a)
|
||||
local a2 = square(a)
|
||||
local a9 = mul(a, nsquare(a2, 2))
|
||||
local a11 = mul(a9, a2)
|
||||
local x5 = mul(square(a11), a9)
|
||||
local x10 = mul(nsquare(x5, 5), x5)
|
||||
local x20 = mul(nsquare(x10, 10), x10)
|
||||
local x40 = mul(nsquare(x20, 20), x20)
|
||||
local x50 = mul(nsquare(x40, 10), x10)
|
||||
local x100 = mul(nsquare(x50, 50), x50)
|
||||
local x200 = mul(nsquare(x100, 100), x100)
|
||||
local x250 = mul(nsquare(x200, 50), x50)
|
||||
return mul(nsquare(x250, 5), a11)
|
||||
end
|
||||
|
||||
local function encode(a)
|
||||
local a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11 = unpack(a)
|
||||
|
||||
-- Canonicalize.
|
||||
if a11 == (2 ^ 21 - 1) * 2 ^ 234
|
||||
and a10 == (2 ^ 21 - 1) * 2 ^ 213
|
||||
and a09 == (2 ^ 21 - 1) * 2 ^ 192
|
||||
and a08 == (2 ^ 22 - 1) * 2 ^ 170
|
||||
and a07 == (2 ^ 21 - 1) * 2 ^ 149
|
||||
and a06 == (2 ^ 21 - 1) * 2 ^ 128
|
||||
and a05 == (2 ^ 21 - 1) * 2 ^ 107
|
||||
and a04 == (2 ^ 22 - 1) * 2 ^ 85
|
||||
and a03 == (2 ^ 21 - 1) * 2 ^ 64
|
||||
and a02 == (2 ^ 21 - 1) * 2 ^ 43
|
||||
and a01 == (2 ^ 21 - 1) * 2 ^ 22
|
||||
and a00 >= 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 =
|
||||
("<I3I3I2I3I3I2I3I3I2I3I3I2"):unpack(b)
|
||||
|
||||
w11 = w11 % 2 ^ 15
|
||||
|
||||
local out = {
|
||||
w00,
|
||||
w01 * 2 ^ 24,
|
||||
w02 * 2 ^ 48,
|
||||
w03 * 2 ^ 64,
|
||||
w04 * 2 ^ 88,
|
||||
w05 * 2 ^ 112,
|
||||
w06 * 2 ^ 128,
|
||||
w07 * 2 ^ 152,
|
||||
w08 * 2 ^ 176,
|
||||
w09 * 2 ^ 192,
|
||||
w10 * 2 ^ 216,
|
||||
w11 * 2 ^ 240,
|
||||
}
|
||||
|
||||
return kmul(out, 1)
|
||||
end
|
||||
|
||||
return {
|
||||
add = add,
|
||||
sub = sub,
|
||||
kmul = kmul,
|
||||
mul = mul,
|
||||
square = square,
|
||||
invert = invert,
|
||||
encode = encode,
|
||||
decode = decode,
|
||||
}
|
310
fq.lua
Normal file
310
fq.lua
Normal file
|
@ -0,0 +1,310 @@
|
|||
--- Arithmetic on Curve25519's scalar field.
|
||||
--
|
||||
-- @module ecnet.primitives.scalar
|
||||
--
|
||||
|
||||
local util = require "ecnet.util"
|
||||
|
||||
local rebaseLE = util.rebaseLE
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
--- The scalar field's order, q.
|
||||
local Q = {
|
||||
16110573,
|
||||
06494812,
|
||||
14047250,
|
||||
10680220,
|
||||
14612958,
|
||||
00000020,
|
||||
00000000,
|
||||
00000000,
|
||||
00000000,
|
||||
00000000,
|
||||
00004096,
|
||||
}
|
||||
|
||||
local INVEXP_BITS = nil
|
||||
do
|
||||
local Q2 = {unpack(Q)}
|
||||
Q2[1] = Q2[1] - 2
|
||||
INVEXP_BITS = rebaseLE(Q2, 2 ^ 24, 2)
|
||||
end
|
||||
|
||||
--- The first Montgomery precomputed constant, -q⁻¹ mod 2²⁶⁴.
|
||||
local T0 = {
|
||||
05537307,
|
||||
01942290,
|
||||
16765621,
|
||||
16628356,
|
||||
10618610,
|
||||
07072433,
|
||||
03735459,
|
||||
01369940,
|
||||
15276086,
|
||||
13038191,
|
||||
13409718,
|
||||
}
|
||||
|
||||
--- The second Montgomery precomputed constant, 2⁵²⁸ mod q.
|
||||
local T1 = {
|
||||
11711996,
|
||||
01747860,
|
||||
08326961,
|
||||
03814718,
|
||||
01859974,
|
||||
13327461,
|
||||
16105061,
|
||||
07590423,
|
||||
04050668,
|
||||
08138906,
|
||||
00000283,
|
||||
}
|
||||
|
||||
--- Carries a number in base 2²⁴.
|
||||
--
|
||||
-- @tparam {number...} a A number 0 <= a < 2 ^ (24 * (#a + 1)) as limbs in
|
||||
-- [-2⁵²..2⁵²].
|
||||
-- @treturn {number...} a as #a + 1 limbs in [0..2²⁴).
|
||||
--
|
||||
local function carry(a)
|
||||
local c = {unpack(a)}
|
||||
c[#c + 1] = 0
|
||||
for i = 1, #c - 1 do
|
||||
local val = c[i]
|
||||
local rem = val % 2 ^ 24
|
||||
local quot = (val - rem) / 2 ^ 24
|
||||
c[i + 1] = c[i + 1] + quot
|
||||
c[i] = rem
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
--- Adds two numbers.
|
||||
--
|
||||
-- @tparam {number...} a An array limbs in [0..2²⁴).
|
||||
-- @tparam {number...} b An array of #a limbs in [0..2²⁴).
|
||||
-- @treturn {number...} a + b as #a + 1 limbs in [0..2²⁴).
|
||||
--
|
||||
local function intAdd(a, b)
|
||||
local c = {}
|
||||
for i = 1, #a do
|
||||
c[i] = a[i] + b[i]
|
||||
end
|
||||
|
||||
-- c's limbs fit in [-2²⁵..2²⁵], since addition adds at most one bit.
|
||||
return carry(c)
|
||||
end
|
||||
|
||||
--- Multiplies two numbers.
|
||||
--
|
||||
-- @tparam {number...} a An array of 11 limbs in [0..2²⁴).
|
||||
-- @tparam {number...} b An array of 11 limbs in [0..2²⁴).
|
||||
-- @treturn {number...} a * b as 22 limbs in [0..2²⁴).
|
||||
--
|
||||
local function intMul(a, b)
|
||||
local c = {}
|
||||
for i = 1, 21 do c[i] = 0 end
|
||||
for i = 1, 11 do
|
||||
for j = 1, 11 do
|
||||
local k = i + j - 1
|
||||
c[k] = c[k] + a[i] * b[j]
|
||||
end
|
||||
end
|
||||
|
||||
-- {a, b} < 2²⁶⁴ means that c < 2⁵²⁸ = 2 ^ (24 * (21 + 1)).
|
||||
-- c's limbs are smaller than 2⁴⁸ * 11 < 2⁵², since multiplication doubles
|
||||
-- bit length, and 11 multiplied limbs are added together.
|
||||
return carry(c)
|
||||
end
|
||||
|
||||
--- Reduces a number modulo q.
|
||||
--
|
||||
-- @tparam {number...} a A number a < 2 * q as 12 limbs in [0..2²⁴).
|
||||
-- @treturn {number...} a mod q as 11 limbs in [0..2²⁴).
|
||||
--
|
||||
local function reduce(a)
|
||||
local c = {unpack(a, 1, 11)} -- a < 2 * q implies that a[12] = 0.
|
||||
|
||||
-- Return c if c < r.
|
||||
for i = 11, 1, -1 do
|
||||
if c[i] < Q[i] then
|
||||
return c
|
||||
elseif c[i] > 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 ("<I3I3I3I3I3I3I3I3I3I3I2"):pack(unpack(demontgomery(a)))
|
||||
end
|
||||
|
||||
--- Decodes a scalar.
|
||||
--
|
||||
-- @tparam string str A 32-byte string encoding some little-endian number a.
|
||||
-- @treturn {number...} 2²⁶⁴ * a mod q as 11 limbs in [0..2²⁴).
|
||||
--
|
||||
local function decode(str)
|
||||
local dec = {("<I3I3I3I3I3I3I3I3I3I3I2"):unpack(str)} dec[12] = nil
|
||||
return montgomery(dec)
|
||||
end
|
||||
|
||||
--- Decodes a scalar from a "wide" string.
|
||||
--
|
||||
-- @tparam string str A 64-byte string encoding some little-endian number a.
|
||||
-- @treturn 2²⁶⁴ * a mod q as 11 limbs in [0..2²⁴).
|
||||
--
|
||||
local function decodeWide(str)
|
||||
local low = {("<I3I3I3I3I3I3I3I3I3I3I3"):unpack(str)} low[12] = nil
|
||||
local high = {("<I3I3I3I3I3I3I3I3I3I3I1"):unpack(str, 34)} high[12] = nil
|
||||
return add(montgomery(low), montgomery(montgomery(high)))
|
||||
end
|
||||
|
||||
--- Returns a scalar in binary.
|
||||
--
|
||||
-- @tparam {number...} a A number a < q as limbs in [0..2²⁴).
|
||||
-- @treturn {number...} 2⁻²⁶⁴ * a mod q as limbs in [0..2).
|
||||
--
|
||||
local function bits(a)
|
||||
return rebaseLE(demontgomery(a), 2 ^ 24, 2)
|
||||
end
|
||||
|
||||
return {
|
||||
num = num,
|
||||
carry = carry,
|
||||
intAdd = intAdd,
|
||||
intMul = intMul,
|
||||
reduce = reduce,
|
||||
add = add,
|
||||
neg = neg,
|
||||
redc = redc,
|
||||
montgomery = montgomery,
|
||||
demontgomery = demontgomery,
|
||||
mul = mul,
|
||||
invert = invert,
|
||||
encode = encode,
|
||||
decode = decode,
|
||||
decodeWide = decodeWide,
|
||||
bits = bits,
|
||||
}
|
126
poly1305.lua
Normal file
126
poly1305.lua
Normal file
|
@ -0,0 +1,126 @@
|
|||
local expect = require "cc.expect".expect
|
||||
|
||||
local band = bit32.band
|
||||
|
||||
local mod = {}
|
||||
|
||||
function mod.mac(key, message)
|
||||
expect(1, key, "string")
|
||||
assert(#key == 32, "key length must be 32")
|
||||
expect(2, message, "string")
|
||||
|
||||
-- Pad message.
|
||||
local pbplen = #message - 15
|
||||
if #message % 16 ~= 0 then
|
||||
message = message .. "\1"
|
||||
message = message .. ("\0"):rep(-#message % 16)
|
||||
end
|
||||
|
||||
-- Decode r.
|
||||
local r0, t1, r2, r3, t4, r5 = ("<I3I3I2I3I3I2"):unpack(key)
|
||||
|
||||
-- Clamp and shift.
|
||||
t1 = band(t1, 0xfffc0f) * 2 ^ 24
|
||||
r2 = band(r2, 0x000fff) * 2 ^ 48
|
||||
r3 = band(r3, 0xfffffc) * 2 ^ 64
|
||||
t4 = band(t4, 0xfffc0f) * 2 ^ 88
|
||||
r5 = band(r5, 0x000fff) * 2 ^ 112
|
||||
|
||||
-- Split some words to fit.
|
||||
local r1 = t1 % 2 ^ 44 r2 = r2 + (t1 - r1)
|
||||
local r4 = t4 % 2 ^ 109 r5 = r5 + (t4 - r4)
|
||||
|
||||
-- Digest.
|
||||
local h0, h1, h2, h3, h4, h5 = 0, 0, 0, 0, 0, 0
|
||||
for i = 1, #message, 16 do
|
||||
-- Decode message block.
|
||||
local m0, m1, m2, m3, m4, m5 = ("<I3I3I3I2I3I2"):unpack(message, i)
|
||||
|
||||
-- Shift and add to accumulator.
|
||||
h0 = h0 + m0
|
||||
h1 = h1 + m1 * 2 ^ 24
|
||||
h2 = h2 + m2 * 2 ^ 48
|
||||
h3 = h3 + m3 * 2 ^ 72
|
||||
h4 = h4 + m4 * 2 ^ 88
|
||||
h5 = h5 + m5 * 2 ^ 112
|
||||
|
||||
-- Apply per-block padding when applicable.
|
||||
if i <= pbplen then
|
||||
h5 = h5 + 2 ^ 128
|
||||
end
|
||||
|
||||
-- Multiply accumulator by r.
|
||||
local g00 = h0 * r0
|
||||
local g01 = h1 * r0 + h0 * r1
|
||||
local g02 = h2 * r0 + h1 * r1 + h0 * r2
|
||||
local g03 = h3 * r0 + h2 * r1 + h1 * r2 + h0 * r3
|
||||
local g04 = h4 * r0 + h3 * r1 + h2 * r2 + h1 * r3 + h0 * r4
|
||||
local g05 = h5 * r0 + h4 * r1 + h3 * r2 + h2 * r3 + h1 * r4 + h0 * r5
|
||||
local g06 = h5 * r1 + h4 * r2 + h3 * r3 + h2 * r4 + h1 * r5
|
||||
local g07 = h5 * r2 + h4 * r3 + h3 * r4 + h2 * r5
|
||||
local g08 = h5 * r3 + h4 * r4 + h3 * r5
|
||||
local g09 = h5 * r4 + h4 * r5
|
||||
local g10 = h5 * r5
|
||||
|
||||
-- Carry and reduce.
|
||||
h5 = g05 % 2 ^ 130 g06 = g06 + (g05 - h5)
|
||||
|
||||
g00 = g00 + g06 * (5 / 2 ^ 130)
|
||||
g01 = g01 + g07 * (5 / 2 ^ 130)
|
||||
g02 = g02 + g08 * (5 / 2 ^ 130)
|
||||
g03 = g03 + g09 * (5 / 2 ^ 130)
|
||||
g04 = g04 + g10 * (5 / 2 ^ 130)
|
||||
|
||||
h0 = g00 % 2 ^ 22 g01 = g01 + (g00 - h0)
|
||||
h1 = g01 % 2 ^ 44 g02 = g02 + (g01 - h1)
|
||||
h2 = g02 % 2 ^ 65 g03 = g03 + (g02 - h2)
|
||||
h3 = g03 % 2 ^ 87 g04 = g04 + (g03 - h3)
|
||||
h4 = g04 % 2 ^ 109 g05 = h5 + (g04 - h4)
|
||||
h5 = g05 % 2 ^ 130 h0 = h0 + (g05 - h5) * (5 / 2 ^ 130)
|
||||
end
|
||||
|
||||
-- Canonicalize.
|
||||
if h5 == (2 ^ 21 - 1) * 2 ^ 109
|
||||
and h4 == (2 ^ 22 - 1) * 2 ^ 87
|
||||
and h3 == (2 ^ 22 - 1) * 2 ^ 65
|
||||
and h2 == (2 ^ 21 - 1) * 2 ^ 44
|
||||
and h1 == (2 ^ 22 - 1) * 2 ^ 22
|
||||
and h0 >= 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 = ("<I3I3I3I2I3I2"):unpack(key, 17)
|
||||
|
||||
-- Add s and carry.
|
||||
h0 = h0 + s0
|
||||
h1 = h1 + s1 * 2 ^ 24
|
||||
h2 = h2 + s2 * 2 ^ 48
|
||||
h3 = h3 + s3 * 2 ^ 72
|
||||
h4 = h4 + s4 * 2 ^ 88
|
||||
h5 = h5 + s5 * 2 ^ 112
|
||||
|
||||
local t0 = h0 % 2 ^ 16 h1 = h1 + (h0 - t0)
|
||||
local t1 = h1 % 2 ^ 40 h2 = h2 + (h1 - t1)
|
||||
local t2 = h2 % 2 ^ 64 h3 = h3 + (h2 - t2)
|
||||
local t3 = h3 % 2 ^ 80 h4 = h4 + (h3 - t3)
|
||||
local t4 = h4 % 2 ^ 104 h5 = h5 + (h4 - t4)
|
||||
local t5 = h5 % 2 ^ 128
|
||||
|
||||
-- Encode.
|
||||
t1 = t1 * 2 ^ -16
|
||||
t2 = t2 * 2 ^ -40
|
||||
t3 = t3 * 2 ^ -64
|
||||
t4 = t4 * 2 ^ -80
|
||||
t5 = t5 * 2 ^ -104
|
||||
|
||||
return ("<I2I3I3I2I3I3"):pack(t0, t1, t2, t3, t4, t5)
|
||||
end
|
||||
|
||||
return mod
|
87
x25519.lua
Normal file
87
x25519.lua
Normal file
|
@ -0,0 +1,87 @@
|
|||
local expect = require "cc.expect".expect
|
||||
local fp = require "ecnet.primitives.fp"
|
||||
|
||||
local add = fp.add
|
||||
local sub = fp.sub
|
||||
local kmul = fp.kmul
|
||||
local mul = fp.mul
|
||||
local square = fp.square
|
||||
local invert = fp.invert
|
||||
local encode = fp.encode
|
||||
local decode = fp.decode
|
||||
|
||||
local function step(dx, x1, z1, x2, z2)
|
||||
local a = add(x1, z1)
|
||||
local aa = square(a)
|
||||
local b = sub(x1, z1)
|
||||
local bb = square(b)
|
||||
local e = sub(aa, bb)
|
||||
local c = add(x2, z2)
|
||||
local d = sub(x2, z2)
|
||||
local da = mul(d, a)
|
||||
local cb = mul(c, b)
|
||||
local x4 = square(add(da, cb))
|
||||
local z4 = mul(dx, square(sub(da, cb)))
|
||||
local x3 = mul(aa, bb)
|
||||
local z3 = mul(e, add(bb, kmul(e, 121666)))
|
||||
return x3, z3, x4, z4
|
||||
end
|
||||
|
||||
local function x25519(dx, bits)
|
||||
local x1 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
local z1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
local x2, z2 = dx, x1
|
||||
|
||||
for i = #bits, 1, -1 do
|
||||
if bits[i] == 0 then
|
||||
x1, z1, x2, z2 = step(dx, x1, z1, x2, z2)
|
||||
else
|
||||
x2, z2, x1, z1 = step(dx, x2, z2, x1, z1)
|
||||
end
|
||||
end
|
||||
|
||||
return mul(x1, invert(z1))
|
||||
end
|
||||
|
||||
local function bits(str)
|
||||
-- Decode.
|
||||
local bytes = {str:byte(1, 32)}
|
||||
local out = {}
|
||||
for i = 1, 32 do
|
||||
local byte = bytes[i]
|
||||
for j = -7, 0 do
|
||||
local bit = byte % 2
|
||||
out[8 * i + j] = bit
|
||||
byte = (byte - bit) / 2
|
||||
end
|
||||
end
|
||||
|
||||
-- Clamp.
|
||||
out[1] = 0
|
||||
out[2] = 0
|
||||
out[3] = 0
|
||||
out[256] = 0
|
||||
out[255] = 1
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local mod = {}
|
||||
|
||||
function mod.publicKey(sk)
|
||||
expect(1, sk, "string")
|
||||
assert(#sk == 32, "secret key length must be 32")
|
||||
|
||||
return encode(x25519({9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, bits(sk)))
|
||||
end
|
||||
|
||||
function mod.exchange(sk, pk)
|
||||
expect(1, sk, "string")
|
||||
assert(#sk == 32, "secret key length must be 32")
|
||||
expect(2, pk, "string")
|
||||
assert(#pk == 32, "public key length must be 32")
|
||||
|
||||
return encode(x25519(decode(pk), bits(sk)))
|
||||
end
|
||||
|
||||
return mod
|
Loading…
Reference in a new issue