@quenty/ellipticcurvecryptography 1.5.0 → 1.6.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
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
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.6.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ellipticcurvecryptography@1.5.0...@quenty/ellipticcurvecryptography@1.6.0) (2025-04-02)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Fix broken tests ([96485ff](https://github.com/Quenty/NevermoreEngine/commit/96485ff69dbba007d13ea4b5fe82f67244fda14c))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [1.5.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ellipticcurvecryptography@1.4.0...@quenty/ellipticcurvecryptography@1.5.0) (2024-09-25)
|
|
7
18
|
|
|
8
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/ellipticcurvecryptography",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Elliptic curve cryptography forked from BoatBomber, forked from ComputerCraft",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "e8ea56930e65322fcffc05a1556d5df988068f0b"
|
|
32
32
|
}
|
|
@@ -1,63 +1,67 @@
|
|
|
1
|
-
|
|
1
|
+
local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).bootstrapStory(script)
|
|
2
|
+
|
|
3
|
+
local Jest = require("Jest")
|
|
2
4
|
local ecc = require(script.Parent)
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
local describe = Jest.Globals.describe
|
|
7
|
+
local expect = Jest.Globals.expect
|
|
8
|
+
local it = Jest.Globals.it
|
|
5
9
|
|
|
6
|
-
--
|
|
7
|
-
local function
|
|
8
|
-
|
|
10
|
+
-- helper function
|
|
11
|
+
local function generateTestData(size)
|
|
12
|
+
local data = table.create(size)
|
|
13
|
+
for x = 1, size do
|
|
14
|
+
data[x] = math.random(35, 120)
|
|
15
|
+
end
|
|
16
|
+
return string.char(table.unpack(data))
|
|
9
17
|
end
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
local
|
|
13
|
-
local clientPrivate, clientPublic = ecc.keypair(ecc.random.random())
|
|
14
|
-
|
|
15
|
-
-- print("\nserverPrivate:",printBytes(serverPrivate),"\nserverPublic:",printBytes(serverPublic))
|
|
16
|
-
-- print("\nclientPrivate:",printBytes(clientPrivate),"\nclientPublic:",printBytes(clientPublic))
|
|
19
|
+
describe("EllipticCurveCryptography Performance", function()
|
|
20
|
+
local N, S = 500, 100 -- N iterations, S bytes per payload
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
local
|
|
20
|
-
local
|
|
22
|
+
it(string.format("should efficiently process %d payloads of %d bytes", N, S), function()
|
|
23
|
+
local serverPrivate, serverPublic = ecc.keypair(DateTime.now().UnixTimestamp)
|
|
24
|
+
local clientPrivate, clientPublic = ecc.keypair(DateTime.now().UnixTimestamp)
|
|
25
|
+
local serverSecret = ecc.exchange(serverPrivate, clientPublic)
|
|
26
|
+
local clientSecret = ecc.exchange(clientPrivate, serverPublic)
|
|
21
27
|
|
|
22
|
-
--
|
|
28
|
+
-- verify shared secret matches before benchmarking
|
|
29
|
+
expect(tostring(serverSecret)).toEqual(tostring(clientSecret))
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
local encryptSum, decryptSum = 0, 0
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
for _ = 1, N do
|
|
34
|
+
local payload = generateTestData(S)
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
local
|
|
30
|
-
local
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
data[x] = math.random(35, 120)
|
|
34
|
-
end
|
|
35
|
-
local payload = string.char(table.unpack(data))
|
|
36
|
+
-- measure encryption + signing
|
|
37
|
+
local start = os.clock()
|
|
38
|
+
local ciphertext = ecc.encrypt(payload, clientSecret)
|
|
39
|
+
local sig = ecc.sign(clientPrivate, payload)
|
|
40
|
+
encryptSum += os.clock() - start
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
-- measure decryption + verification
|
|
43
|
+
start = os.clock()
|
|
44
|
+
local plaintext = ecc.decrypt(ciphertext, serverSecret)
|
|
45
|
+
ecc.verify(clientPublic, plaintext, sig)
|
|
46
|
+
decryptSum += os.clock() - start
|
|
47
|
+
end
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
-- calculate metrics
|
|
50
|
+
local encryptTotal = encryptSum * 1000 -- convert to ms
|
|
51
|
+
local encryptAvg = (encryptSum / N) * 1000
|
|
52
|
+
local decryptTotal = decryptSum * 1000
|
|
53
|
+
local decryptAvg = (decryptSum / N) * 1000
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
end
|
|
55
|
+
-- performance expectations
|
|
56
|
+
-- expect(encryptAvg).toBeLessThan(1) -- expect sub-1ms average for encryption
|
|
57
|
+
-- expect(decryptAvg).toBeLessThan(1) -- expect sub-1ms average for decryption
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
return true
|
|
59
|
+
-- log performance results (optional, but useful for debugging)
|
|
60
|
+
print(string.format(
|
|
61
|
+
"benchmark results:\n" ..
|
|
62
|
+
"encrypt & sign: %.2fms total, %.2fms avg\n" ..
|
|
63
|
+
"decrypt & verify: %.2fms total, %.2fms avg",
|
|
64
|
+
encryptTotal, encryptAvg, decryptTotal, decryptAvg
|
|
65
|
+
))
|
|
66
|
+
end, 30000)
|
|
67
|
+
end)
|
|
@@ -1,54 +1,51 @@
|
|
|
1
|
+
local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).bootstrapStory(script)
|
|
2
|
+
|
|
3
|
+
local Jest = require("Jest")
|
|
1
4
|
local ecc = require(script.Parent)
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
local describe = Jest.Globals.describe
|
|
7
|
+
local expect = Jest.Globals.expect
|
|
8
|
+
local it = Jest.Globals.it
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
local
|
|
7
|
-
|
|
10
|
+
local function generateTestData(size)
|
|
11
|
+
local data = table.create(size)
|
|
12
|
+
for x = 1, size do
|
|
13
|
+
data[x] = math.random(35, 120)
|
|
14
|
+
end
|
|
15
|
+
return string.char(table.unpack(data))
|
|
8
16
|
end
|
|
9
17
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
local
|
|
13
|
-
|
|
14
|
-
-- print("\nserverPrivate:",printBytes(serverPrivate),"\nserverPublic:",printBytes(serverPublic))
|
|
15
|
-
-- print("\nclientPrivate:",printBytes(clientPrivate),"\nclientPublic:",printBytes(clientPublic))
|
|
16
|
-
|
|
17
|
-
-- They share their publics and exchange to shared secret
|
|
18
|
-
local serverSecret = ecc.exchange(serverPrivate, clientPublic)
|
|
19
|
-
local clientSecret = ecc.exchange(clientPrivate, serverPublic)
|
|
20
|
-
|
|
21
|
-
--print("\nsharedSecret:", printBytes(serverSecret))
|
|
18
|
+
describe("EllipticCurveCryptography", function()
|
|
19
|
+
it("should generate matching shared secrets", function()
|
|
20
|
+
local serverPrivate, serverPublic = ecc.keypair(DateTime.now().UnixTimestamp)
|
|
21
|
+
local clientPrivate, clientPublic = ecc.keypair(DateTime.now().UnixTimestamp)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
local serverSecret = ecc.exchange(serverPrivate, clientPublic)
|
|
24
|
+
local clientSecret = ecc.exchange(clientPrivate, serverPublic)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for x = 1, 50 do
|
|
28
|
-
data[x] = math.random(35, 120)
|
|
29
|
-
end
|
|
30
|
-
local payload = string.char(table.unpack(data))
|
|
26
|
+
expect(tostring(serverSecret)).toEqual(tostring(clientSecret))
|
|
27
|
+
end)
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
it("should successfully encrypt, decrypt, and verify multiple payloads", function()
|
|
30
|
+
local serverPrivate, serverPublic = ecc.keypair(DateTime.now().UnixTimestamp)
|
|
31
|
+
local clientPrivate, clientPublic = ecc.keypair(DateTime.now().UnixTimestamp)
|
|
32
|
+
local serverSecret = ecc.exchange(serverPrivate, clientPublic)
|
|
33
|
+
local clientSecret = ecc.exchange(clientPrivate, serverPublic)
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
for _ = 1, 100 do
|
|
36
|
+
local payload = generateTestData(50)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
local validate = ecc.verify(clientPublic, plaintext, sig)
|
|
42
|
-
|
|
43
|
-
-- print("\ndecryptedPayload:",plaintext,"\nverified:",validate)
|
|
44
|
-
|
|
45
|
-
assert(payload ~= tostring(ciphertext), "Encrypted payload must be different from plaintext")
|
|
46
|
-
assert(payload == tostring(plaintext), "Decrypted data must equal the original payload")
|
|
47
|
-
assert(validate, "Signature must verify decrypted data")
|
|
48
|
-
|
|
49
|
-
--print(" Test run %d passed", i)
|
|
50
|
-
end
|
|
38
|
+
-- encrypt and sign
|
|
39
|
+
local ciphertext = ecc.encrypt(payload, clientSecret)
|
|
40
|
+
local sig = ecc.sign(clientPrivate, payload)
|
|
51
41
|
|
|
52
|
-
|
|
42
|
+
-- decrypt and verify
|
|
43
|
+
local plaintext = ecc.decrypt(ciphertext, serverSecret)
|
|
44
|
+
local validate = ecc.verify(clientPublic, plaintext, sig)
|
|
53
45
|
|
|
54
|
-
|
|
46
|
+
expect(payload).never.toEqual(tostring(ciphertext))
|
|
47
|
+
expect(payload).toEqual(tostring(plaintext))
|
|
48
|
+
expect(validate).toBe(true)
|
|
49
|
+
end
|
|
50
|
+
end)
|
|
51
|
+
end)
|