Skip to content

Commit 36b9004

Browse files
committed
test: add tests for invalid signature inputs and Koblitz encoding/decoding
1 parent 8f24242 commit 36b9004

File tree

4 files changed

+96
-23
lines changed

4 files changed

+96
-23
lines changed

src/algorithms.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class DigitalSignature {
8686
* @returns {boolean} True if the signature is valid, false otherwise.
8787
*/
8888
verify_signature(public_key, message_hash, r, s) {
89-
if (!(1 <= r < this.curve.n && 1 <= s < this.curve.n)) {
89+
if (r < 1n || r >= this.curve.n || s < 1n || s >= this.curve.n) {
9090
throw new Error('r or s are not in the valid range [1, curve order - 1].')
9191
}
9292

src/algorithms.test.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,54 @@ test('digital-signature: generate and verify signature', () => {
1818

1919
test('digital-signature: verify signature with invalid inputs', () => {
2020
const message_hash = BigInt(545454445644654n)
21+
const signature = ds.generate_signature(message_hash)
22+
2123
// Choose invalid r and s values (outside the range [1, n-1])
2224
const invalid_r = ds.curve.n
2325
const invalid_s = BigInt(0)
26+
2427
// Check that the appropriate exception is raised for invalid r and s
2528
expect(() => {
26-
ds.verify_signature(ds.public_key, message_hash, invalid_r, invalid_s)
27-
}).toThrowError()
29+
ds.verify_signature(
30+
ds.public_key,
31+
message_hash,
32+
invalid_r,
33+
BigInt(signature[1]),
34+
)
35+
}).toThrowError('r or s are not in the valid range [1, curve order - 1].')
36+
37+
expect(() => {
38+
ds.verify_signature(
39+
ds.public_key,
40+
message_hash,
41+
BigInt(signature[0]),
42+
invalid_s,
43+
)
44+
}).toThrowError('r or s are not in the valid range [1, curve order - 1].')
2845
})
2946

3047
const encoder = new Koblitz('secp521r1')
3148
const decoder = new Koblitz('secp521r1')
3249

50+
test('koblitz: encode throws error for unsupported alphabet size', () => {
51+
const encoder = new Koblitz()
52+
const message = 'Test message'
53+
54+
expect(() => {
55+
encoder.encode(message, 250n)
56+
}).toThrow('Alphabet size not supported')
57+
})
58+
59+
test('koblitz: decode throws error for unsupported alphabet size', () => {
60+
const decoder = new Koblitz()
61+
const point = { x: 1n, y: 1n }
62+
const j = 0n
63+
64+
expect(() => {
65+
decoder.decode(point, j, 250n)
66+
}).toThrow('Alphabet size not supported')
67+
})
68+
3369
test('koblitz: encode and decode ascii', () => {
3470
const message = 'Hello, EC!'
3571
const encode = encoder.encode(message, 2n ** 8n)

src/core.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export class EllipticCurveOperations {
8080
* @returns {Point} The resulting point.
8181
*/
8282
multiply_point(k, P) {
83-
if (typeof k !== 'bigint' || k <= 0n || k >= this.n) {
83+
if (typeof k !== 'bigint' || k < 1n || k >= this.n) {
8484
throw new Error('k is not in the range 0 < k < n')
8585
}
8686

src/protocols.test.js

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { test, expect } from '@jest/globals'
22
import { DiffieHellman, MasseyOmura } from './protocols'
3+
import { Koblitz } from './algorithms'
4+
import { Point } from './core'
35

46
test('diffie-hellman: compute shared secret', () => {
57
const private_key_alice = 12345n
@@ -18,31 +20,66 @@ test('diffie-hellman: compute shared secret', () => {
1820
})
1921

2022
test('massey-omura: encryption decryption', () => {
21-
const private_key_sender = 123456n
22-
const mo_sender = new MasseyOmura(private_key_sender)
23+
// Initialize the Koblitz instance for the elliptic curve 'secp192k1'
24+
const koblitz = new Koblitz('secp192k1')
2325

24-
const private_key_receiver = 654321n
25-
const mo_receiver = new MasseyOmura(private_key_receiver)
26+
// Sender's side
27+
// -------------
28+
const privateKeySender = BigInt('70604135')
29+
// Initialize Massey-Omura protocol with the sender's private key
30+
const moSender = new MasseyOmura(privateKeySender)
2631

27-
const message = mo_sender.curve.G // Using the curve's generator point for simplicity
32+
// Encode the message using the Koblitz method
33+
// `j` is used to handle the ambiguity in the decoding process
34+
const [message, j] = koblitz.encode('Hello, world!')
2835

29-
// Sender encrypts the message
30-
const encrypted_by_sender = mo_sender.first_encryption_step(message)
36+
// Perform the first encryption step with Massey-Omura protocol
37+
const encryptedMsgSender = moSender.first_encryption_step(message)
3138

32-
// Receiver encrypts the already encrypted message
33-
const encrypted_by_receiver =
34-
mo_receiver.second_encryption_step(encrypted_by_sender)
39+
// The encoded message is now sent to the receiver...
40+
// (transmission of encryptedMsgSender)
3541

36-
// Sender decrypts the message partly
37-
const partially_decrypted_by_sender = mo_sender.partial_decryption_step(
38-
encrypted_by_receiver,
39-
)
42+
// Receiver's side
43+
// ---------------
44+
const privateKeyReceiver = BigInt('48239108668')
45+
// Initialize Massey-Omura protocol with the receiver's private key
46+
const moReceiver = new MasseyOmura(privateKeyReceiver)
4047

41-
// Receiver completes decryption
42-
const fully_decrypted_message = mo_receiver.partial_decryption_step(
43-
partially_decrypted_by_sender,
44-
)
48+
// Perform the second encryption step with Massey-Omura protocol
49+
const encryptedMsgReceiver =
50+
moReceiver.second_encryption_step(encryptedMsgSender)
51+
52+
// The double-encrypted message is sent back to the sender...
53+
// (transmission of encryptedMsgReceiver)
54+
55+
// Sender's side again
56+
// -------------------
57+
const partialDecryptedMsg =
58+
moSender.partial_decryption_step(encryptedMsgReceiver)
59+
60+
// The partially decrypted message is sent back to the receiver...
61+
// (transmission of partialDecryptedMsg)
62+
63+
// Receiver's final decryption
64+
// ---------------------------
65+
const originalMessage =
66+
moReceiver.partial_decryption_step(partialDecryptedMsg)
67+
68+
// Decode the message using the Koblitz method
69+
// `j` is used to resolve the mapping from the elliptic curve point back to the message
70+
const decodedMessage = koblitz.decode(originalMessage, j)
4571

4672
// The fully decrypted message should match the original message
47-
expect(fully_decrypted_message).toStrictEqual(message)
73+
expect(decodedMessage).toStrictEqual('Hello, world!')
74+
})
75+
76+
test('massey-omura: validate the public key value', () => {
77+
const moSender = new MasseyOmura(654564n)
78+
79+
const P1 = new Point(
80+
2561645154652864168258282342383115659685709191094067233983n,
81+
89709827696035605786509950363037856155865475850237621433n,
82+
)
83+
84+
expect(moSender.public_key.toString()).toStrictEqual(P1.toString())
4885
})

0 commit comments

Comments
 (0)