Skip to content

Commit 01fcf31

Browse files
committed
Add sig fuzz tests
1 parent 3729ab6 commit 01fcf31

File tree

4 files changed

+185
-2
lines changed

4 files changed

+185
-2
lines changed

.github/workflows/test.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ jobs:
3333
- name: Run fuzzy field tests
3434
run: |
3535
go test -tags=fuzz -fuzz=Fuzz -fuzztime=30s github.com/elliottech/poseidon_crypto/field
36+
- name: Run fuzzy signature tests
37+
run: |
38+
go test -tags=fuzz -fuzz=Fuzz -fuzztime=30s github.com/elliottech/poseidon_crypto/signature/schnorr
39+
- name: Run fuzzy int tests
40+
run: |
41+
for test in $(go test -list='Fuzz.*' github.com/elliottech/poseidon_crypto/int | grep ^Fuzz); do
42+
go test -fuzz="^${test}$" -fuzztime=30s github.com/elliottech/poseidon_crypto/int
43+
done
3644
3745
lint:
3846
name: Lint

int/int_test.go

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package int
22

3-
import "testing"
3+
import (
4+
"math"
5+
"math/big"
6+
"testing"
7+
)
48

59
func TestRecodeSigned5_161(t *testing.T) {
610
scalar1 := Signed161{
@@ -18,3 +22,140 @@ func TestRecodeSigned5_161(t *testing.T) {
1822
}
1923
}
2024
}
25+
26+
func FuzzTestAdd(f *testing.F) {
27+
f.Add(uint64(0), uint64(0), uint64(0), uint64(0))
28+
f.Add(uint64(math.MaxUint64), uint64(1), uint64(1), uint64(0))
29+
f.Add(uint64(math.MaxUint64), uint64(0), uint64(1), uint64(0))
30+
f.Add(uint64(math.MaxUint64), uint64(math.MaxUint64), uint64(math.MaxUint64), uint64(math.MaxUint64))
31+
32+
f.Fuzz(func(t *testing.T, a, b, c, d uint64) {
33+
i128a := UInt128{Hi: a, Lo: b}
34+
i128b := UInt128{Hi: c, Lo: d}
35+
result := AddUInt128(i128a, i128b)
36+
37+
expected := new(big.Int).Add(new(big.Int).SetBits([]big.Word{big.Word(b), big.Word(a)}), new(big.Int).SetBits([]big.Word{big.Word(d), big.Word(c)}))
38+
expectedReduced := new(big.Int).And(expected, new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1)))
39+
40+
if !equalsBigInt(result, expectedReduced) {
41+
t.Errorf("Add(%d, %d): got %v, want %v",
42+
a, b, result.ToBigInt(), expected)
43+
}
44+
45+
i128ab := AddUint64(a, b)
46+
expected = new(big.Int).Add(new(big.Int).SetUint64(a), new(big.Int).SetUint64(b))
47+
if !equalsBigInt(i128ab, expected) {
48+
t.Errorf("AddUint64(%d, %d): got %v, want %v",
49+
a, b, i128ab.ToBigInt(), expected)
50+
}
51+
})
52+
}
53+
54+
func FuzzTestAddUInt64(f *testing.F) {
55+
f.Add(uint64(0), uint64(0), uint64(0))
56+
f.Add(uint64(math.MaxUint64), uint64(1), uint64(1))
57+
f.Add(uint64(math.MaxUint64), uint64(0), uint64(0))
58+
f.Add(uint64(math.MaxUint64), uint64(math.MaxUint64), uint64(math.MaxUint64))
59+
60+
f.Fuzz(func(t *testing.T, hi, lo uint64, b uint64) {
61+
i128 := UInt128{Hi: hi, Lo: lo}
62+
result := AddUint128AndUint64(i128, b)
63+
64+
big128 := i128.ToBigInt()
65+
expected := new(big.Int).Add(big128, new(big.Int).SetUint64(b))
66+
67+
if fitsInInt128(expected) {
68+
if !equalsBigInt(result, expected) {
69+
t.Errorf("AddInt64({%d, %d}, %d): got %v, want %v",
70+
hi, lo, b, result.ToBigInt(), expected)
71+
}
72+
} else {
73+
expectedReduced := new(big.Int).And(expected, new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1)))
74+
if !equalsBigInt(result, expectedReduced) {
75+
t.Errorf("AddInt64({%d, %d}, %d): got %v, want %v (reduced)",
76+
hi, lo, b, result.ToBigInt(), expectedReduced)
77+
}
78+
}
79+
})
80+
}
81+
82+
func FuzzTestMulUInt64(f *testing.F) {
83+
f.Add(uint64(0), uint64(0))
84+
f.Add(uint64(math.MaxUint64), uint64(1))
85+
f.Add(uint64(math.MaxUint64), uint64(0))
86+
f.Add(uint64(math.MaxUint64), uint64(math.MaxUint64))
87+
88+
f.Fuzz(func(t *testing.T, a, b uint64) {
89+
result := MulUInt64(a, b)
90+
expected := new(big.Int).Mul(new(big.Int).SetUint64(a), new(big.Int).SetUint64(b))
91+
92+
if fitsInInt128(expected) {
93+
if !equalsBigInt(result, expected) {
94+
t.Errorf("MulInt64(%d, %d): got %v, want %v",
95+
a, b, result.ToBigInt(), expected)
96+
}
97+
}
98+
})
99+
}
100+
101+
func FuzzTestMulUint128AndUint64(f *testing.F) {
102+
f.Add(uint64(0), uint64(0), uint64(0))
103+
f.Add(uint64(math.MaxUint64), uint64(1), uint64(1))
104+
f.Add(uint64(math.MaxUint64), uint64(0), uint64(0))
105+
f.Add(uint64(math.MaxUint64), uint64(math.MaxUint64), uint64(math.MaxUint64))
106+
107+
f.Fuzz(func(t *testing.T, hi, lo uint64, b uint64) {
108+
i128 := UInt128{Hi: hi, Lo: lo}
109+
result := MulUint128AndUint64(i128, b)
110+
111+
big128 := i128.ToBigInt()
112+
expected := new(big.Int).Mul(big128, new(big.Int).SetUint64(b))
113+
114+
if fitsInInt128(expected) {
115+
if !equalsBigInt(result, expected) {
116+
t.Errorf("MulUint128AndUint64({%d, %d}, %d): got %v, want %v",
117+
hi, lo, b, result.ToBigInt(), expected)
118+
}
119+
} else {
120+
expectedReduced := new(big.Int).And(expected, new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1)))
121+
if !equalsBigInt(result, expectedReduced) {
122+
t.Errorf("MulUint128AndUint64({%d, %d}, %d): got %v, want %v (reduced)",
123+
hi, lo, b, result.ToBigInt(), expectedReduced)
124+
}
125+
}
126+
})
127+
}
128+
129+
func FuzzTestSubUint128AndUint64(f *testing.F) {
130+
f.Add(uint64(0), uint64(0), uint64(0))
131+
f.Add(uint64(1), uint64(1), uint64(0))
132+
f.Add(uint64(0), uint64(1), uint64(0))
133+
f.Add(uint64(math.MaxUint64), uint64(math.MaxUint64), uint64(math.MaxUint64))
134+
135+
f.Fuzz(func(t *testing.T, hi, lo uint64, b uint64) {
136+
i128 := UInt128{Hi: hi, Lo: lo}
137+
result := SubUint128AndUint64(i128, b)
138+
139+
expected := new(big.Int).Sub(new(big.Int).SetBits([]big.Word{big.Word(lo), big.Word(hi)}), new(big.Int).SetUint64(b))
140+
if expected.Sign() < 0 {
141+
expected.Add(expected, new(big.Int).Lsh(big.NewInt(1), 128))
142+
}
143+
144+
if !equalsBigInt(result, expected) {
145+
t.Errorf("SubUint64({%d, %d}, %d): got %v, want %v",
146+
hi, lo, b, result.ToBigInt(), expected)
147+
}
148+
})
149+
}
150+
151+
func equalsBigInt(a UInt128, b *big.Int) bool {
152+
return a.ToBigInt().Cmp(b) == 0
153+
}
154+
155+
func fitsInInt128(b *big.Int) bool {
156+
max := new(big.Int).Lsh(big.NewInt(1), 127)
157+
max.Sub(max, big.NewInt(1)) // (2^127) - 1
158+
min := new(big.Int).Lsh(big.NewInt(-1), 127) // -(2^127)
159+
160+
return b.Cmp(min) >= 0 && b.Cmp(max) <= 0
161+
}

