Initial commit

This commit is contained in:
Miguel Oliveira 2022-03-01 20:08:55 -03:00
commit 3ea90b786b
No known key found for this signature in database
GPG key ID: 2C2BE789E1377025
8 changed files with 1495 additions and 0 deletions

50
.vscode/settings.json vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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