-- 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