@quenty/ellipticcurvecryptography 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +3 -3
- package/src/Shared/EllipticCurveCryptography/arith.lua +33 -23
- package/src/Shared/EllipticCurveCryptography/chacha20.lua +31 -20
- package/src/Shared/EllipticCurveCryptography/curve.lua +8 -8
- package/src/Shared/EllipticCurveCryptography/init.lua +49 -40
- package/src/Shared/EllipticCurveCryptography/modp.lua +23 -20
- package/src/Shared/EllipticCurveCryptography/modq.lua +53 -51
- package/src/Shared/EllipticCurveCryptography/random.lua +9 -8
- package/src/Shared/EllipticCurveCryptography/sha256.lua +43 -33
- package/src/Shared/EllipticCurveCryptography/twoPower.lua +4 -4
- package/src/Shared/{EllipticCurveCryptography/testing.spec.lua → EllipticCurveCryptography.spec.lua} +2 -4
- package/src/Shared/{EllipticCurveCryptography/benchmark.spec.lua → EllipticCurveCryptographyBenchmark.spec.lua} +2 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.14.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ellipticcurvecryptography@1.13.0...@quenty/ellipticcurvecryptography@1.14.0) (2026-07-23)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **ellipticcurvecryptography:** move specs out of ModuleScript folder ([eb31399](https://github.com/Quenty/NevermoreEngine/commit/eb31399c5e25a790ede55b395ed7972d038b5e6a))
|
|
11
|
+
|
|
12
|
+
# [1.13.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ellipticcurvecryptography@1.12.0...@quenty/ellipticcurvecryptography@1.13.0) (2026-07-14)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- **ellipticcurvecryptography:** convert package to --!strict ([48e814a](https://github.com/Quenty/NevermoreEngine/commit/48e814abb5f01f54627dd4f827a287fb98f405bc))
|
|
17
|
+
|
|
6
18
|
# [1.12.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ellipticcurvecryptography@1.11.0...@quenty/ellipticcurvecryptography@1.12.0) (2026-05-29)
|
|
7
19
|
|
|
8
20
|
**Note:** Version bump only for package @quenty/ellipticcurvecryptography
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/ellipticcurvecryptography",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "Elliptic curve cryptography forked from BoatBomber, forked from ComputerCraft",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"BoatBomber"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@quenty/nevermore-test-runner": "1.
|
|
32
|
+
"@quenty/nevermore-test-runner": "1.5.0",
|
|
33
33
|
"@quentystudios/jest-lua": "3.10.0-quenty.2"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "1de37218a2bedb8e3f8614a2e09bba9eddc812da"
|
|
39
39
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
-- Big integer arithmetic for 168-bit (and 336-bit) numbers
|
|
3
3
|
-- Numbers are represented as little-endian tables of 24-bit integers
|
|
4
4
|
local twoPower = require(script.Parent.twoPower)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type BigInt = { number }
|
|
7
|
+
type DoubleInt = { number }
|
|
8
|
+
|
|
9
|
+
local function isEqual(a: BigInt, b: BigInt): boolean
|
|
7
10
|
return a[1] == b[1]
|
|
8
11
|
and a[2] == b[2]
|
|
9
12
|
and a[3] == b[3]
|
|
@@ -13,7 +16,7 @@ local function isEqual(a, b)
|
|
|
13
16
|
and a[7] == b[7]
|
|
14
17
|
end
|
|
15
18
|
|
|
16
|
-
local function compare(a, b)
|
|
19
|
+
local function compare(a: BigInt, b: BigInt): number
|
|
17
20
|
for i = 7, 1, -1 do
|
|
18
21
|
if a[i] > b[i] then
|
|
19
22
|
return 1
|
|
@@ -25,7 +28,7 @@ local function compare(a, b)
|
|
|
25
28
|
return 0
|
|
26
29
|
end
|
|
27
30
|
|
|
28
|
-
local function add(a, b)
|
|
31
|
+
local function add(a: BigInt, b: BigInt): BigInt
|
|
29
32
|
-- c7 may be greater than 2^24 before reduction
|
|
30
33
|
local c1 = a[1] + b[1]
|
|
31
34
|
local c2 = a[2] + b[2]
|
|
@@ -63,7 +66,7 @@ local function add(a, b)
|
|
|
63
66
|
return { c1, c2, c3, c4, c5, c6, c7 }
|
|
64
67
|
end
|
|
65
68
|
|
|
66
|
-
local function sub(a, b)
|
|
69
|
+
local function sub(a: BigInt, b: BigInt): BigInt
|
|
67
70
|
-- c7 may be negative before reduction
|
|
68
71
|
local c1 = a[1] - b[1]
|
|
69
72
|
local c2 = a[2] - b[2]
|
|
@@ -101,7 +104,7 @@ local function sub(a, b)
|
|
|
101
104
|
return { c1, c2, c3, c4, c5, c6, c7 }
|
|
102
105
|
end
|
|
103
106
|
|
|
104
|
-
local function rShift(a)
|
|
107
|
+
local function rShift(a: BigInt): BigInt
|
|
105
108
|
local c1 = a[1]
|
|
106
109
|
local c2 = a[2]
|
|
107
110
|
local c3 = a[3]
|
|
@@ -134,7 +137,7 @@ local function rShift(a)
|
|
|
134
137
|
return { c1, c2, c3, c4, c5, c6, c7 }
|
|
135
138
|
end
|
|
136
139
|
|
|
137
|
-
local function addDouble(a, b)
|
|
140
|
+
local function addDouble(a: DoubleInt, b: DoubleInt): DoubleInt
|
|
138
141
|
-- a and b are 336-bit integers (14 words)
|
|
139
142
|
local c1 = a[1] + b[1]
|
|
140
143
|
local c2 = a[2] + b[2]
|
|
@@ -207,7 +210,7 @@ local function addDouble(a, b)
|
|
|
207
210
|
return { c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14 }
|
|
208
211
|
end
|
|
209
212
|
|
|
210
|
-
local function mult(a, b, half_multiply)
|
|
213
|
+
local function mult(a: BigInt, b: BigInt, half_multiply: boolean): DoubleInt
|
|
211
214
|
local a1, a2, a3, a4, a5, a6, a7 = a[1], a[2], a[3], a[4], a[5], a[6], a[7]
|
|
212
215
|
local b1, b2, b3, b4, b5, b6, b7 = b[1], b[2], b[3], b[4], b[5], b[6], b[7]
|
|
213
216
|
|
|
@@ -218,7 +221,13 @@ local function mult(a, b, half_multiply)
|
|
|
218
221
|
local c5 = a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1
|
|
219
222
|
local c6 = a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1
|
|
220
223
|
local c7 = a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1
|
|
221
|
-
local c8
|
|
224
|
+
local c8: number = 0
|
|
225
|
+
local c9: number = 0
|
|
226
|
+
local c10: number = 0
|
|
227
|
+
local c11: number = 0
|
|
228
|
+
local c12: number = 0
|
|
229
|
+
local c13: number = 0
|
|
230
|
+
local c14: number = 0
|
|
222
231
|
if not half_multiply then
|
|
223
232
|
c8 = a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2
|
|
224
233
|
c9 = a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3
|
|
@@ -277,7 +286,7 @@ local function mult(a, b, half_multiply)
|
|
|
277
286
|
return { c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14 }
|
|
278
287
|
end
|
|
279
288
|
|
|
280
|
-
local function square(a)
|
|
289
|
+
local function square(a: BigInt): DoubleInt
|
|
281
290
|
-- returns a 336-bit integer (14 words)
|
|
282
291
|
local a1, a2, a3, a4, a5, a6, a7 = a[1], a[2], a[3], a[4], a[5], a[6], a[7]
|
|
283
292
|
|
|
@@ -340,8 +349,8 @@ local function square(a)
|
|
|
340
349
|
return { c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14 }
|
|
341
350
|
end
|
|
342
351
|
|
|
343
|
-
local function encodeInt(a)
|
|
344
|
-
local enc = table.create(21)
|
|
352
|
+
local function encodeInt(a: BigInt): { number }
|
|
353
|
+
local enc: { number } = table.create(21)
|
|
345
354
|
|
|
346
355
|
for i = 1, 7 do
|
|
347
356
|
local word = a[i]
|
|
@@ -354,9 +363,9 @@ local function encodeInt(a)
|
|
|
354
363
|
return enc
|
|
355
364
|
end
|
|
356
365
|
|
|
357
|
-
local function decodeInt(enc)
|
|
358
|
-
local a = {}
|
|
359
|
-
local encCopy = table.create(21)
|
|
366
|
+
local function decodeInt(enc: { number }): BigInt
|
|
367
|
+
local a: BigInt = {}
|
|
368
|
+
local encCopy: { number } = table.create(21)
|
|
360
369
|
|
|
361
370
|
for i = 1, 21 do
|
|
362
371
|
local byte = enc[i]
|
|
@@ -379,26 +388,27 @@ local function decodeInt(enc)
|
|
|
379
388
|
return a
|
|
380
389
|
end
|
|
381
390
|
|
|
382
|
-
local function mods(d, w)
|
|
383
|
-
local result = d[1] % twoPower[w]
|
|
391
|
+
local function mods(d: BigInt, w: number): number
|
|
392
|
+
local result = d[1] % (twoPower :: any)[w]
|
|
384
393
|
|
|
385
|
-
if result >= twoPower[w - 1] then
|
|
386
|
-
result -= twoPower[w]
|
|
394
|
+
if result >= (twoPower :: any)[w - 1] then
|
|
395
|
+
result -= (twoPower :: any)[w]
|
|
387
396
|
end
|
|
388
397
|
|
|
389
398
|
return result
|
|
390
399
|
end
|
|
391
400
|
|
|
392
401
|
-- Represents a 168-bit number as the (2^w)-ary Non-Adjacent Form
|
|
393
|
-
local function NAF(d, w)
|
|
394
|
-
local t
|
|
395
|
-
local
|
|
402
|
+
local function NAF(d: BigInt, w: number): { number }
|
|
403
|
+
local t: { number } = {}
|
|
404
|
+
local t_len = 0
|
|
405
|
+
local newD: BigInt = { table.unpack(d) }
|
|
396
406
|
|
|
397
407
|
for _ = 1, 168 do
|
|
398
408
|
if newD[1] % 2 == 1 then
|
|
399
409
|
t_len += 1
|
|
400
410
|
t[t_len] = mods(newD, w)
|
|
401
|
-
newD = sub(newD, { t[
|
|
411
|
+
newD = sub(newD, { t[t_len], 0, 0, 0, 0, 0, 0 })
|
|
402
412
|
else
|
|
403
413
|
t_len += 1
|
|
404
414
|
t[t_len] = 0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--!native
|
|
3
3
|
|
|
4
4
|
-- Chacha20 cipher in ComputerCraft
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
-- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
|
|
9
9
|
-- http://pastebin.com/GPzf9JSa
|
|
10
10
|
-- Last update: April 17, 2017
|
|
11
|
-
local twoPower = require(script.Parent.twoPower)
|
|
11
|
+
local twoPower: any = require(script.Parent.twoPower)
|
|
12
12
|
local util = require(script.Parent.util)
|
|
13
13
|
|
|
14
14
|
local bxor = bit32.bxor
|
|
@@ -20,13 +20,13 @@ local mod = 2 ^ 32
|
|
|
20
20
|
local tau = table.pack(string.byte("expand 16-byte k", 1, -1))
|
|
21
21
|
local sigma = table.pack(string.byte("expand 32-byte k", 1, -1))
|
|
22
22
|
|
|
23
|
-
local function rotl(n, b)
|
|
23
|
+
local function rotl(n: number, b: number): number
|
|
24
24
|
local s = n / twoPower[32 - b]
|
|
25
25
|
local f = s % 1
|
|
26
26
|
return (s - f) + f * mod
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
local function quarterRound(s, a, b, c, d)
|
|
29
|
+
local function quarterRound(s: { number }, a: number, b: number, c: number, d: number): { number }
|
|
30
30
|
s[a] = (s[a] + s[b]) % mod
|
|
31
31
|
s[d] = rotl(bxor(s[d], s[a]), 16)
|
|
32
32
|
s[c] = (s[c] + s[d]) % mod
|
|
@@ -38,8 +38,8 @@ local function quarterRound(s, a, b, c, d)
|
|
|
38
38
|
return s
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
local function hashBlock(state, rnd)
|
|
42
|
-
local s = { table.unpack(state) }
|
|
41
|
+
local function hashBlock(state: { number }, rnd: number): { number }
|
|
42
|
+
local s: { number } = { table.unpack(state) }
|
|
43
43
|
for i = 1, rnd do
|
|
44
44
|
local r = i % 2 == 1
|
|
45
45
|
s = r and quarterRound(s, 1, 5, 9, 13) or quarterRound(s, 1, 6, 11, 16)
|
|
@@ -55,17 +55,17 @@ local function hashBlock(state, rnd)
|
|
|
55
55
|
return s
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
local function LE_toInt(bs, i)
|
|
58
|
+
local function LE_toInt(bs: { number }, i: number): number
|
|
59
59
|
return (bs[i + 1] or 0)
|
|
60
60
|
+ blshift((bs[i + 2] or 0), 8)
|
|
61
61
|
+ blshift((bs[i + 3] or 0), 16)
|
|
62
62
|
+ blshift((bs[i + 4] or 0), 24)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
local function initState(key, nonce, counter)
|
|
65
|
+
local function initState(key: { number }, nonce: { number }, counter: number): { number }
|
|
66
66
|
local isKey256 = #key == 32
|
|
67
|
-
local const = isKey256 and sigma or tau
|
|
68
|
-
local state = table.create(16)
|
|
67
|
+
local const: { number } = isKey256 and sigma or tau
|
|
68
|
+
local state: { number } = table.create(16)
|
|
69
69
|
|
|
70
70
|
state[1] = LE_toInt(const, 0)
|
|
71
71
|
state[2] = LE_toInt(const, 4)
|
|
@@ -89,8 +89,9 @@ local function initState(key, nonce, counter)
|
|
|
89
89
|
return state
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
local function serialize(state)
|
|
93
|
-
local r
|
|
92
|
+
local function serialize(state: { number }): { number }
|
|
93
|
+
local r: { number } = table.create(16)
|
|
94
|
+
local len_r = 0
|
|
94
95
|
for i = 1, 16 do
|
|
95
96
|
r[len_r + 1] = band(state[i], 0xFF)
|
|
96
97
|
r[len_r + 2] = band(brshift(state[i], 8), 0xFF)
|
|
@@ -102,24 +103,34 @@ local function serialize(state)
|
|
|
102
103
|
return r
|
|
103
104
|
end
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
export type ByteTable = typeof(setmetatable({} :: { number }, {} :: typeof(util.byteTableMT)))
|
|
107
|
+
|
|
108
|
+
local function crypt(
|
|
109
|
+
data: string | { number },
|
|
110
|
+
key: { number },
|
|
111
|
+
nonce: { number },
|
|
112
|
+
cntr: number?,
|
|
113
|
+
round: number?
|
|
114
|
+
): ByteTable
|
|
106
115
|
assert(type(key) == "table", "ChaCha20: Invalid key format (" .. type(key) .. "), must be table")
|
|
107
116
|
assert(type(nonce) == "table", "ChaCha20: Invalid nonce format (" .. type(nonce) .. "), must be table")
|
|
108
117
|
assert(#key == 16 or #key == 32, "ChaCha20: Invalid key length (" .. #key .. "), must be 16 or 32")
|
|
109
118
|
assert(#nonce == 12, "ChaCha20: Invalid nonce length (" .. #nonce .. "), must be 12")
|
|
110
119
|
|
|
111
|
-
local newData = type(data) == "table" and { table.unpack(data
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
local newData: { number } = type(data) == "table" and { table.unpack(data :: { number }) }
|
|
121
|
+
or util.stringToByteArray(data :: string)
|
|
122
|
+
local counter = tonumber(cntr) or 1
|
|
123
|
+
local rounds = tonumber(round) or 20
|
|
114
124
|
|
|
115
|
-
local out
|
|
116
|
-
local
|
|
125
|
+
local out: { number } = {}
|
|
126
|
+
local out_len = 0
|
|
127
|
+
local state = initState(key, nonce, counter)
|
|
117
128
|
local blockAmt = math.floor(#newData / 64)
|
|
118
129
|
for i = 0, blockAmt do
|
|
119
|
-
local ks = serialize(hashBlock(state,
|
|
130
|
+
local ks = serialize(hashBlock(state, rounds))
|
|
120
131
|
state[13] = (state[13] + 1) % mod
|
|
121
132
|
|
|
122
|
-
local block = table.create(64)
|
|
133
|
+
local block: { number } = table.create(64)
|
|
123
134
|
for j = 1, 64 do
|
|
124
135
|
block[j] = newData[(i * 64) + j]
|
|
125
136
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--!native
|
|
3
3
|
|
|
4
4
|
--[=[
|
|
@@ -49,7 +49,7 @@ local montgomeryModP = modp.montgomeryModP
|
|
|
49
49
|
local expModP = modp.expModP
|
|
50
50
|
local inverseMontgomeryModQ = modq.inverseMontgomeryModQ
|
|
51
51
|
|
|
52
|
-
local pointMT
|
|
52
|
+
local pointMT: any
|
|
53
53
|
local ZERO = table.create(7, 0)
|
|
54
54
|
local ONE = montgomeryModP({ 1, 0, 0, 0, 0, 0, 0 })
|
|
55
55
|
|
|
@@ -193,9 +193,9 @@ end
|
|
|
193
193
|
local function scalarMult(multiplier, P1)
|
|
194
194
|
-- w = 5
|
|
195
195
|
local naf = NAF(multiplier, 5)
|
|
196
|
-
local PTable = { P1 }
|
|
196
|
+
local PTable: { any } = { P1 }
|
|
197
197
|
local P2 = pointDouble(P1)
|
|
198
|
-
local Q = { table.create(7, 0), { table.unpack(ONE) }, { table.unpack(ONE) } }
|
|
198
|
+
local Q: any = { table.create(7, 0), { table.unpack(ONE) }, { table.unpack(ONE) } }
|
|
199
199
|
|
|
200
200
|
for i = 3, 31, 2 do
|
|
201
201
|
PTable[i] = pointAdd(PTable[i - 2], P2)
|
|
@@ -215,14 +215,14 @@ end
|
|
|
215
215
|
|
|
216
216
|
-- Lookup table 4-ary NAF method for scalar multiplication by G.
|
|
217
217
|
-- Precomputations for the regular NAF method are done before the multiplication.
|
|
218
|
-
local GTable = { G }
|
|
218
|
+
local GTable: { any } = { G }
|
|
219
219
|
for i = 2, 168 do
|
|
220
220
|
GTable[i] = pointDouble(GTable[i - 1])
|
|
221
221
|
end
|
|
222
222
|
|
|
223
223
|
local function scalarMultG(multiplier)
|
|
224
224
|
local naf = NAF(multiplier, 2)
|
|
225
|
-
local Q = { table.create(7, 0), { table.unpack(ONE) }, { table.unpack(ONE) } }
|
|
225
|
+
local Q: any = { table.create(7, 0), { table.unpack(ONE) }, { table.unpack(ONE) } }
|
|
226
226
|
|
|
227
227
|
for i = 1, 168 do
|
|
228
228
|
if naf[i] == 1 then
|
|
@@ -237,7 +237,7 @@ end
|
|
|
237
237
|
|
|
238
238
|
-- Point compression and encoding.
|
|
239
239
|
-- Compresses curve points to 22 bytes.
|
|
240
|
-
local function pointEncode(P1)
|
|
240
|
+
local function pointEncode(P1: any)
|
|
241
241
|
P1 = pointScale(P1)
|
|
242
242
|
local result = {}
|
|
243
243
|
local x, y = P1[1], P1[2]
|
|
@@ -321,7 +321,7 @@ pointMT = {
|
|
|
321
321
|
return pointIsEqual(P1, P2)
|
|
322
322
|
end,
|
|
323
323
|
|
|
324
|
-
__mul = function(P1, s)
|
|
324
|
+
__mul = function(P1: any, s: any)
|
|
325
325
|
if type(P1) == "number" then
|
|
326
326
|
return s * P1
|
|
327
327
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--!native
|
|
3
3
|
|
|
4
4
|
--[=[
|
|
@@ -39,6 +39,9 @@ local modq = require(script.modq)
|
|
|
39
39
|
local random = require(script.random)
|
|
40
40
|
local sha256 = require(script.sha256)
|
|
41
41
|
local util = require(script.util)
|
|
42
|
+
|
|
43
|
+
type ByteTable = typeof(setmetatable({} :: { number }, {} :: typeof(util.byteTableMT)))
|
|
44
|
+
|
|
42
45
|
local EllipticCurveCryptography = {}
|
|
43
46
|
|
|
44
47
|
EllipticCurveCryptography.chacha20 = chacha20
|
|
@@ -52,7 +55,7 @@ EllipticCurveCryptography._byteMetatable = assert(util.byteTableMT, "No byteTabl
|
|
|
52
55
|
@param key any
|
|
53
56
|
@return boolean
|
|
54
57
|
]=]
|
|
55
|
-
function EllipticCurveCryptography.isByteTable(key)
|
|
58
|
+
function EllipticCurveCryptography.isByteTable(key: any): boolean
|
|
56
59
|
return type(key) == "table" and getmetatable(key) == EllipticCurveCryptography._byteMetatable
|
|
57
60
|
end
|
|
58
61
|
|
|
@@ -61,14 +64,14 @@ end
|
|
|
61
64
|
|
|
62
65
|
@param value any
|
|
63
66
|
]=]
|
|
64
|
-
function EllipticCurveCryptography.createByteTable(value)
|
|
67
|
+
function EllipticCurveCryptography.createByteTable(value: { number }): ByteTable
|
|
65
68
|
assert(type(value) == "table", "Bad value")
|
|
66
69
|
|
|
67
70
|
return setmetatable(table.clone(value), EllipticCurveCryptography._byteMetatable)
|
|
68
71
|
end
|
|
69
72
|
|
|
70
|
-
function EllipticCurveCryptography._getNonceFromEpoch()
|
|
71
|
-
local nonce = table.create(12)
|
|
73
|
+
function EllipticCurveCryptography._getNonceFromEpoch(): { number }
|
|
74
|
+
local nonce: { number } = table.create(12)
|
|
72
75
|
local epoch = DateTime.now().UnixTimestampMillis
|
|
73
76
|
for i = 1, 12 do
|
|
74
77
|
nonce[i] = epoch % 256
|
|
@@ -98,23 +101,23 @@ end
|
|
|
98
101
|
@param key ByteTable
|
|
99
102
|
@return ByteTable
|
|
100
103
|
]=]
|
|
101
|
-
function EllipticCurveCryptography.encrypt(data, key)
|
|
104
|
+
function EllipticCurveCryptography.encrypt(data: string | ByteTable, key: ByteTable): ByteTable
|
|
102
105
|
assert(type(data) == "string" or EllipticCurveCryptography.isByteTable(data), "Bad data")
|
|
103
106
|
assert(EllipticCurveCryptography.isByteTable(key), "Bad key")
|
|
104
107
|
|
|
105
|
-
local encKey = sha256.hmac("encKey", key)
|
|
106
|
-
local macKey = sha256.hmac("macKey", key)
|
|
108
|
+
local encKey = sha256.hmac("encKey", (key :: any) :: { number })
|
|
109
|
+
local macKey = sha256.hmac("macKey", (key :: any) :: { number })
|
|
107
110
|
local nonce = EllipticCurveCryptography._getNonceFromEpoch()
|
|
108
111
|
|
|
109
|
-
local ciphertext = chacha20.crypt(data, encKey, nonce)
|
|
112
|
+
local ciphertext = chacha20.crypt(data :: any, (encKey :: any) :: { number }, nonce)
|
|
110
113
|
|
|
111
|
-
local result = nonce
|
|
112
|
-
for _, value in ipairs(ciphertext) do
|
|
114
|
+
local result: { number } = nonce
|
|
115
|
+
for _, value in ipairs(ciphertext :: any) do
|
|
113
116
|
table.insert(result, value)
|
|
114
117
|
end
|
|
115
118
|
|
|
116
|
-
local mac = sha256.hmac(result, macKey)
|
|
117
|
-
for _, value in ipairs(mac) do
|
|
119
|
+
local mac = sha256.hmac(result, (macKey :: any) :: { number })
|
|
120
|
+
for _, value in ipairs((mac :: any) :: { number }) do
|
|
118
121
|
table.insert(result, value)
|
|
119
122
|
end
|
|
120
123
|
|
|
@@ -135,21 +138,22 @@ end
|
|
|
135
138
|
@param key ByteTable
|
|
136
139
|
@return ByteTable
|
|
137
140
|
]=]
|
|
138
|
-
function EllipticCurveCryptography.decrypt(data, key)
|
|
141
|
+
function EllipticCurveCryptography.decrypt(data: string | ByteTable, key: ByteTable): ByteTable
|
|
139
142
|
assert(type(data) == "string" or EllipticCurveCryptography.isByteTable(data), "Bad data")
|
|
140
143
|
assert(EllipticCurveCryptography.isByteTable(key), "Bad key")
|
|
141
144
|
|
|
142
|
-
local actualData = type(data) == "table" and { table.unpack(data
|
|
143
|
-
|
|
144
|
-
local
|
|
145
|
-
local
|
|
145
|
+
local actualData: { number } = type(data) == "table" and { table.unpack(data :: any) }
|
|
146
|
+
or { string.byte(tostring(data), 1, -1) }
|
|
147
|
+
local encKey = sha256.hmac("encKey", (key :: any) :: { number })
|
|
148
|
+
local macKey = sha256.hmac("macKey", (key :: any) :: { number })
|
|
149
|
+
local mac = sha256.hmac({ table.unpack(actualData, 1, #actualData - 32) }, (macKey :: any) :: { number })
|
|
146
150
|
local messageMac = { table.unpack(actualData, #actualData - 31) }
|
|
147
|
-
assert(mac:isEqual(messageMac), "invalid mac")
|
|
151
|
+
assert((mac :: any):isEqual(messageMac), "invalid mac")
|
|
148
152
|
local nonce = { table.unpack(actualData, 1, 12) }
|
|
149
153
|
local ciphertext = { table.unpack(actualData, 13, #actualData - 32) }
|
|
150
|
-
local result = chacha20.crypt(ciphertext, encKey, nonce)
|
|
154
|
+
local result: ByteTable = chacha20.crypt(ciphertext, (encKey :: any) :: { number }, nonce)
|
|
151
155
|
|
|
152
|
-
return
|
|
156
|
+
return result
|
|
153
157
|
end
|
|
154
158
|
|
|
155
159
|
--[=[
|
|
@@ -167,10 +171,10 @@ end
|
|
|
167
171
|
@return ByteTable -- privateKey
|
|
168
172
|
@return ByteTable -- publicKey
|
|
169
173
|
]=]
|
|
170
|
-
function EllipticCurveCryptography.keypair(seed)
|
|
174
|
+
function EllipticCurveCryptography.keypair(seed: number): (ByteTable, ByteTable)
|
|
171
175
|
assert(type(seed) == "number", "Bad seed")
|
|
172
176
|
|
|
173
|
-
local x
|
|
177
|
+
local x: any
|
|
174
178
|
if seed then
|
|
175
179
|
x = modq.hashModQ(seed)
|
|
176
180
|
else
|
|
@@ -179,8 +183,8 @@ function EllipticCurveCryptography.keypair(seed)
|
|
|
179
183
|
|
|
180
184
|
local Y = curve.G * x
|
|
181
185
|
|
|
182
|
-
local privateKey = x:encode()
|
|
183
|
-
local publicKey = Y:encode()
|
|
186
|
+
local privateKey: ByteTable = x:encode()
|
|
187
|
+
local publicKey: ByteTable = Y:encode()
|
|
184
188
|
|
|
185
189
|
return privateKey, publicKey
|
|
186
190
|
end
|
|
@@ -203,15 +207,15 @@ end
|
|
|
203
207
|
@param publicKey ByteTable
|
|
204
208
|
@return ByteTable
|
|
205
209
|
]=]
|
|
206
|
-
function EllipticCurveCryptography.exchange(privateKey, publicKey)
|
|
210
|
+
function EllipticCurveCryptography.exchange(privateKey: ByteTable, publicKey: ByteTable): ByteTable
|
|
207
211
|
assert(EllipticCurveCryptography.isByteTable(privateKey), "Bad privateKey")
|
|
208
212
|
assert(EllipticCurveCryptography.isByteTable(publicKey), "Bad publicKey")
|
|
209
213
|
|
|
210
214
|
local x = modq.decodeModQ(privateKey)
|
|
211
|
-
local Y = curve.pointDecode(publicKey)
|
|
215
|
+
local Y = curve.pointDecode(publicKey :: any)
|
|
212
216
|
local Z = Y * x
|
|
213
217
|
|
|
214
|
-
local sharedSecret = sha256.digest(Z:encode())
|
|
218
|
+
local sharedSecret: ByteTable = sha256.digest(Z:encode())
|
|
215
219
|
|
|
216
220
|
return sharedSecret
|
|
217
221
|
end
|
|
@@ -227,24 +231,25 @@ end
|
|
|
227
231
|
@param message string | EncodedMessage
|
|
228
232
|
@return ByteTable
|
|
229
233
|
]=]
|
|
230
|
-
function EllipticCurveCryptography.sign(privateKey, message)
|
|
234
|
+
function EllipticCurveCryptography.sign(privateKey: ByteTable, message: string | ByteTable): ByteTable
|
|
231
235
|
assert(EllipticCurveCryptography.isByteTable(privateKey), "Bad privateKey")
|
|
232
236
|
assert(type(message) == "string" or EllipticCurveCryptography.isByteTable(message), "Bad message")
|
|
233
237
|
|
|
234
|
-
local actualMessage = type(message) == "table" and string.char(table.unpack(message)) or tostring(message)
|
|
235
|
-
local actualPrivateKey = type(privateKey) == "table" and string.char(table.unpack(privateKey))
|
|
238
|
+
local actualMessage = type(message) == "table" and string.char(table.unpack(message :: any)) or tostring(message)
|
|
239
|
+
local actualPrivateKey = type(privateKey) == "table" and string.char(table.unpack(privateKey :: any))
|
|
236
240
|
or tostring(privateKey)
|
|
237
241
|
|
|
238
|
-
local x = modq.decodeModQ(actualPrivateKey)
|
|
239
|
-
local k = modq.randomModQ()
|
|
242
|
+
local x: any = modq.decodeModQ(actualPrivateKey)
|
|
243
|
+
local k: any = modq.randomModQ()
|
|
240
244
|
local R = curve.G * k
|
|
241
|
-
local e = modq.hashModQ(actualMessage .. tostring(R))
|
|
245
|
+
local e: any = modq.hashModQ(actualMessage .. tostring(R))
|
|
242
246
|
local s = k - x * e
|
|
243
247
|
|
|
244
248
|
e = e:encode()
|
|
245
249
|
s = s:encode()
|
|
246
250
|
|
|
247
|
-
local result
|
|
251
|
+
local result: { number } = e
|
|
252
|
+
local result_len = #e
|
|
248
253
|
for index, value in ipairs(s) do
|
|
249
254
|
result[result_len + index] = value
|
|
250
255
|
end
|
|
@@ -265,16 +270,20 @@ end
|
|
|
265
270
|
@param message ByteTable | string
|
|
266
271
|
@param signature ByteTable
|
|
267
272
|
]=]
|
|
268
|
-
function EllipticCurveCryptography.verify(
|
|
273
|
+
function EllipticCurveCryptography.verify(
|
|
274
|
+
publicKey: ByteTable,
|
|
275
|
+
message: string | ByteTable,
|
|
276
|
+
signature: ByteTable
|
|
277
|
+
): boolean
|
|
269
278
|
assert(EllipticCurveCryptography.isByteTable(publicKey), "Bad privateKey")
|
|
270
279
|
assert(type(message) == "string" or EllipticCurveCryptography.isByteTable(message), "Bad message")
|
|
271
280
|
assert(EllipticCurveCryptography.isByteTable(signature), "Bad signature")
|
|
272
281
|
|
|
273
|
-
local actualMessage = type(message) == "table" and string.char(table.unpack(message)) or tostring(message)
|
|
282
|
+
local actualMessage = type(message) == "table" and string.char(table.unpack(message :: any)) or tostring(message)
|
|
274
283
|
local sigLen = #signature
|
|
275
|
-
local Y = curve.pointDecode(publicKey)
|
|
276
|
-
local e = modq.decodeModQ({ table.unpack(signature, 1, sigLen / 2) })
|
|
277
|
-
local s = modq.decodeModQ({ table.unpack(signature, sigLen / 2 + 1) })
|
|
284
|
+
local Y = curve.pointDecode(publicKey :: any)
|
|
285
|
+
local e = modq.decodeModQ({ table.unpack(signature :: any, 1, sigLen / 2) })
|
|
286
|
+
local s = modq.decodeModQ({ table.unpack(signature :: any, sigLen / 2 + 1) })
|
|
278
287
|
local Rv = curve.G * s + Y * e
|
|
279
288
|
local ev = modq.hashModQ(actualMessage .. tostring(Rv))
|
|
280
289
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
-- Arithmetic on the finite field of integers modulo p
|
|
3
3
|
-- Where p is the finite field modulus
|
|
4
4
|
local arith = require(script.Parent.arith)
|
|
@@ -8,17 +8,20 @@ local addDouble = arith.addDouble
|
|
|
8
8
|
local mult = arith.mult
|
|
9
9
|
local square = arith.square
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
type BigInt = { number }
|
|
12
|
+
type DoubleInt = { number }
|
|
13
|
+
|
|
14
|
+
local p: BigInt = { 3, 0, 0, 0, 0, 0, 15761408 }
|
|
12
15
|
|
|
13
16
|
-- We're using the Montgomery Reduction for fast modular multiplication.
|
|
14
17
|
-- https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
|
|
15
18
|
-- r = 2^168
|
|
16
19
|
-- p * pInverse = -1 (mod r)
|
|
17
20
|
-- r2 = r * r (mod p)
|
|
18
|
-
local pInverse = { 5592405, 5592405, 5592405, 5592405, 5592405, 5592405, 14800213 }
|
|
19
|
-
local r2 = { 13533400, 837116, 6278376, 13533388, 837116, 6278376, 7504076 }
|
|
21
|
+
local pInverse: BigInt = { 5592405, 5592405, 5592405, 5592405, 5592405, 5592405, 14800213 }
|
|
22
|
+
local r2: BigInt = { 13533400, 837116, 6278376, 13533388, 837116, 6278376, 7504076 }
|
|
20
23
|
|
|
21
|
-
local function multByP(a)
|
|
24
|
+
local function multByP(a: BigInt): DoubleInt
|
|
22
25
|
local a1, a2, a3, a4, a5, a6, a7 = a[1], a[2], a[3], a[4], a[5], a[6], a[7]
|
|
23
26
|
|
|
24
27
|
local c1 = a1 * 3
|
|
@@ -82,7 +85,7 @@ local function multByP(a)
|
|
|
82
85
|
end
|
|
83
86
|
|
|
84
87
|
-- Reduces a number from [0, 2p - 1] to [0, p - 1]
|
|
85
|
-
local function reduceModP(a)
|
|
88
|
+
local function reduceModP(a: BigInt): BigInt
|
|
86
89
|
-- a < p
|
|
87
90
|
if a[7] < 15761408 or a[7] == 15761408 and a[1] < 3 then
|
|
88
91
|
return { table.unpack(a) }
|
|
@@ -133,11 +136,11 @@ local function reduceModP(a)
|
|
|
133
136
|
return { c1, c2, c3, c4, c5, c6, c7 }
|
|
134
137
|
end
|
|
135
138
|
|
|
136
|
-
local function addModP(a, b)
|
|
139
|
+
local function addModP(a: BigInt, b: BigInt): BigInt
|
|
137
140
|
return reduceModP(add(a, b))
|
|
138
141
|
end
|
|
139
142
|
|
|
140
|
-
local function subModP(a, b)
|
|
143
|
+
local function subModP(a: BigInt, b: BigInt): BigInt
|
|
141
144
|
local result = sub(a, b)
|
|
142
145
|
|
|
143
146
|
if result[7] < 0 then
|
|
@@ -149,29 +152,29 @@ end
|
|
|
149
152
|
|
|
150
153
|
-- Montgomery REDC algorithn
|
|
151
154
|
-- Reduces a number from [0, p^2 - 1] to [0, p - 1]
|
|
152
|
-
local function REDC(T)
|
|
155
|
+
local function REDC(T: DoubleInt): BigInt
|
|
153
156
|
local m = mult(T, pInverse, true)
|
|
154
|
-
local t = { table.unpack(addDouble(T, multByP(m)), 8, 14) }
|
|
157
|
+
local t: BigInt = { table.unpack(addDouble(T, multByP(m)), 8, 14) }
|
|
155
158
|
|
|
156
159
|
return reduceModP(t)
|
|
157
160
|
end
|
|
158
161
|
|
|
159
|
-
local function multModP(a, b)
|
|
162
|
+
local function multModP(a: BigInt, b: BigInt): BigInt
|
|
160
163
|
-- Only works with a, b in Montgomery form
|
|
161
|
-
return REDC(mult(a, b))
|
|
164
|
+
return REDC(mult(a, b, false))
|
|
162
165
|
end
|
|
163
166
|
|
|
164
|
-
local function squareModP(a)
|
|
167
|
+
local function squareModP(a: BigInt): BigInt
|
|
165
168
|
-- Only works with a in Montgomery form
|
|
166
169
|
return REDC(square(a))
|
|
167
170
|
end
|
|
168
171
|
|
|
169
|
-
local function montgomeryModP(a)
|
|
172
|
+
local function montgomeryModP(a: BigInt): BigInt
|
|
170
173
|
return multModP(a, r2)
|
|
171
174
|
end
|
|
172
175
|
|
|
173
|
-
local function inverseMontgomeryModP(a)
|
|
174
|
-
local newA = { table.unpack(a) }
|
|
176
|
+
local function inverseMontgomeryModP(a: BigInt): BigInt
|
|
177
|
+
local newA: DoubleInt = { table.unpack(a) }
|
|
175
178
|
|
|
176
179
|
for i = 8, 14 do
|
|
177
180
|
newA[i] = 0
|
|
@@ -180,11 +183,11 @@ local function inverseMontgomeryModP(a)
|
|
|
180
183
|
return REDC(newA)
|
|
181
184
|
end
|
|
182
185
|
|
|
183
|
-
local ONE = montgomeryModP({ 1, 0, 0, 0, 0, 0, 0 })
|
|
186
|
+
local ONE: BigInt = montgomeryModP({ 1, 0, 0, 0, 0, 0, 0 })
|
|
184
187
|
|
|
185
|
-
local function expModP(base, exponentBinary)
|
|
186
|
-
local newBase = { table.unpack(base) }
|
|
187
|
-
local result = { table.unpack(ONE) }
|
|
188
|
+
local function expModP(base: BigInt, exponentBinary: { number }): BigInt
|
|
189
|
+
local newBase: BigInt = { table.unpack(base) }
|
|
190
|
+
local result: BigInt = { table.unpack(ONE) }
|
|
188
191
|
|
|
189
192
|
for i = 1, 168 do
|
|
190
193
|
if exponentBinary[i] == 1 then
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--!native
|
|
3
3
|
|
|
4
4
|
-- Arithmetic on the Finite Field of Integers modulo q
|
|
@@ -8,6 +8,8 @@ local random = require(script.Parent.random)
|
|
|
8
8
|
local sha256 = require(script.Parent.sha256)
|
|
9
9
|
local util = require(script.Parent.util)
|
|
10
10
|
|
|
11
|
+
type BigInt = { number }
|
|
12
|
+
|
|
11
13
|
local isEqual = arith.isEqual
|
|
12
14
|
local compare = arith.compare
|
|
13
15
|
local add = arith.add
|
|
@@ -18,11 +20,11 @@ local square = arith.square
|
|
|
18
20
|
local encodeInt = arith.encodeInt
|
|
19
21
|
local decodeInt = arith.decodeInt
|
|
20
22
|
|
|
21
|
-
local modQMT
|
|
23
|
+
local modQMT: any
|
|
22
24
|
|
|
23
|
-
local q = { 9622359, 6699217, 13940450, 16775734, 16777215, 16777215, 3940351 }
|
|
25
|
+
local q: BigInt = { 9622359, 6699217, 13940450, 16775734, 16777215, 16777215, 3940351 }
|
|
24
26
|
-- this isn't an optimization, it just shortens the amount of time I have to scroll
|
|
25
|
-
local qMinusTwoBinary = table.create(166, 1)
|
|
27
|
+
local qMinusTwoBinary: { number } = table.create(166, 1)
|
|
26
28
|
qMinusTwoBinary[2] = 0
|
|
27
29
|
qMinusTwoBinary[4] = 0
|
|
28
30
|
qMinusTwoBinary[6] = 0
|
|
@@ -76,59 +78,59 @@ qMinusTwoBinary[162] = 0
|
|
|
76
78
|
-- r = 2^168
|
|
77
79
|
-- q * qInverse = -1 (mod r)
|
|
78
80
|
-- r2 = r * r (mod q)
|
|
79
|
-
local qInverse = { 15218585, 5740955, 3271338, 9903997, 9067368, 7173545, 6988392 }
|
|
80
|
-
local r2 = { 1336213, 11071705, 9716828, 11083885, 9188643, 1494868, 3306114 }
|
|
81
|
+
local qInverse: BigInt = { 15218585, 5740955, 3271338, 9903997, 9067368, 7173545, 6988392 }
|
|
82
|
+
local r2: BigInt = { 1336213, 11071705, 9716828, 11083885, 9188643, 1494868, 3306114 }
|
|
81
83
|
|
|
82
84
|
-- Reduces a number from [0, 2q - 1] to [0, q - 1]
|
|
83
|
-
local function reduceModQ(a)
|
|
84
|
-
local result = { table.unpack(a) }
|
|
85
|
+
local function reduceModQ(a: BigInt): BigInt
|
|
86
|
+
local result: BigInt = { table.unpack(a) }
|
|
85
87
|
|
|
86
88
|
if compare(result, q) >= 0 then
|
|
87
89
|
result = sub(result, q)
|
|
88
90
|
end
|
|
89
91
|
|
|
90
|
-
return setmetatable(result, modQMT)
|
|
92
|
+
return setmetatable(result, modQMT) :: any
|
|
91
93
|
end
|
|
92
94
|
|
|
93
|
-
local function addModQ(a, b)
|
|
95
|
+
local function addModQ(a: BigInt, b: BigInt): BigInt
|
|
94
96
|
return reduceModQ(add(a, b))
|
|
95
97
|
end
|
|
96
98
|
|
|
97
|
-
local function subModQ(a, b)
|
|
98
|
-
local result = sub(a, b)
|
|
99
|
+
local function subModQ(a: BigInt, b: BigInt): BigInt
|
|
100
|
+
local result: BigInt = sub(a, b)
|
|
99
101
|
|
|
100
102
|
if result[7] < 0 then
|
|
101
103
|
result = add(result, q)
|
|
102
104
|
end
|
|
103
105
|
|
|
104
|
-
return setmetatable(result, modQMT)
|
|
106
|
+
return setmetatable(result, modQMT) :: any
|
|
105
107
|
end
|
|
106
108
|
|
|
107
109
|
-- Montgomery REDC algorithn
|
|
108
110
|
-- Reduces a number from [0, q^2 - 1] to [0, q - 1]
|
|
109
|
-
local function REDC(T)
|
|
110
|
-
local m = { table.unpack(mult({ table.unpack(T, 1, 7) }, qInverse, true), 1, 7) }
|
|
111
|
-
local t = { table.unpack(addDouble(T, mult(m, q)), 8, 14) }
|
|
111
|
+
local function REDC(T: { number }): BigInt
|
|
112
|
+
local m: BigInt = { table.unpack(mult({ table.unpack(T, 1, 7) }, qInverse, true), 1, 7) }
|
|
113
|
+
local t: BigInt = { table.unpack(addDouble(T, mult(m, q, false)), 8, 14) }
|
|
112
114
|
|
|
113
115
|
return reduceModQ(t)
|
|
114
116
|
end
|
|
115
117
|
|
|
116
|
-
local function multModQ(a, b)
|
|
118
|
+
local function multModQ(a: BigInt, b: BigInt): BigInt
|
|
117
119
|
-- Only works with a, b in Montgomery form
|
|
118
|
-
return REDC(mult(a, b))
|
|
120
|
+
return REDC(mult(a, b, false))
|
|
119
121
|
end
|
|
120
122
|
|
|
121
|
-
local function squareModQ(a)
|
|
123
|
+
local function squareModQ(a: BigInt): BigInt
|
|
122
124
|
-- Only works with a in Montgomery form
|
|
123
125
|
return REDC(square(a))
|
|
124
126
|
end
|
|
125
127
|
|
|
126
|
-
local function montgomeryModQ(a)
|
|
128
|
+
local function montgomeryModQ(a: BigInt): BigInt
|
|
127
129
|
return multModQ(a, r2)
|
|
128
130
|
end
|
|
129
131
|
|
|
130
|
-
local function inverseMontgomeryModQ(a)
|
|
131
|
-
local newA = { table.unpack(a) }
|
|
132
|
+
local function inverseMontgomeryModQ(a: BigInt): BigInt
|
|
133
|
+
local newA: { number } = { table.unpack(a) }
|
|
132
134
|
|
|
133
135
|
for i = 8, 14 do
|
|
134
136
|
newA[i] = 0
|
|
@@ -137,11 +139,11 @@ local function inverseMontgomeryModQ(a)
|
|
|
137
139
|
return REDC(newA)
|
|
138
140
|
end
|
|
139
141
|
|
|
140
|
-
local ONE = montgomeryModQ({ 1, 0, 0, 0, 0, 0, 0 })
|
|
142
|
+
local ONE: BigInt = montgomeryModQ({ 1, 0, 0, 0, 0, 0, 0 })
|
|
141
143
|
|
|
142
|
-
local function expModQ(base, exponentBinary)
|
|
143
|
-
local newBase = { table.unpack(base) }
|
|
144
|
-
local result = { table.unpack(ONE) }
|
|
144
|
+
local function expModQ(base: BigInt, exponentBinary: { number }): BigInt
|
|
145
|
+
local newBase: BigInt = { table.unpack(base) }
|
|
146
|
+
local result: BigInt = { table.unpack(ONE) }
|
|
145
147
|
|
|
146
148
|
for i = 1, 168 do
|
|
147
149
|
if exponentBinary[i] == 1 then
|
|
@@ -154,9 +156,9 @@ local function expModQ(base, exponentBinary)
|
|
|
154
156
|
return result
|
|
155
157
|
end
|
|
156
158
|
|
|
157
|
-
local function intExpModQ(base, exponent)
|
|
158
|
-
local newBase = { table.unpack(base) }
|
|
159
|
-
local result = setmetatable({ table.unpack(ONE) }, modQMT)
|
|
159
|
+
local function intExpModQ(base: BigInt, exponent: number): BigInt
|
|
160
|
+
local newBase: BigInt = { table.unpack(base) }
|
|
161
|
+
local result: BigInt = setmetatable({ table.unpack(ONE) }, modQMT) :: any
|
|
160
162
|
|
|
161
163
|
if exponent < 0 then
|
|
162
164
|
newBase = expModQ(newBase, qMinusTwoBinary)
|
|
@@ -175,46 +177,46 @@ local function intExpModQ(base, exponent)
|
|
|
175
177
|
return result
|
|
176
178
|
end
|
|
177
179
|
|
|
178
|
-
local function encodeModQ(a)
|
|
180
|
+
local function encodeModQ(a: BigInt): { number }
|
|
179
181
|
local result = encodeInt(a)
|
|
180
182
|
|
|
181
|
-
return setmetatable(result, util.byteTableMT)
|
|
183
|
+
return setmetatable(result, util.byteTableMT) :: any
|
|
182
184
|
end
|
|
183
185
|
|
|
184
|
-
local function decodeModQ(s)
|
|
185
|
-
s = type(s) == "table" and { table.unpack(s, 1, 21) } or { string.byte(tostring(s), 1, 21) }
|
|
186
|
-
local result = decodeInt(s)
|
|
186
|
+
local function decodeModQ(s: any): BigInt
|
|
187
|
+
s = type(s) == "table" and { table.unpack(s :: { number }, 1, 21) } or { string.byte(tostring(s), 1, 21) }
|
|
188
|
+
local result: BigInt = decodeInt(s)
|
|
187
189
|
result[7] %= q[7]
|
|
188
190
|
|
|
189
|
-
return setmetatable(result, modQMT)
|
|
191
|
+
return setmetatable(result, modQMT) :: any
|
|
190
192
|
end
|
|
191
193
|
|
|
192
|
-
local function randomModQ()
|
|
194
|
+
local function randomModQ(): BigInt
|
|
193
195
|
while true do
|
|
194
|
-
local s = { table.unpack(random.random(), 1, 21) }
|
|
195
|
-
local result = decodeInt(s)
|
|
196
|
+
local s: { number } = { table.unpack(random.random() :: any, 1, 21) }
|
|
197
|
+
local result: BigInt = decodeInt(s)
|
|
196
198
|
if result[7] < q[7] then
|
|
197
|
-
return setmetatable(result, modQMT)
|
|
199
|
+
return setmetatable(result, modQMT) :: any
|
|
198
200
|
end
|
|
199
201
|
end
|
|
200
202
|
end
|
|
201
203
|
|
|
202
|
-
local function hashModQ(data)
|
|
204
|
+
local function hashModQ(data: any): BigInt
|
|
203
205
|
return decodeModQ(sha256.digest(data))
|
|
204
206
|
end
|
|
205
207
|
|
|
206
208
|
modQMT = {
|
|
207
209
|
__index = {
|
|
208
|
-
encode = function(self)
|
|
210
|
+
encode = function(self: BigInt): { number }
|
|
209
211
|
return encodeModQ(self)
|
|
210
212
|
end,
|
|
211
213
|
},
|
|
212
214
|
|
|
213
|
-
__tostring = function(self)
|
|
214
|
-
return self:encode():toHex()
|
|
215
|
+
__tostring = function(self: BigInt): string
|
|
216
|
+
return (self :: any):encode():toHex()
|
|
215
217
|
end,
|
|
216
218
|
|
|
217
|
-
__add = function(self, other)
|
|
219
|
+
__add = function(self: any, other: any): BigInt
|
|
218
220
|
if type(self) == "number" then
|
|
219
221
|
return other + self
|
|
220
222
|
end
|
|
@@ -227,7 +229,7 @@ modQMT = {
|
|
|
227
229
|
return addModQ(self, other)
|
|
228
230
|
end,
|
|
229
231
|
|
|
230
|
-
__sub = function(a, b)
|
|
232
|
+
__sub = function(a: any, b: any): BigInt
|
|
231
233
|
if type(a) == "number" then
|
|
232
234
|
assert(a < 16777216, "number operand too big")
|
|
233
235
|
a = montgomeryModQ({ a, 0, 0, 0, 0, 0, 0 })
|
|
@@ -241,15 +243,15 @@ modQMT = {
|
|
|
241
243
|
return subModQ(a, b)
|
|
242
244
|
end,
|
|
243
245
|
|
|
244
|
-
__unm = function(self)
|
|
246
|
+
__unm = function(self: BigInt): BigInt
|
|
245
247
|
return subModQ(q, self)
|
|
246
248
|
end,
|
|
247
249
|
|
|
248
|
-
__eq = function(self, other)
|
|
250
|
+
__eq = function(self: BigInt, other: BigInt): boolean
|
|
249
251
|
return isEqual(self, other)
|
|
250
252
|
end,
|
|
251
253
|
|
|
252
|
-
__mul = function(self, other)
|
|
254
|
+
__mul = function(self: any, other: any): BigInt
|
|
253
255
|
if type(self) == "number" then
|
|
254
256
|
return other * self
|
|
255
257
|
end
|
|
@@ -268,7 +270,7 @@ modQMT = {
|
|
|
268
270
|
return multModQ(self, other)
|
|
269
271
|
end,
|
|
270
272
|
|
|
271
|
-
__div = function(a, b)
|
|
273
|
+
__div = function(a: any, b: any): BigInt
|
|
272
274
|
if type(a) == "number" then
|
|
273
275
|
assert(a < 16777216, "number operand too big")
|
|
274
276
|
a = montgomeryModQ({ a, 0, 0, 0, 0, 0, 0 })
|
|
@@ -279,12 +281,12 @@ modQMT = {
|
|
|
279
281
|
b = montgomeryModQ({ b, 0, 0, 0, 0, 0, 0 })
|
|
280
282
|
end
|
|
281
283
|
|
|
282
|
-
local bInv = expModQ(b, qMinusTwoBinary)
|
|
284
|
+
local bInv: BigInt = expModQ(b, qMinusTwoBinary)
|
|
283
285
|
|
|
284
286
|
return multModQ(a, bInv)
|
|
285
287
|
end,
|
|
286
288
|
|
|
287
|
-
__pow = function(self, other)
|
|
289
|
+
__pow = function(self: BigInt, other: number): BigInt
|
|
288
290
|
return intExpModQ(self, other)
|
|
289
291
|
end,
|
|
290
292
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--!native
|
|
3
3
|
|
|
4
4
|
-- random.lua - Random Byte Generator
|
|
5
5
|
local sha256 = require(script.Parent.sha256)
|
|
6
6
|
|
|
7
|
-
local entropy = ""
|
|
8
|
-
local accumulator
|
|
7
|
+
local entropy: string = ""
|
|
8
|
+
local accumulator: { string } = {}
|
|
9
|
+
local accumulator_len: number = 0
|
|
9
10
|
|
|
10
11
|
local random = {}
|
|
11
12
|
|
|
12
|
-
local function feed(data)
|
|
13
|
+
local function feed(data: any)
|
|
13
14
|
accumulator_len += 1
|
|
14
15
|
accumulator[accumulator_len] = tostring(data or "")
|
|
15
16
|
end
|
|
@@ -21,7 +22,7 @@ local function digest()
|
|
|
21
22
|
accumulator_len = 0
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
local entropyInitialized = false
|
|
25
|
+
local entropyInitialized: boolean = false
|
|
25
26
|
|
|
26
27
|
-- Defer this initialization until requested
|
|
27
28
|
local function ensureEntropyInit()
|
|
@@ -55,7 +56,7 @@ local function ensureEntropyInit()
|
|
|
55
56
|
-- TODO: Suppress this warning
|
|
56
57
|
warn(
|
|
57
58
|
string.format(
|
|
58
|
-
"[EllipticCurveCryptography.random] - Generating entropy took %
|
|
59
|
+
"[EllipticCurveCryptography.random] - Generating entropy took %g ms",
|
|
59
60
|
1000 * (os.clock() - startTime)
|
|
60
61
|
)
|
|
61
62
|
)
|
|
@@ -72,7 +73,7 @@ function random.save()
|
|
|
72
73
|
entropy = tostring(sha256.digest(entropy))
|
|
73
74
|
end
|
|
74
75
|
|
|
75
|
-
function random.seed(data)
|
|
76
|
+
function random.seed(data: any)
|
|
76
77
|
ensureEntropyInit()
|
|
77
78
|
|
|
78
79
|
feed("seed")
|
|
@@ -83,7 +84,7 @@ function random.seed(data)
|
|
|
83
84
|
random.save()
|
|
84
85
|
end
|
|
85
86
|
|
|
86
|
-
function random.random()
|
|
87
|
+
function random.random(): any
|
|
87
88
|
ensureEntropyInit()
|
|
88
89
|
|
|
89
90
|
feed("random")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--!
|
|
1
|
+
--!strict
|
|
2
2
|
--!native
|
|
3
3
|
|
|
4
4
|
-- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
|
|
@@ -10,22 +10,24 @@
|
|
|
10
10
|
-- Last update: October 10, 2017
|
|
11
11
|
-- Updated by Quenty December 4th, 2023
|
|
12
12
|
|
|
13
|
-
local twoPower = require(script.Parent.twoPower)
|
|
13
|
+
local twoPower: { [number]: number } = require(script.Parent.twoPower) :: any
|
|
14
14
|
local util = require(script.Parent.util)
|
|
15
15
|
|
|
16
|
+
type ByteTable = typeof(setmetatable({} :: { number }, {} :: typeof(util.byteTableMT)))
|
|
17
|
+
|
|
16
18
|
local mod32 = 2 ^ 32
|
|
17
19
|
local band = bit32.band
|
|
18
20
|
local bnot = bit32.bnot
|
|
19
21
|
local bxor = bit32.bxor
|
|
20
22
|
local blshift = bit32.lshift
|
|
21
23
|
|
|
22
|
-
local function rrotate(n, b)
|
|
24
|
+
local function rrotate(n: number, b: number): number
|
|
23
25
|
local s = n / twoPower[b]
|
|
24
26
|
local f = s % 1
|
|
25
27
|
return (s - f) + f * mod32
|
|
26
28
|
end
|
|
27
29
|
|
|
28
|
-
local function brshift(int, by) -- Thanks bit32 for bad rshift
|
|
30
|
+
local function brshift(int: number, by: number): number -- Thanks bit32 for bad rshift
|
|
29
31
|
return math.floor(int / twoPower[by])
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -107,7 +109,7 @@ local K = {
|
|
|
107
109
|
0xc67178f2,
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
local function counter(incr)
|
|
112
|
+
local function counter(incr: number): (number, number)
|
|
111
113
|
local t1, t2 = 0, 0
|
|
112
114
|
if 0xFFFFFFFF - t1 < incr then
|
|
113
115
|
t2 = t2 + 1
|
|
@@ -119,11 +121,11 @@ local function counter(incr)
|
|
|
119
121
|
return t2, t1
|
|
120
122
|
end
|
|
121
123
|
|
|
122
|
-
local function BE_toInt(bs, i)
|
|
124
|
+
local function BE_toInt(bs: { number }, i: number): number
|
|
123
125
|
return blshift((bs[i] or 0), 24) + blshift((bs[i + 1] or 0), 16) + blshift((bs[i + 2] or 0), 8) + (bs[i + 3] or 0)
|
|
124
126
|
end
|
|
125
127
|
|
|
126
|
-
local function preprocess(data)
|
|
128
|
+
local function preprocess(data: { number }): { { number } }
|
|
127
129
|
local len = #data
|
|
128
130
|
local data_len = #data + 1
|
|
129
131
|
|
|
@@ -135,9 +137,9 @@ local function preprocess(data)
|
|
|
135
137
|
|
|
136
138
|
local blocks = math.ceil(data_len / 64)
|
|
137
139
|
|
|
138
|
-
local proc = table.create(blocks)
|
|
140
|
+
local proc: { { number } } = table.create(blocks)
|
|
139
141
|
for i = 1, blocks do
|
|
140
|
-
local block = table.create(16)
|
|
142
|
+
local block: { number } = table.create(16)
|
|
141
143
|
proc[i] = block
|
|
142
144
|
for j = 1, 16 do
|
|
143
145
|
block[j] = BE_toInt(data, 1 + ((i - 1) * 64) + ((j - 1) * 4))
|
|
@@ -148,7 +150,7 @@ local function preprocess(data)
|
|
|
148
150
|
return proc
|
|
149
151
|
end
|
|
150
152
|
|
|
151
|
-
local function digestblock(w, C)
|
|
153
|
+
local function digestblock(w: { number }, C: { number }): { number }
|
|
152
154
|
for j = 17, 64 do
|
|
153
155
|
local s0 = bxor(bxor(rrotate(w[j - 15], 7), rrotate(w[j - 15], 18)), brshift(w[j - 15], 3))
|
|
154
156
|
local s1 = bxor(bxor(rrotate(w[j - 2], 17), rrotate(w[j - 2], 19)), brshift(w[j - 2], 10))
|
|
@@ -177,8 +179,8 @@ local function digestblock(w, C)
|
|
|
177
179
|
return C
|
|
178
180
|
end
|
|
179
181
|
|
|
180
|
-
local function toBytes(t, n)
|
|
181
|
-
local b = table.create(n * 4)
|
|
182
|
+
local function toBytes(t: { number }, n: number): ByteTable
|
|
183
|
+
local b: { number } = table.create(n * 4)
|
|
182
184
|
for i = 1, n do
|
|
183
185
|
b[(i - 1) * 4 + 1] = band(brshift(t[i], 24), 0xFF)
|
|
184
186
|
b[(i - 1) * 4 + 2] = band(brshift(t[i], 16), 0xFF)
|
|
@@ -189,29 +191,36 @@ local function toBytes(t, n)
|
|
|
189
191
|
return setmetatable(b, util.byteTableMT)
|
|
190
192
|
end
|
|
191
193
|
|
|
192
|
-
local function digest(data)
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
local function digest(data: (string | { number })?): ByteTable
|
|
195
|
+
local rawData: string | { number } = data or ""
|
|
196
|
+
local byteData: { number }
|
|
197
|
+
if type(rawData) == "table" then
|
|
198
|
+
byteData = { table.unpack(rawData) }
|
|
199
|
+
else
|
|
200
|
+
byteData = util.stringToByteArray(rawData)
|
|
201
|
+
end
|
|
195
202
|
|
|
196
|
-
|
|
197
|
-
local C = { table.unpack(H) }
|
|
198
|
-
for _, value in ipairs(
|
|
203
|
+
local proc = preprocess(byteData)
|
|
204
|
+
local C: { number } = { table.unpack(H) }
|
|
205
|
+
for _, value in ipairs(proc) do
|
|
199
206
|
C = digestblock(value, C)
|
|
200
207
|
end
|
|
201
208
|
|
|
202
209
|
return toBytes(C, 8)
|
|
203
210
|
end
|
|
204
211
|
|
|
205
|
-
local function hmac(data, key)
|
|
206
|
-
local actualData = type(data) == "table" and { table.unpack(data
|
|
207
|
-
|
|
212
|
+
local function hmac(data: string | { number }, key: string | { number }): ByteTable
|
|
213
|
+
local actualData: { number } = type(data) == "table" and { table.unpack(data :: { number }) }
|
|
214
|
+
or util.stringToByteArray(data :: string)
|
|
215
|
+
local actualKey: { number } = type(key) == "table" and { table.unpack(key :: { number }) }
|
|
216
|
+
or util.stringToByteArray(key :: string)
|
|
208
217
|
|
|
209
218
|
local blocksize = 64
|
|
210
219
|
|
|
211
|
-
actualKey = #actualKey > blocksize and digest(actualKey) or actualKey
|
|
220
|
+
actualKey = #actualKey > blocksize and (digest(actualKey) :: any) or actualKey
|
|
212
221
|
|
|
213
|
-
local ipad = table.create(blocksize)
|
|
214
|
-
local opad = table.create(blocksize)
|
|
222
|
+
local ipad: { number } = table.create(blocksize)
|
|
223
|
+
local opad: { number } = table.create(blocksize)
|
|
215
224
|
|
|
216
225
|
for i = 1, blocksize do
|
|
217
226
|
ipad[i] = bxor(0x36, actualKey[i] or 0)
|
|
@@ -222,26 +231,27 @@ local function hmac(data, key)
|
|
|
222
231
|
ipad[blocksize + i] = value
|
|
223
232
|
end
|
|
224
233
|
|
|
225
|
-
|
|
226
|
-
local padded_key = table.create(blocksize * 2)
|
|
234
|
+
local ipadDigest = digest(ipad)
|
|
235
|
+
local padded_key: { number } = table.create(blocksize * 2)
|
|
227
236
|
for i = 1, blocksize do
|
|
228
237
|
padded_key[i] = opad[i]
|
|
229
|
-
padded_key[blocksize + i] =
|
|
238
|
+
padded_key[blocksize + i] = ipadDigest[i]
|
|
230
239
|
end
|
|
231
240
|
|
|
232
241
|
return digest(padded_key)
|
|
233
242
|
end
|
|
234
243
|
|
|
235
|
-
local function pbkdf2(pass, salt, iter, dklen)
|
|
236
|
-
local actualSalt = type(salt) == "table" and salt
|
|
244
|
+
local function pbkdf2(pass: string | { number }, salt: string | { number }, iter: number, dklen: number?): ByteTable
|
|
245
|
+
local actualSalt: { number } = type(salt) == "table" and salt :: { number }
|
|
246
|
+
or util.stringToByteArray(salt :: string)
|
|
237
247
|
local hashlen = 32
|
|
238
248
|
local actualDklen = dklen or 32
|
|
239
249
|
local block = 1
|
|
240
|
-
local out = {}
|
|
250
|
+
local out: { number } = {}
|
|
241
251
|
|
|
242
252
|
while actualDklen > 0 do
|
|
243
|
-
local ikey = {}
|
|
244
|
-
local isalt = { table.unpack(actualSalt) }
|
|
253
|
+
local ikey: { number } = {}
|
|
254
|
+
local isalt: { number } = { table.unpack(actualSalt) }
|
|
245
255
|
local isalt_len = #isalt
|
|
246
256
|
local clen = actualDklen > hashlen and hashlen or actualDklen
|
|
247
257
|
|
|
@@ -253,7 +263,7 @@ local function pbkdf2(pass, salt, iter, dklen)
|
|
|
253
263
|
isalt_len += 4
|
|
254
264
|
|
|
255
265
|
for _ = 1, iter do
|
|
256
|
-
isalt = hmac(isalt, pass)
|
|
266
|
+
isalt = hmac(isalt, pass) :: any
|
|
257
267
|
for k = 1, clen do
|
|
258
268
|
ikey[k] = bxor(isalt[k], ikey[k] or 0)
|
|
259
269
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
--!
|
|
2
|
-
local twoPower = setmetatable({}, {
|
|
3
|
-
__index = function(self, index)
|
|
1
|
+
--!strict
|
|
2
|
+
local twoPower: { [number]: number } = setmetatable({}, {
|
|
3
|
+
__index = function(self: { [number]: number }, index: number): number
|
|
4
4
|
local value = 2 ^ index
|
|
5
5
|
self[index] = value
|
|
6
6
|
return value
|
|
7
7
|
end,
|
|
8
|
-
})
|
|
8
|
+
}) :: any
|
|
9
9
|
|
|
10
10
|
-- NOTE: This takes somewhere between 1.5 ms to 4 ms
|
|
11
11
|
-- precache
|
package/src/Shared/{EllipticCurveCryptography/testing.spec.lua → EllipticCurveCryptography.spec.lua}
RENAMED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
--!nonstrict
|
|
2
|
-
local require = (
|
|
3
|
-
game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
|
|
4
|
-
).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
|
|
2
|
+
local require = require(script.Parent.loader).load(script)
|
|
5
3
|
|
|
6
4
|
local Jest = require("Jest")
|
|
7
|
-
local ecc = require(
|
|
5
|
+
local ecc = require("EllipticCurveCryptography")
|
|
8
6
|
|
|
9
7
|
local describe = Jest.Globals.describe
|
|
10
8
|
local expect = Jest.Globals.expect
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
--!nonstrict
|
|
2
|
-
local require = (
|
|
3
|
-
game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
|
|
4
|
-
).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
|
|
2
|
+
local require = require(script.Parent.loader).load(script)
|
|
5
3
|
|
|
6
4
|
local Jest = require("Jest")
|
|
7
|
-
local ecc = require(
|
|
5
|
+
local ecc = require("EllipticCurveCryptography")
|
|
8
6
|
|
|
9
7
|
local describe = Jest.Globals.describe
|
|
10
8
|
local expect = Jest.Globals.expect
|