int/uint128.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
package int
22

3-
import "math/bits"
3+
import (
4+
"math/big"
5+
"math/bits"
6+
)
47

58
type UInt128 struct {
69
Hi, Lo uint64
710
}
811

12+
func (u UInt128) ToBigInt() *big.Int {
13+
bi := new(big.Int).SetUint64(u.Hi)
14+
bi.Lsh(bi, 64)
15+
bi.Add(bi, new(big.Int).SetUint64(u.Lo))
16+
return bi
17+
}
18+
919
func UInt128FromUint64(v uint64) UInt128 {
1020
return UInt128{Hi: 0, Lo: v}
1121
}

signature/schnorr/schnorr_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package signature
22

33
import (
4+
"encoding/binary"
5+
"math/big"
46
"testing"
57

68
curve "github.com/elliottech/poseidon_crypto/curve/ecgfp5"
@@ -24,6 +26,28 @@ func TestSchnorrSignAndVerify(t *testing.T) {
2426
}
2527
}
2628

29+
func FuzzTestSchnorrSignAndVerify(f *testing.F) {
30+
f.Add([]byte{1, 2, 3, 4}, []byte{5, 6, 7, 8})
31+
32+
f.Fuzz(func(t *testing.T, a, b []byte) {
33+
scalar := curve.FromNonCanonicalBigInt(new(big.Int).SetBytes(a))
34+
35+
msgBytes := make([]g.GoldilocksField, 0)
36+
for i := 0; i < len(b); i += 8 {
37+
var chunk [8]byte
38+
copy(chunk[:], b[i:min(i+8, len(b))])
39+
msgBytes = append(msgBytes, g.GoldilocksField(binary.LittleEndian.Uint64(chunk[:])))
40+
}
41+
hashedMsg := p2.HashToQuinticExtension(msgBytes)
42+
43+
sig := SchnorrSignHashedMessage(hashedMsg, scalar)
44+
pk := SchnorrPkFromSk(scalar)
45+
if !IsSchnorrSignatureValid(pk, hashedMsg, sig) {
46+
t.Fatalf("Signature is invalid")
47+
}
48+
})
49+
}
50+
2751
func TestComparativeSchnorrSignAndVerify(t *testing.T) {
2852
sks := []curve.ECgFp5Scalar{
2953
curve.ECgFp5Scalar{

0 commit comments

Comments
 (0)