Skip to content

Commit 0341291

Browse files
committed
test(ciphers): add tests for Winternitz one-time signature
1 parent 9ad14d9 commit 0341291

1 file changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
8+
import java.nio.charset.StandardCharsets;
9+
import java.util.Arrays;
10+
import org.junit.jupiter.api.Test;
11+
import org.junit.jupiter.params.ParameterizedTest;
12+
import org.junit.jupiter.params.provider.CsvSource;
13+
import org.junit.jupiter.params.provider.ValueSource;
14+
15+
class WinternitzSignatureTest {
16+
17+
private static final byte[] MESSAGE = "hello winternitz".getBytes(StandardCharsets.UTF_8);
18+
19+
@Test
20+
void testValidSignatureVerifies() {
21+
WinternitzSignature keyPair = new WinternitzSignature();
22+
23+
byte[][] signature = keyPair.sign(MESSAGE);
24+
25+
assertTrue(WinternitzSignature.verify(MESSAGE, signature, keyPair.getPublicKey(), 16));
26+
}
27+
28+
@ParameterizedTest
29+
@ValueSource(ints = {4, 16, 256})
30+
void testSignAndVerifyForEverySupportedW(int w) {
31+
WinternitzSignature keyPair = new WinternitzSignature(w);
32+
33+
byte[][] signature = keyPair.sign(MESSAGE);
34+
35+
assertTrue(WinternitzSignature.verify(MESSAGE, signature, keyPair.getPublicKey(), w));
36+
}
37+
38+
@ParameterizedTest
39+
@CsvSource({"4, 128, 5", "16, 64, 3", "256, 32, 2"})
40+
void testParametersAreDerivedFromW(int w, int expectedLen1, int expectedLen2) {
41+
WinternitzSignature.Parameters parameters = WinternitzSignature.Parameters.forW(w);
42+
43+
assertEquals(expectedLen1, parameters.len1());
44+
assertEquals(expectedLen2, parameters.len2());
45+
assertEquals(expectedLen1 + expectedLen2, parameters.len());
46+
}
47+
48+
@Test
49+
void testDefaultSignatureHas67Values() {
50+
WinternitzSignature keyPair = new WinternitzSignature();
51+
52+
byte[][] signature = keyPair.sign(MESSAGE);
53+
54+
assertEquals(67, signature.length);
55+
assertEquals(67, keyPair.getPublicKey().length);
56+
for (byte[] value : signature) {
57+
assertEquals(32, value.length);
58+
}
59+
}
60+
61+
@Test
62+
void testTamperedMessageFailsVerification() {
63+
WinternitzSignature keyPair = new WinternitzSignature();
64+
byte[] message = MESSAGE.clone();
65+
byte[][] signature = keyPair.sign(message);
66+
67+
message[0] ^= 0x01;
68+
69+
assertFalse(WinternitzSignature.verify(message, signature, keyPair.getPublicKey(), 16));
70+
}
71+
72+
@Test
73+
void testTamperedSignatureFailsVerification() {
74+
WinternitzSignature keyPair = new WinternitzSignature();
75+
byte[][] signature = keyPair.sign(MESSAGE);
76+
77+
signature[10][0] ^= 0x01;
78+
79+
assertFalse(WinternitzSignature.verify(MESSAGE, signature, keyPair.getPublicKey(), 16));
80+
}
81+
82+
@Test
83+
void testDifferentPublicKeyDoesNotVerify() {
84+
WinternitzSignature keyPair1 = new WinternitzSignature();
85+
WinternitzSignature keyPair2 = new WinternitzSignature();
86+
87+
byte[][] signature = keyPair1.sign(MESSAGE);
88+
89+
assertFalse(WinternitzSignature.verify(MESSAGE, signature, keyPair2.getPublicKey(), 16));
90+
}
91+
92+
@Test
93+
void testVerifyingWithDifferentWThrowsException() {
94+
WinternitzSignature keyPair = new WinternitzSignature(16);
95+
byte[][] signature = keyPair.sign(MESSAGE);
96+
byte[][] publicKey = keyPair.getPublicKey();
97+
98+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, signature, publicKey, 4));
99+
}
100+
101+
@Test
102+
void testSecondSignatureThrowsException() {
103+
WinternitzSignature keyPair = new WinternitzSignature();
104+
byte[] second = "second message".getBytes(StandardCharsets.UTF_8);
105+
106+
keyPair.sign(MESSAGE);
107+
108+
assertThrows(IllegalStateException.class, () -> keyPair.sign(second));
109+
}
110+
111+
@Test
112+
void testNullAndMalformedInput() {
113+
WinternitzSignature keyPair = new WinternitzSignature();
114+
byte[][] publicKey = keyPair.getPublicKey();
115+
byte[][] signature = keyPair.sign(MESSAGE);
116+
byte[][] tooShort = Arrays.copyOf(signature, 66);
117+
byte[][] wrongValueLength = signature.clone();
118+
wrongValueLength[0] = new byte[31];
119+
byte[][] nullValue = signature.clone();
120+
nullValue[0] = null;
121+
122+
assertThrows(IllegalArgumentException.class, () -> new WinternitzSignature().sign(null));
123+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(null, signature, publicKey, 16));
124+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, null, publicKey, 16));
125+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, tooShort, publicKey, 16));
126+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, wrongValueLength, publicKey, 16));
127+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, nullValue, publicKey, 16));
128+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, signature, null, 16));
129+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, signature, tooShort, 16));
130+
}
131+
132+
@ParameterizedTest
133+
@ValueSource(ints = {0, 3, 15, -16, 2, 8, 512})
134+
void testUnsupportedWThrowsException(int w) {
135+
assertThrows(IllegalArgumentException.class, () -> new WinternitzSignature(w));
136+
assertThrows(IllegalArgumentException.class, () -> WinternitzSignature.verify(MESSAGE, new byte[67][32], new byte[67][32], w));
137+
}
138+
139+
@Test
140+
void testModifyingReturnedPublicKeyDoesNotChangeInternalState() {
141+
WinternitzSignature keyPair = new WinternitzSignature();
142+
byte[][] signature = keyPair.sign(MESSAGE);
143+
144+
byte[][] exposed = keyPair.getPublicKey();
145+
exposed[0][0] ^= 0x01;
146+
exposed[1] = new byte[32];
147+
148+
assertTrue(WinternitzSignature.verify(MESSAGE, signature, keyPair.getPublicKey(), 16));
149+
}
150+
151+
@Test
152+
void testEmptyAndLongMessages() {
153+
byte[] empty = new byte[0];
154+
byte[] longMessage = new byte[8192];
155+
for (int i = 0; i < longMessage.length; i++) {
156+
longMessage[i] = (byte) i;
157+
}
158+
WinternitzSignature keyPair1 = new WinternitzSignature();
159+
WinternitzSignature keyPair2 = new WinternitzSignature();
160+
161+
byte[][] emptySignature = keyPair1.sign(empty);
162+
byte[][] longSignature = keyPair2.sign(longMessage);
163+
164+
assertTrue(WinternitzSignature.verify(empty, emptySignature, keyPair1.getPublicKey(), 16));
165+
assertTrue(WinternitzSignature.verify(longMessage, longSignature, keyPair2.getPublicKey(), 16));
166+
}
167+
168+
@Test
169+
void testDifferentMessagesProduceDifferentSignatures() {
170+
WinternitzSignature keyPair1 = new WinternitzSignature();
171+
WinternitzSignature keyPair2 = new WinternitzSignature();
172+
173+
byte[][] signature1 = keyPair1.sign("first message".getBytes(StandardCharsets.UTF_8));
174+
byte[][] signature2 = keyPair2.sign("second message".getBytes(StandardCharsets.UTF_8));
175+
176+
assertFalse(Arrays.deepEquals(signature1, signature2));
177+
}
178+
}

0 commit comments

Comments
 (0)