Initial commit

This commit is contained in:
2026-08-09 13:54:08 +03:00
commit eb12eb7a81
4 changed files with 891 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright © 2026 tema5002
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+566
View File
@@ -0,0 +1,566 @@
-- local curve25519 = require("curve25519")
-- curve25519(private_key, peer_public_value)
if not load("return (1>>1) == 0 and (1<<1) == 2 and (1&1) == 1 and (1|0) == 1") then
error("bitwise operators not available; need Lua 5.3+")
end
local kBottom25Bits = 0x1ffffff
local kBottom26Bits = 0x3ffffff
local kTop39Bits = 0xfffffffffe000000
local kTop38Bits = 0xfffffffffc000000
local function load_3(i, offset)
return i[1 + offset] | (i[2 + offset] << 8) | (i[3 + offset] << 16)
end
local function load_4(i, offset)
return i[1 + offset] | (i[2 + offset] << 8) | (i[3 + offset] << 16) | (i[4 + offset] << 24)
end
local function arshift(x, n)
n = n & 63
if n == 0 then return x end
if x >= 0 then
return x >> n
else
return (x >> n) | (~0 << (64 - n))
end
end
local function fe_frombytes(s)
local h = {
load_4(s, 0),
load_3(s, 4) << 6,
load_3(s, 7) << 5,
load_3(s, 10) << 3,
load_3(s, 13) << 2,
load_4(s, 16),
load_3(s, 20) << 7,
load_3(s, 23) << 5,
load_3(s, 26) << 4,
(load_3(s, 29) & 0x7fffff) << 2
}
local carry
carry = h[10] + (1 << 24); h[1] = h[1] + arshift(carry, 25) * 19; h[10] = h[10] - (carry & kTop39Bits)
carry = h[2] + (1 << 24); h[3] = h[3] + arshift(carry, 25); h[2] = h[2] - (carry & kTop39Bits)
carry = h[4] + (1 << 24); h[5] = h[5] + arshift(carry, 25); h[4] = h[4] - (carry & kTop39Bits)
carry = h[6] + (1 << 24); h[7] = h[7] + arshift(carry, 25); h[6] = h[6] - (carry & kTop39Bits)
carry = h[8] + (1 << 24); h[9] = h[9] + arshift(carry, 25); h[8] = h[8] - (carry & kTop39Bits)
carry = h[1] + (1 << 25); h[2] = h[2] + arshift(carry, 26); h[1] = h[1] - (carry & kTop38Bits)
carry = h[3] + (1 << 25); h[4] = h[4] + arshift(carry, 26); h[3] = h[3] - (carry & kTop38Bits)
carry = h[5] + (1 << 25); h[6] = h[6] + arshift(carry, 26); h[5] = h[5] - (carry & kTop38Bits)
carry = h[7] + (1 << 25); h[8] = h[8] + arshift(carry, 26); h[7] = h[7] - (carry & kTop38Bits)
carry = h[9] + (1 << 25); h[10] = h[10] + arshift(carry, 26); h[9] = h[9] - (carry & kTop38Bits)
return h
end
local function fe_tobytes(h)
local q
q = (19 * h[10] + (1 << 24)) >> 25
q = arshift(h[1] + q, 26)
q = arshift(h[2] + q, 25)
q = arshift(h[3] + q, 26)
q = arshift(h[4] + q, 25)
q = arshift(h[5] + q, 26)
q = arshift(h[6] + q, 25)
q = arshift(h[7] + q, 26)
q = arshift(h[8] + q, 25)
q = arshift(h[9] + q, 26)
q = arshift(h[10] + q, 25)
h[1] = h[1] + 19 * q
h[2] = h[2] + arshift(h[1], 26)
h[1] = h[1] & kBottom26Bits
h[3] = h[3] + arshift(h[2], 25)
h[2] = h[2] & kBottom25Bits
h[4] = h[4] + arshift(h[3], 26)
h[3] = h[3] & kBottom26Bits
h[5] = h[5] + arshift(h[4], 25)
h[4] = h[4] & kBottom25Bits
h[6] = h[6] + arshift(h[5], 26)
h[5] = h[5] & kBottom26Bits
h[7] = h[7] + arshift(h[6], 25)
h[6] = h[6] & kBottom25Bits
h[8] = h[8] + arshift(h[7], 26)
h[7] = h[7] & kBottom26Bits
h[9] = h[9] + arshift(h[8], 25)
h[8] = h[8] & kBottom25Bits
h[10] = h[10] + arshift(h[9], 26)
h[9] = h[9] & kBottom26Bits
h[10] = h[10] & kBottom25Bits
return {
(h[1] >> 0) & 0xff,
(h[1] >> 8) & 0xff,
(h[1] >> 16) & 0xff,
((h[1] >> 24) | (h[2] << 2)) & 0xff,
(h[2] >> 6) & 0xff,
(h[2] >> 14) & 0xff,
((h[2] >> 22) | (h[3] << 3)) & 0xff,
(h[3] >> 5) & 0xff,
(h[3] >> 13) & 0xff,
((h[3] >> 21) | (h[4] << 5)) & 0xff,
(h[4] >> 3) & 0xff,
(h[4] >> 11) & 0xff,
((h[4] >> 19) | (h[5] << 6)) & 0xff,
(h[5] >> 2) & 0xff,
(h[5] >> 10) & 0xff,
(h[5] >> 18) & 0xff,
(h[6] >> 0) & 0xff,
(h[6] >> 8) & 0xff,
(h[6] >> 16) & 0xff,
((h[6] >> 24) | (h[7] << 1)) & 0xff,
(h[7] >> 7) & 0xff,
(h[7] >> 15) & 0xff,
((h[7] >> 23) | (h[8] << 3)) & 0xff,
(h[8] >> 5) & 0xff,
(h[8] >> 13) & 0xff,
((h[8] >> 21) | (h[9] << 4)) & 0xff,
(h[9] >> 4) & 0xff,
(h[9] >> 12) & 0xff,
((h[9] >> 20) | (h[10] << 6)) & 0xff,
(h[10] >> 2) & 0xff,
(h[10] >> 10) & 0xff,
(h[10] >> 18) & 0xff
}
end
local function fe_add(f, g)
local h = {}
for i = 1, 10 do
h[i] = (f[i] + g[i])
end
return h
end
local function fe_addto(f, g)
for i = 1, 10 do
f[i] = (f[i] + g[i])
end
end
local function fe_sub(f, g)
local h = {}
for i = 1, 10 do
h[i] = (f[i] - g[i])
end
return h
end
local function fe_subto(f, g)
for i = 1, 10 do
f[i] = (f[i] - g[i])
end
end
local function fe_cswap(f, g, b)
b = 0 - b
for i = 1, 10 do
local x = f[i] ~ g[i]
x = x & b
f[i] = f[i] ~ x
g[i] = g[i] ~ x
end
end
local function fe_mul121666(f)
local h = {
f[1] * 121666,
f[2] * 121666,
f[3] * 121666,
f[4] * 121666,
f[5] * 121666,
f[6] * 121666,
f[7] * 121666,
f[8] * 121666,
f[9] * 121666,
f[10] * 121666
}
local carry
carry = h[10] + (1 << 24); h[1] = h[1] + arshift(carry, 25) * 19; h[10] = h[10] - (carry & kTop39Bits)
carry = h[2] + (1 << 24); h[3] = h[3] + arshift(carry, 25); h[2] = h[2] - (carry & kTop39Bits)
carry = h[4] + (1 << 24); h[5] = h[5] + arshift(carry, 25); h[4] = h[4] - (carry & kTop39Bits)
carry = h[6] + (1 << 24); h[7] = h[7] + arshift(carry, 25); h[6] = h[6] - (carry & kTop39Bits)
carry = h[8] + (1 << 24); h[9] = h[9] + arshift(carry, 25); h[8] = h[8] - (carry & kTop39Bits)
carry = h[1] + (1 << 25); h[2] = h[2] + arshift(carry, 26); h[1] = h[1] - (carry & kTop38Bits)
carry = h[3] + (1 << 25); h[4] = h[4] + arshift(carry, 26); h[3] = h[3] - (carry & kTop38Bits)
carry = h[5] + (1 << 25); h[6] = h[6] + arshift(carry, 26); h[5] = h[5] - (carry & kTop38Bits)
carry = h[7] + (1 << 25); h[8] = h[8] + arshift(carry, 26); h[7] = h[7] - (carry & kTop38Bits)
carry = h[9] + (1 << 25); h[10] = h[10] + arshift(carry, 26); h[9] = h[9] - (carry & kTop38Bits)
return h
end
local function fe_mul(f, g)
local g2_19 = 19 * g[2]
local g3_19 = 19 * g[3]
local g4_19 = 19 * g[4]
local g5_19 = 19 * g[5]
local g6_19 = 19 * g[6]
local g7_19 = 19 * g[7]
local g8_19 = 19 * g[8]
local g9_19 = 19 * g[9]
local g10_19 = 19 * g[10]
local f2_2 = 2 * f[2]
local f4_2 = 2 * f[4]
local f6_2 = 2 * f[6]
local f8_2 = 2 * f[8]
local f10_2 = 2 * f[10]
local f1g1 = f[1] * g[1]
local f1g2 = f[1] * g[2]
local f1g3 = f[1] * g[3]
local f1g4 = f[1] * g[4]
local f1g5 = f[1] * g[5]
local f1g6 = f[1] * g[6]
local f1g7 = f[1] * g[7]
local f1g8 = f[1] * g[8]
local f1g9 = f[1] * g[9]
local f1g10 = f[1] * g[10]
local f2g1 = f[2] * g[1]
local f2g2_2 = f2_2 * g[2]
local f2g3 = f[2] * g[3]
local f2g4_2 = f2_2 * g[4]
local f2g5 = f[2] * g[5]
local f2g6_2 = f2_2 * g[6]
local f2g7 = f[2] * g[7]
local f2g8_2 = f2_2 * g[8]
local f2g9 = f[2] * g[9]
local f2g10_38 = f2_2 * g10_19
local f3g1 = f[3] * g[1]
local f3g2 = f[3] * g[2]
local f3g3 = f[3] * g[3]
local f3g4 = f[3] * g[4]
local f3g5 = f[3] * g[5]
local f3g6 = f[3] * g[6]
local f3g7 = f[3] * g[7]
local f3g8 = f[3] * g[8]
local f3g9_19 = f[3] * g9_19
local f3g10_19 = f[3] * g10_19
local f4g1 = f[4] * g[1]
local f4g2_2 = f4_2 * g[2]
local f4g3 = f[4] * g[3]
local f4g4_2 = f4_2 * g[4]
local f4g5 = f[4] * g[5]
local f4g6_2 = f4_2 * g[6]
local f4g7 = f[4] * g[7]
local f4g8_38 = f4_2 * g8_19
local f4g9_19 = f[4] * g9_19
local f4g10_38 = f4_2 * g10_19
local f5g1 = f[5] * g[1]
local f5g2 = f[5] * g[2]
local f5g3 = f[5] * g[3]
local f5g4 = f[5] * g[4]
local f5g5 = f[5] * g[5]
local f5g6 = f[5] * g[6]
local f5g7_19 = f[5] * g7_19
local f5g8_19 = f[5] * g8_19
local f5g9_19 = f[5] * g9_19
local f5g10_19 = f[5] * g10_19
local f6g1 = f[6] * g[1]
local f6g2_2 = f6_2 * g[2]
local f6g3 = f[6] * g[3]
local f6g4_2 = f6_2 * g[4]
local f6g5 = f[6] * g[5]
local f6g6_38 = f6_2 * g6_19
local f6g7_19 = f[6] * g7_19
local f6g8_38 = f6_2 * g8_19
local f6g9_19 = f[6] * g9_19
local f6g10_38 = f6_2 * g10_19
local f7g1 = f[7] * g[1]
local f7g2 = f[7] * g[2]
local f7g3 = f[7] * g[3]
local f7g4 = f[7] * g[4]
local f7g5_19 = f[7] * g5_19
local f7g6_19 = f[7] * g6_19
local f7g7_19 = f[7] * g7_19
local f7g8_19 = f[7] * g8_19
local f7g9_19 = f[7] * g9_19
local f7g10_19 = f[7] * g10_19
local f8g1 = f[8] * g[1]
local f8g2_2 = f8_2 * g[2]
local f8g3 = f[8] * g[3]
local f8g4_38 = f8_2 * g4_19
local f8g5_19 = f[8] * g5_19
local f8g6_38 = f8_2 * g6_19
local f8g7_19 = f[8] * g7_19
local f8g8_38 = f8_2 * g8_19
local f8g9_19 = f[8] * g9_19
local f8g10_38 = f8_2 * g10_19
local f9g1 = f[9] * g[1]
local f9g2 = f[9] * g[2]
local f9g3_19 = f[9] * g3_19
local f9g4_19 = f[9] * g4_19
local f9g5_19 = f[9] * g5_19
local f9g6_19 = f[9] * g6_19
local f9g7_19 = f[9] * g7_19
local f9g8_19 = f[9] * g8_19
local f9g9_19 = f[9] * g9_19
local f9g10_19 = f[9] * g10_19
local f10g1 = f[10] * g[1]
local f10g2_38 = f10_2 * g2_19
local f10g3_19 = f[10] * g3_19
local f10g4_38 = f10_2 * g4_19
local f10g5_19 = f[10] * g5_19
local f10g6_38 = f10_2 * g6_19
local f10g7_19 = f[10] * g7_19
local f10g8_38 = f10_2 * g8_19
local f10g9_19 = f[10] * g9_19
local f10g10_38 = f10_2 * g10_19
local h = {
f1g1 + f2g10_38 + f3g9_19 + f4g8_38 + f5g7_19 + f6g6_38 + f7g5_19 + f8g4_38 + f9g3_19 + f10g2_38,
f1g2 + f2g1 + f3g10_19 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 + f10g3_19,
f1g3 + f2g2_2 + f3g1 + f4g10_38 + f5g9_19 + f6g8_38 + f7g7_19 + f8g6_38 + f9g5_19 + f10g4_38,
f1g4 + f2g3 + f3g2 + f4g1 + f5g10_19 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 + f10g5_19,
f1g5 + f2g4_2 + f3g3 + f4g2_2 + f5g1 + f6g10_38 + f7g9_19 + f8g8_38 + f9g7_19 + f10g6_38,
f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g10_19 + f8g9_19 + f9g8_19 + f10g7_19,
f1g7 + f2g6_2 + f3g5 + f4g4_2 + f5g3 + f6g2_2 + f7g1 + f8g10_38 + f9g9_19 + f10g8_38,
f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g10_19 + f10g9_19,
f1g9 + f2g8_2 + f3g7 + f4g6_2 + f5g5 + f6g4_2 + f7g3 + f8g2_2 + f9g1 + f10g10_38,
f1g10 + f2g9 + f3g8 + f4g7 + f5g6 + f6g5 + f7g4 + f8g3 + f9g2 + f10g1
}
local carry
carry = h[1] + (1 << 25); h[2] = h[2] + arshift(carry, 26); h[1] = h[1] - (carry & kTop38Bits)
carry = h[5] + (1 << 25); h[6] = h[6] + arshift(carry, 26); h[5] = h[5] - (carry & kTop38Bits)
carry = h[2] + (1 << 24); h[3] = h[3] + arshift(carry, 25); h[2] = h[2] - (carry & kTop39Bits)
carry = h[6] + (1 << 24); h[7] = h[7] + arshift(carry, 25); h[6] = h[6] - (carry & kTop39Bits)
carry = h[3] + (1 << 25); h[4] = h[4] + arshift(carry, 26); h[3] = h[3] - (carry & kTop38Bits)
carry = h[7] + (1 << 25); h[8] = h[8] + arshift(carry, 26); h[7] = h[7] - (carry & kTop38Bits)
carry = h[4] + (1 << 24); h[5] = h[5] + arshift(carry, 25); h[4] = h[4] - (carry & kTop39Bits)
carry = h[8] + (1 << 24); h[9] = h[9] + arshift(carry, 25); h[8] = h[8] - (carry & kTop39Bits)
carry = h[5] + (1 << 25); h[6] = h[6] + arshift(carry, 26); h[5] = h[5] - (carry & kTop38Bits)
carry = h[9] + (1 << 25); h[10] = h[10] + arshift(carry, 26); h[9] = h[9] - (carry & kTop38Bits)
carry = h[10] + (1 << 24); h[1] = h[1] + arshift(carry, 25) * 19; h[10] = h[10] - (carry & kTop39Bits)
carry = h[1] + (1 << 25); h[2] = h[2] + arshift(carry, 26); h[1] = h[1] - (carry & kTop38Bits)
return h
end
local function fe_sq(f)
local f1_2 = 2 * f[1]
local f2_2 = 2 * f[2]
local f3_2 = 2 * f[3]
local f4_2 = 2 * f[4]
local f5_2 = 2 * f[5]
local f6_2 = 2 * f[6]
local f7_2 = 2 * f[7]
local f8_2 = 2 * f[8]
local f6_38 = 38 * f[6]
local f7_19 = 19 * f[7]
local f8_38 = 38 * f[8]
local f9_19 = 19 * f[9]
local f10_38 = 38 * f[10]
local f1f1 = f[1] * f[1]
local f1f2_2 = f1_2 * f[2]
local f1f3_2 = f1_2 * f[3]
local f1f4_2 = f1_2 * f[4]
local f1f5_2 = f1_2 * f[5]
local f1f6_2 = f1_2 * f[6]
local f1f7_2 = f1_2 * f[7]
local f1f8_2 = f1_2 * f[8]
local f1f9_2 = f1_2 * f[9]
local f1f10_2 = f1_2 * f[10]
local f2f2_2 = f2_2 * f[2]
local f2f3_2 = f2_2 * f[3]
local f2f4_4 = f2_2 * f4_2
local f2f5_2 = f2_2 * f[5]
local f2f6_4 = f2_2 * f6_2
local f2f7_2 = f2_2 * f[7]
local f2f8_4 = f2_2 * f8_2
local f2f9_2 = f2_2 * f[9]
local f2f10_76 = f2_2 * f10_38
local f3f3 = f[3] * f[3]
local f3f4_2 = f3_2 * f[4]
local f3f5_2 = f3_2 * f[5]
local f3f6_2 = f3_2 * f[6]
local f3f7_2 = f3_2 * f[7]
local f3f8_2 = f3_2 * f[8]
local f3f9_38 = f3_2 * f9_19
local f3f10_38 = f[3] * f10_38
local f4f4_2 = f4_2 * f[4]
local f4f5_2 = f4_2 * f[5]
local f4f6_4 = f4_2 * f6_2
local f4f7_2 = f4_2 * f[7]
local f4f8_76 = f4_2 * f8_38
local f4f9_38 = f4_2 * f9_19
local f4f10_76 = f4_2 * f10_38
local f5f5 = f[5] * f[5]
local f5f6_2 = f5_2 * f[6]
local f5f7_38 = f5_2 * f7_19
local f5f8_38 = f[5] * f8_38
local f5f9_38 = f5_2 * f9_19
local f5f10_38 = f[5] * f10_38
local f6f6_38 = f[6] * f6_38
local f6f7_38 = f6_2 * f7_19
local f6f8_76 = f6_2 * f8_38
local f6f9_38 = f6_2 * f9_19
local f6f10_76 = f6_2 * f10_38
local f7f7_19 = f[7] * f7_19
local f7f8_38 = f[7] * f8_38
local f7f9_38 = f7_2 * f9_19
local f7f10_38 = f[7] * f10_38
local f8f8_38 = f[8] * f8_38
local f8f9_38 = f8_2 * f9_19
local f8f10_76 = f8_2 * f10_38
local f9f9_19 = f[9] * f9_19
local f9f10_38 = f[9] * f10_38
local f10f10_38 = f[10] * f10_38
local h = {
f1f1 + f2f10_76 + f3f9_38 + f4f8_76 + f5f7_38 + f6f6_38,
f1f2_2 + f3f10_38 + f4f9_38 + f5f8_38 + f6f7_38,
f1f3_2 + f2f2_2 + f4f10_76 + f5f9_38 + f6f8_76 + f7f7_19,
f1f4_2 + f2f3_2 + f5f10_38 + f6f9_38 + f7f8_38,
f1f5_2 + f2f4_4 + f3f3 + f6f10_76 + f7f9_38 + f8f8_38,
f1f6_2 + f2f5_2 + f3f4_2 + f7f10_38 + f8f9_38,
f1f7_2 + f2f6_4 + f3f5_2 + f4f4_2 + f8f10_76 + f9f9_19,
f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 + f9f10_38,
f1f9_2 + f2f8_4 + f3f7_2 + f4f6_4 + f5f5 + f10f10_38,
f1f10_2 + f2f9_2 + f3f8_2 + f4f7_2 + f5f6_2
}
local carry
carry = h[1] + (1 << 25); h[2] = h[2] + arshift(carry, 26); h[1] = h[1] - (carry & kTop38Bits)
carry = h[5] + (1 << 25); h[6] = h[6] + arshift(carry, 26); h[5] = h[5] - (carry & kTop38Bits)
carry = h[2] + (1 << 24); h[3] = h[3] + arshift(carry, 25); h[2] = h[2] - (carry & kTop39Bits)
carry = h[6] + (1 << 24); h[7] = h[7] + arshift(carry, 25); h[6] = h[6] - (carry & kTop39Bits)
carry = h[3] + (1 << 25); h[4] = h[4] + arshift(carry, 26); h[3] = h[3] - (carry & kTop38Bits)
carry = h[7] + (1 << 25); h[8] = h[8] + arshift(carry, 26); h[7] = h[7] - (carry & kTop38Bits)
carry = h[4] + (1 << 24); h[5] = h[5] + arshift(carry, 25); h[4] = h[4] - (carry & kTop39Bits)
carry = h[8] + (1 << 24); h[9] = h[9] + arshift(carry, 25); h[8] = h[8] - (carry & kTop39Bits)
carry = h[5] + (1 << 25); h[6] = h[6] + arshift(carry, 26); h[5] = h[5] - (carry & kTop38Bits)
carry = h[9] + (1 << 25); h[10] = h[10] + arshift(carry, 26); h[9] = h[9] - (carry & kTop38Bits)
carry = h[10] + (1 << 24); h[1] = h[1] + arshift(carry, 25) * 19; h[10] = h[10] - (carry & kTop39Bits)
carry = h[1] + (1 << 25); h[2] = h[2] + arshift(carry, 26); h[1] = h[1] - (carry & kTop38Bits)
return h
end
local function fe_invert(z)
local t0 = fe_sq(z)
local t1 = fe_sq(t0)
t1 = fe_sq(t1)
t1 = fe_mul(z, t1)
t0 = fe_mul(t0, t1)
local t2 = fe_sq(t0)
t1 = fe_mul(t1, t2)
t2 = fe_sq(t1)
for _ = 1, 4 do
t2 = fe_sq(t2)
end
t1 = fe_mul(t2, t1)
t2 = fe_sq(t1)
for _ = 1, 9 do
t2 = fe_sq(t2)
end
t2 = fe_mul(t2, t1)
local t3 = fe_sq(t2)
for _ = 1, 19 do
t3 = fe_sq(t3)
end
t2 = fe_mul(t3, t2)
for _ = 0, 9 do
t2 = fe_sq(t2)
end
t1 = fe_mul(t2, t1)
t2 = fe_sq(t1)
for _ = 1, 49 do
t2 = fe_sq(t2)
end
t2 = fe_mul(t2, t1)
t3 = fe_sq(t2)
for _ = 1, 99 do
t3 = fe_sq(t3);
end
t2 = fe_mul(t3, t2)
t2 = fe_sq(t2)
for _ = 1, 49 do
t2 = fe_sq(t2)
end
t1 = fe_mul(t2, t1)
t1 = fe_sq(t1)
for _ = 1, 4 do
t1 = fe_sq(t1)
end
return fe_mul(t1, t0)
end
local function x25519_scalar_mult_generic(scalar, point)
local x1 = fe_frombytes(point)
local x2 = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
local z2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
local x3 = { table.unpack(x1) }
local z3 = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
local swap = 0
local e = { table.unpack(scalar) }
e[1] = e[1] & 248
e[32] = e[32] & 127
e[32] = e[32] | 64
for pos = 254, 0, -1 do
local b = 1 & (e[pos // 8 + 1] >> (pos & 7))
swap = swap ~ b
fe_cswap(x2, x3, swap)
fe_cswap(z2, z3, swap)
swap = b
local tmp0 = fe_sub(x3, z3)
local tmp1 = fe_sub(x2, z2)
fe_addto(x2, z2)
z2 = fe_add(x3, z3)
z3 = fe_mul(tmp0, x2)
z2 = fe_mul(z2, tmp1)
tmp0 = fe_sq(tmp1)
tmp1 = fe_sq(x2)
x3 = fe_add(z3, z2);
z2 = fe_sub(z3, z2);
x2 = fe_mul(tmp1, tmp0)
fe_subto(tmp1, tmp0);
z2 = fe_sq(z2)
z3 = fe_mul121666(tmp1)
x3 = fe_sq(x3)
fe_addto(tmp0, z3)
z3 = fe_mul(x1, z2)
z2 = fe_mul(tmp1, tmp0)
end
-- safety or something
for i = 1, 32 do
e[i] = 0
end
return fe_tobytes(fe_mul(fe_invert(z2), x2))
end
return x25519_scalar_mult_generic
Executable
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env lua
local curve25519 = dofile("curve25519.lua")
local function print_hex(a)
for _, h in pairs(a) do
io.write(string.format("%02x", h))
end
print()
end
local base_point = { 9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
local client_private = {
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20
}
local server_private = {
0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,
0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,
0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,
0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0
}
local client_public = curve25519(client_private, base_point)
local server_public = curve25519(server_private, base_point)
print("client_public")
print_hex(client_public)
print("server_public")
print_hex(server_public)
local client_shared = curve25519(client_private, server_public)
local server_shared = curve25519(server_private, client_public)
print("client_shared")
print_hex(client_shared)
print("server_shared")
print_hex(server_shared)
+264
View File
@@ -0,0 +1,264 @@
local program_name = "BlueSSH"
local program_version = "1.0"
local program_string = program_name .. "_" .. program_version
local component = require("component")
local internet = component.internet
local event = require("event")
local computer = require("computer")
local serialize = require("serialize")
local function lazy_require(name)
local this = {}
local module
setmetatable(this, {
__index = function(_, key)
module = module or require(name)
return module[key]
end,
__call = function(_, ...)
module = module or require(name)
return module(...)
end
})
return this
end
local curve25519 = lazy_require("curve25519")
local function parse_ssh_version(str)
local proto, software, comments = str:match("^SSH%-(%d+%.%d+)%-(%S+)%s?(.*)\r\n$")
if not proto then return nil, "invalid SSH version string" end
return proto, software, comments or nil
end
local function encode_ssh_version(proto, software, comments)
return "SSH-" .. proto .. "-" .. software .. (comments and (" " .. comments) or "") .. "\r\n"
end
local random
if not component.isAvailable("data") or component.data.random == nil then
terminal.write("ssh: WARNING: THIS PROGRAM IS NOT CRYPTOGRAPHICALLY SAFE WITHOUT A TIER 2 DATA CARD, DO NOT CONNECT TO A REAL SERVER WITH THIS\n")
random = function(n)
local parts = {}
for i = 1, n do parts[i] = math.random(0, 255) end
return table.concat(parts)
end
else
random = component.data.random
end
local SSH_MSG_DISCONNECT = 1
local SSH_MSG_IGNORE = 2
local SSH_MSG_UNIMPLEMENTED = 3
local SSH_MSG_DEBUG = 4
local SSH_MSG_SERVICE_REQUEST = 5
local SSH_MSG_SERVICE_ACCEPT = 6
local SSH_MSG_KEXINIT = 20
local SSH_MSG_NEWKEYS = 21
local function socket()
local this = {}
local _sock
local _host
local _port
function this.connect(host, port)
_host = host; _port = port
_sock = internet.connect(host, port)
local ok = false
for _ = 1, 50 do
local err
ok, err = _sock.finishConnect()
if ok == nil then
return nil, err
end
if ok == true then
return true
end
coroutine.yield()
end
return nil, "timed out"
end
local _read_buf = ""
function this.read(n)
while #_read_buf < n do
local chunk, err = _sock.read(n - #_read_buf)
if chunk == nil then return nil, err end
_read_buf = _read_buf .. chunk
end
local to_return = _read_buf:sub(1, n);
_read_buf = _read_buf:sub(n + 1, -1)
return to_return
end
function this.read_until_crlf(n)
local chunk, err = _sock.read(n)
if not chunk then return nil, err end
_read_buf = _read_buf .. chunk
local crlf_pos = _read_buf:find("\r\n", 1, true)
if crlf_pos == nil then return nil end
local to_return = _read_buf:sub(1, crlf_pos + 1)
_read_buf = _read_buf:sub(crlf_pos + 2, -1)
return to_return
end
function this.read_uint8()
local x, err = this.read(1)
if x == nil then return nil, err end
return string.unpack(">I1", x)
end
function this.read_uint32()
local x, err = this.read(4)
if x == nil then return nil, err end
return string.unpack(">I4", x)
end
function this.read_packet(mac_length)
mac_length = mac_length or 0
local packet_length, err = this.read_uint32()
if not packet_length then return nil, err end
local padding_length, err = this.read_uint8()
if not padding_length then return nil, err end
local payload, err = this.read(packet_length - padding_length - 1)
if not payload then return nil, err end
local random_padding, err = this.read(padding_length)
if not random_padding then return nil, err end
local mac, err = this.read(mac_length)
if not mac then return nil, err end
return payload
end
function this.write_packet(payload, block_size)
block_size = block_size or 8
local min_padding = 4
local padding_length = block_size - ((5 + #payload) % block_size)
if padding_length < min_padding then
padding_length = padding_length + block_size
end
local padding = random(padding_length)
local packet_length = 1 + #payload + padding_length
local packet = string.pack(">I4", packet_length)
.. string.char(padding_length)
.. payload
.. padding
return this.write(packet)
end
local function parse_namelist(payload, pos)
local len = string.unpack(">I4", payload, pos)
local s = payload:sub(pos + 4, pos + 4 + len - 1)
local list = {}
if #s > 0 then
for name in s:gmatch("[^,]+") do
list[#list + 1] = name
end
end
return list, pos + 4 + len
end
local function encode_namelist(list)
return string.pack(">s4", table.concat(list or {}, ","))
end
function this.parse_kexinit(payload)
local packet_type = payload:byte(1)
if packet_type ~= SSH_MSG_KEXINIT then return nil, "unknown server side error" end
local pos = 2
local kex = {}
kex.cookie = payload:sub(pos, pos + 15)
pos = pos + 16
kex.kex_algorithms, pos = parse_namelist(payload, pos)
kex.server_host_key_algorithms, pos = parse_namelist(payload, pos)
kex.encryption_algorithms_client_to_server, pos = parse_namelist(payload, pos)
kex.encryption_algorithms_server_to_client, pos = parse_namelist(payload, pos)
kex.mac_algorithms_client_to_server, pos = parse_namelist(payload, pos)
kex.mac_algorithms_server_to_client, pos = parse_namelist(payload, pos)
kex.compression_algorithms_client_to_server, pos = parse_namelist(payload, pos)
kex.compression_algorithms_server_to_client, pos = parse_namelist(payload, pos)
kex.languages_client_to_server, pos = parse_namelist(payload, pos)
kex.languages_server_to_client, pos = parse_namelist(payload, pos)
kex.first_kex_packet_follows = payload:byte(pos) ~= 0
pos = pos + 1
-- next 4 bytes are reserved (uint32 == 0)
return kex
end
function this.build_kexinit(algs)
return string.char(SSH_MSG_KEXINIT) ..
random(16) ..
encode_namelist(algs.kex_algorithms) ..
encode_namelist(algs.server_host_key_algorithms) ..
encode_namelist(algs.encryption_algorithms_client_to_server) ..
encode_namelist(algs.encryption_algorithms_server_to_client) ..
encode_namelist(algs.mac_algorithms_client_to_server) ..
encode_namelist(algs.mac_algorithms_server_to_client) ..
encode_namelist(algs.compression_algorithms_client_to_server) ..
encode_namelist(algs.compression_algorithms_server_to_client) ..
encode_namelist(algs.languages_client_to_server) ..
encode_namelist(algs.languages_server_to_client) ..
'\0' .. -- first_kex_packet_follows
'\0\0\0\0' -- reserved
end
function this.write(x)
local written = 0
while written < #x do
local bytes, err = _sock.write(x:sub(written + 1, -1))
if not bytes then return nil, err end
written = written + bytes
end
return written
end
return this
end
local sock = socket()
sock.connect("localhost", 22)
-- RFC 4253: The maximum length of the string is 255 characters
local server_protoversion, server_softwareversion, server_comments = parse_ssh_version(sock.read_until_crlf(255))
if server_protoversion ~= "2.0" then
return
end
sock.write(encode_ssh_version("2.0", program_string))
print(sock.parse_kexinit(sock.read_packet()))
--[[
local my_algs = {
kex_algorithms = {},
server_host_key_algorithms = {},
encryption_algorithms_client_to_server = {},
encryption_algorithms_server_to_client = {},
mac_algorithms_client_to_server = {},
mac_algorithms_server_to_client = {},
compression_algorithms_client_to_server = { "none" },
compression_algorithms_server_to_client = { "none" },
languages_client_to_server = {},
languages_server_to_client = {},
}
local my_kexinit_payload = sock.build_kexinit(my_algs)
sock.write_packet(my_kexinit_payload)
]]