gpv_test.go raw
1 package ring
2
3 import (
4 "testing"
5 )
6
7 // TestGPVSignVerify verifies basic sign/verify round-trip.
8 func TestGPVSignVerify(t *testing.T) {
9 gp := SmallGPVParams()
10 pk, sk := GPVKeyGen(gp)
11
12 msg := []byte("hello lattice world")
13 sig := GPVSign(sk, msg)
14
15 if !GPVVerify(pk, msg, sig) {
16 t.Fatal("valid signature rejected")
17 }
18 }
19
20 // TestGPVWrongMessage verifies signature doesn't verify for wrong message.
21 func TestGPVWrongMessage(t *testing.T) {
22 gp := SmallGPVParams()
23 pk, sk := GPVKeyGen(gp)
24
25 msg := []byte("correct message")
26 sig := GPVSign(sk, msg)
27
28 if GPVVerify(pk, []byte("wrong message"), sig) {
29 t.Fatal("signature verified for wrong message")
30 }
31 }
32
33 // TestGPVWrongKey verifies signature doesn't verify with wrong key.
34 func TestGPVWrongKey(t *testing.T) {
35 gp := SmallGPVParams()
36 _, sk1 := GPVKeyGen(gp)
37 pk2, _ := GPVKeyGen(gp)
38
39 msg := []byte("test message")
40 sig := GPVSign(sk1, msg)
41
42 if GPVVerify(pk2, msg, sig) {
43 t.Fatal("signature verified with wrong public key")
44 }
45 }
46
47 // TestGPVMultipleMessages verifies multiple sign/verify cycles.
48 func TestGPVMultipleMessages(t *testing.T) {
49 gp := SmallGPVParams()
50 pk, sk := GPVKeyGen(gp)
51
52 messages := []string{
53 "",
54 "a",
55 "hello",
56 "the quick brown fox jumps over the lazy dog",
57 "lattice-based cryptography is the future",
58 }
59
60 for _, msg := range messages {
61 sig := GPVSign(sk, []byte(msg))
62 if !GPVVerify(pk, []byte(msg), sig) {
63 t.Fatalf("verification failed for message %q", msg)
64 }
65 }
66 }
67
68 // TestGPVSignatureShortness verifies that signatures are actually short.
69 func TestGPVSignatureShortness(t *testing.T) {
70 gp := SmallGPVParams()
71 _, sk := GPVKeyGen(gp)
72
73 msg := []byte("test shortness")
74 sig := GPVSign(sk, msg)
75
76 zNorm := Norm(sig.E1)
77 cNorm := Norm(sig.E2)
78
79 t.Logf("||z||_∞ = %d, ||c||_∞ = %d, bound = %d",
80 zNorm, cNorm, uint32(gp.Sigma*1.5))
81
82 // z should be within the bound.
83 if zNorm > uint32(gp.Sigma*1.5) {
84 t.Errorf("z norm %d exceeds bound %d", zNorm, uint32(gp.Sigma*1.5))
85 }
86
87 // c should have small coefficients (±1 or 0).
88 if cNorm > 1 {
89 t.Errorf("c norm %d should be ≤ 1", cNorm)
90 }
91 }
92
93 // TestGPVDifferentSignatures verifies that signing the same message
94 // produces different signatures (due to randomness).
95 func TestGPVDifferentSignatures(t *testing.T) {
96 gp := SmallGPVParams()
97 pk, sk := GPVKeyGen(gp)
98
99 msg := []byte("determinism check")
100 sig1 := GPVSign(sk, msg)
101 sig2 := GPVSign(sk, msg)
102
103 // Both should verify.
104 if !GPVVerify(pk, msg, sig1) || !GPVVerify(pk, msg, sig2) {
105 t.Fatal("valid signatures rejected")
106 }
107
108 // But should be different (probabilistic signatures).
109 if Equal(sig1.E1, sig2.E1) && Equal(sig1.E2, sig2.E2) {
110 t.Fatal("two signatures are identical — randomness failure")
111 }
112 }
113
114 // TestGPVFalcon512Params verifies GPV works with Falcon-512 parameters.
115 func TestGPVFalcon512Params(t *testing.T) {
116 gp := DefaultGPVParams()
117 pk, sk := GPVKeyGen(gp)
118
119 msg := []byte("Falcon-512 parameter test")
120 sig := GPVSign(sk, msg)
121
122 if !GPVVerify(pk, msg, sig) {
123 t.Fatal("Falcon-512 signature rejected")
124 }
125
126 zNorm := Norm(sig.E1)
127 t.Logf("Falcon-512: ||z||_∞ = %d, σ = %.1f, bound = %d",
128 zNorm, gp.Sigma, uint32(gp.Sigma*1.5))
129 }
130
131 func BenchmarkGPVKeyGen(b *testing.B) {
132 gp := SmallGPVParams()
133 for range b.N {
134 GPVKeyGen(gp)
135 }
136 }
137
138 func BenchmarkGPVSign(b *testing.B) {
139 gp := SmallGPVParams()
140 _, sk := GPVKeyGen(gp)
141 msg := []byte("benchmark message")
142 b.ResetTimer()
143 for range b.N {
144 GPVSign(sk, msg)
145 }
146 }
147
148 func BenchmarkGPVVerify(b *testing.B) {
149 gp := SmallGPVParams()
150 pk, sk := GPVKeyGen(gp)
151 msg := []byte("benchmark message")
152 sig := GPVSign(sk, msg)
153 b.ResetTimer()
154 for range b.N {
155 GPVVerify(pk, msg, sig)
156 }
157 }
158