Skip to content

Commit bcf4e3c

Browse files
authored
1 parent 1666657 commit bcf4e3c

File tree

14 files changed

+51370
-58
lines changed

14 files changed

+51370
-58
lines changed

field/field_test.go

Lines changed: 256 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@ package field
22

33
import (
44
"encoding/binary"
5+
"math"
56
"testing"
67

78
g "github.com/elliottech/poseidon_crypto/field/goldilocks"
89
gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension"
910

10-
"math/rand"
11+
"math/big"
12+
"math/rand/v2"
1113
)
1214

1315
func TestBytes(t *testing.T) {
1416
e1 := g.Sample()
1517

1618
leBytes := g.ToLittleEndianBytes(e1)
17-
beBytess := e1.Bytes()
18-
beBytes := beBytess[:]
19+
beBytes := e1.Bytes()
1920
for i := 0; i < g.Bytes; i++ {
2021
if beBytes[i] != leBytes[g.Bytes-i-1] {
2122
t.Fatalf("Big endian and little endian bytes are not reversed")
@@ -27,19 +28,208 @@ func TestBytes(t *testing.T) {
2728
t.Fatalf("bytes do not match")
2829
}
2930

30-
randUint64 := rand.Uint64()
31-
elem := g.FromUint64(randUint64)
31+
r := rand.Uint64N(g.ORDER)
3232

3333
leBytesUint64 := make([]byte, 8)
34-
binary.LittleEndian.PutUint64(leBytesUint64, randUint64)
35-
leBytesElem := g.ToLittleEndianBytes(elem)
34+
binary.LittleEndian.PutUint64(leBytesUint64, r)
35+
36+
leBytesElem := g.ToLittleEndianBytes(g.FromUint64(r))
3637
for i := 0; i < 8; i++ {
3738
if leBytesUint64[i] != leBytesElem[i] {
3839
t.Fatalf("Little-endian bytes do not match at index %d: expected %x, got %x", i, leBytesUint64[i], leBytesElem[i])
3940
}
4041
}
4142
}
4243

44+
func TestBytesF(t *testing.T) {
45+
r := rand.Uint64N(g.ORDER)
46+
f := g.GoldilocksField(r)
47+
48+
rBytes := make([]byte, 8)
49+
binary.LittleEndian.PutUint64(rBytes, r)
50+
51+
fBytes := g.ToLittleEndianBytesF(f)
52+
for i := 0; i < 8; i++ {
53+
if rBytes[i] != fBytes[i] {
54+
t.Fatalf("Little-endian bytes do not match at index %d: expected %x, got %x", i, rBytes[i], fBytes[i])
55+
}
56+
}
57+
58+
ff := g.FromCanonicalLittleEndianBytesF(fBytes)
59+
if ff != f {
60+
t.Fatalf("bytes do not match")
61+
}
62+
}
63+
64+
// Goldilocks field tests
65+
66+
// Inputs that covers several input ranges
67+
var inputs = []uint64{
68+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 2147483638, 2147483639, 2147483640, 2147483641, 2147483642, 2147483643, 2147483644, 2147483645, 2147483646, 2147483647, 2147483648, 2147483649,
69+
2147483650, 2147483651, 2147483652, 2147483653, 2147483654, 2147483655, 2147483656, 2147483657, 4294967286, 4294967287, 4294967288, 4294967289, 4294967290, 4294967291,
70+
4294967292, 4294967293, 4294967294, 4294967295, 4294967296, 4294967297, 4294967298, 4294967299, 4294967300, 4294967301, 4294967302, 4294967303, 4294967304, 4294967305,
71+
9223372036854775798, 9223372036854775799, 9223372036854775800, 9223372036854775801, 9223372036854775802, 9223372036854775803, 9223372036854775804, 9223372036854775805,
72+
9223372036854775806, 9223372036854775807, 9223372036854775808, 9223372036854775809, 9223372036854775810, 9223372036854775811, 9223372036854775812, 9223372036854775813,
73+
9223372036854775814, 9223372036854775815, 9223372036854775816, 9223372036854775817, 18446744069414584311, 18446744069414584312, 18446744069414584313, 18446744069414584314,
74+
18446744069414584315, 18446744069414584316, 18446744069414584317, 18446744069414584318, 18446744069414584319, 18446744069414584320,
75+
}
76+
77+
func NewBigInt(x uint64) *big.Int {
78+
return big.NewInt(0).SetUint64(x)
79+
}
80+
81+
func SumMod(x, y uint64) uint64 {
82+
sum := NewBigInt(x).Add(NewBigInt(x), NewBigInt(y))
83+
res := sum.Mod(sum, NewBigInt(g.ORDER))
84+
if !res.IsUint64() {
85+
panic("sum is not uint64")
86+
}
87+
return res.Uint64()
88+
}
89+
90+
func SubMod(x, y uint64) uint64 {
91+
sub := NewBigInt(x).Sub(NewBigInt(x), NewBigInt(y))
92+
res := sub.Mod(sub, NewBigInt(g.ORDER))
93+
if !res.IsUint64() {
94+
panic("difference is not uint64")
95+
}
96+
return res.Uint64()
97+
}
98+
99+
func MulMod(x, y uint64) uint64 {
100+
mul := NewBigInt(x).Mul(NewBigInt(x), NewBigInt(y))
101+
res := mul.Mod(mul, NewBigInt(g.ORDER))
102+
if !res.IsUint64() {
103+
panic("product is not uint64")
104+
}
105+
return res.Uint64()
106+
}
107+
108+
func NegMod(x uint64) uint64 {
109+
neg := NewBigInt(x).Neg(NewBigInt(x))
110+
res := neg.Mod(neg, NewBigInt(g.ORDER))
111+
if !res.IsUint64() {
112+
panic("negative number is not uint64")
113+
}
114+
return res.Uint64()
115+
}
116+
117+
func SquareMod(x uint64) uint64 {
118+
square := NewBigInt(x).Mul(NewBigInt(x), NewBigInt(x))
119+
res := square.Mod(square, NewBigInt(g.ORDER))
120+
if !res.IsUint64() {
121+
panic("square is not uint64")
122+
}
123+
return res.Uint64()
124+
}
125+
126+
func TestAddF(t *testing.T) {
127+
for _, lhs := range inputs {
128+
for _, rhs := range inputs {
129+
fLhs := g.GoldilocksField(lhs)
130+
fRhs := g.GoldilocksField(rhs)
131+
sum := g.AddF(fLhs, fRhs).ToCanonicalUint64()
132+
expected := SumMod(lhs, rhs)
133+
if sum != expected {
134+
t.Fatalf("Expected %d + %d = %d, but got %d", lhs, rhs, expected, sum)
135+
}
136+
}
137+
}
138+
}
139+
140+
func TestSubF(t *testing.T) {
141+
for _, lhs := range inputs {
142+
for _, rhs := range inputs {
143+
fLhs := g.GoldilocksField(lhs)
144+
fRhs := g.GoldilocksField(rhs)
145+
diff := g.SubF(fLhs, fRhs).ToCanonicalUint64()
146+
expected := SubMod(lhs, rhs)
147+
if diff != expected {
148+
t.Fatalf("Expected %d - %d = %d, but got %d", lhs, rhs, expected, diff)
149+
}
150+
}
151+
}
152+
}
153+
154+
func TestMulF(t *testing.T) {
155+
for _, lhs := range inputs {
156+
for _, rhs := range inputs {
157+
fLhs := g.GoldilocksField(lhs)
158+
fRhs := g.GoldilocksField(rhs)
159+
mul := g.MulF(fLhs, fRhs).ToCanonicalUint64()
160+
expected := MulMod(lhs, rhs)
161+
if mul != expected {
162+
t.Fatalf("Expected %d * %d = %d, but got %d", lhs, rhs, expected, mul)
163+
}
164+
}
165+
}
166+
}
167+
168+
func TestNegF(t *testing.T) {
169+
for _, lhs := range inputs {
170+
fLhs := g.GoldilocksField(lhs)
171+
neg := g.NegF(fLhs).ToCanonicalUint64()
172+
expected := NegMod(lhs)
173+
if neg != expected {
174+
t.Fatalf("Expected Neg(%d) = %d, but got %d", lhs, expected, neg)
175+
}
176+
}
177+
}
178+
179+
func TestSquareF(t *testing.T) {
180+
for _, lhs := range inputs {
181+
fLhs := g.GoldilocksField(lhs)
182+
sqr := g.SquareF(fLhs).ToCanonicalUint64()
183+
expected := SquareMod(lhs)
184+
if sqr != expected {
185+
t.Fatalf("Expected (%d)^2 = %d, but got %d", lhs, expected, sqr)
186+
}
187+
}
188+
}
189+
190+
func TestSubFDoubleWraparound(t *testing.T) {
191+
/*
192+
let (a, b) = (F::from_canonical_u64((F::ORDER + 1u64) / 2u64), F::TWO);
193+
let x = a * b;
194+
assert_eq!(x, F::ONE);
195+
assert_eq!(F::ZERO - x, F::NEG_ONE);
196+
*/
197+
198+
a := g.GoldilocksField((g.ORDER + 1) / 2)
199+
b := g.GoldilocksField(2)
200+
x := g.MulF(a, b)
201+
if x.ToCanonicalUint64() != g.OneF().ToCanonicalUint64() {
202+
t.Fatalf("Expected a*b to be 1, but got %v", x)
203+
}
204+
if g.SubF(g.ZeroF(), x).ToCanonicalUint64() != g.NegOneF().ToCanonicalUint64() {
205+
t.Fatalf("Expected 0 - x to be -1, but got %v", g.SubF(g.ZeroF(), x))
206+
}
207+
}
208+
209+
func TestAddFDoubleWraparound(t *testing.T) {
210+
/*
211+
let a = F::from_canonical_u64(u64::MAX - F::ORDER);
212+
let b = F::NEG_ONE;
213+
214+
let c = (a + a) + (b + b);
215+
let d = (a + b) + (a + b);
216+
217+
assert_eq!(c, d);
218+
*/
219+
220+
a := g.GoldilocksField(math.MaxUint64 - g.ORDER)
221+
b := g.NegOneF()
222+
223+
c := g.AddF(g.AddF(a, a), g.AddF(b, b))
224+
d := g.AddF(g.AddF(a, b), g.AddF(a, b))
225+
226+
if c.ToCanonicalUint64() != d.ToCanonicalUint64() {
227+
t.Fatalf("Expected c to be equal to d, but got %v and %v", c, d)
228+
}
229+
}
230+
231+
// Quintic extension tests
232+
43233
func TestQuinticExtensionAddSubMulSquare(t *testing.T) {
44234
val1 := gFp5.Element{
45235
g.FromUint64(0x1234567890ABCDEF),
@@ -59,23 +249,78 @@ func TestQuinticExtensionAddSubMulSquare(t *testing.T) {
59249
add := gFp5.Add(val1, val2)
60250
expectedAdd := [5]uint64{1311768471589866989, 1147797413325783839, 1234605620731475846, 9833440832084189711, 12302652064957136911}
61251
for i := 0; i < 5; i++ {
62-
if add[i] != g.FromUint64(expectedAdd[i]) {
252+
if add[i].Uint64() != expectedAdd[i] {
253+
t.Fatalf("Addition: Expected limb %d to be %x, but got %x", i, expectedAdd[i], add[i])
254+
}
255+
}
256+
257+
sub := gFp5.Sub(val1, val2)
258+
expectedSub := [5]uint64{1311768462999932401, 1147797404735849251, 1234605612141541258, 9833440823494255123, 12302652056367202323}
259+
for i := 0; i < 5; i++ {
260+
if sub[i].Uint64() != expectedSub[i] {
261+
t.Fatalf("Subtraction: Expected limb %d to be %x, but got %x", i, expectedSub[i], sub[i])
262+
}
263+
}
264+
265+
mul := gFp5.Mul(val1, val2)
266+
expectedMul := [5]uint64{12801331769143413385, 14031114708135177824, 4192851210753422088, 14031114723597060086, 4193451712464626164}
267+
for i := 0; i < 5; i++ {
268+
if mul[i].Uint64() != expectedMul[i] {
269+
t.Fatalf("Multiplication: Expected limb %d to be %x, but got %x", i, expectedMul[i], mul[i])
270+
}
271+
}
272+
273+
square := gFp5.Square(val1)
274+
expectedSquare := [5]uint64{
275+
2711468769317614959,
276+
15562737284369360677,
277+
48874032493986270,
278+
11211402278708723253,
279+
2864528669572451733,
280+
}
281+
for i := 0; i < 5; i++ {
282+
if square[i].Uint64() != expectedSquare[i] {
283+
t.Fatalf("Square: Expected limb %d to be %x, but got %x", i, expectedSquare[i], square[i])
284+
}
285+
}
286+
}
287+
288+
func TestQuinticExtensionAddSubMulSquareF(t *testing.T) {
289+
val1 := gFp5.FromPlonky2GoldilocksField([]g.GoldilocksField{
290+
g.GoldilocksField(0x1234567890ABCDEF),
291+
g.GoldilocksField(0x0FEDCBA987654321),
292+
g.GoldilocksField(0x1122334455667788),
293+
g.GoldilocksField(0x8877665544332211),
294+
g.GoldilocksField(0xAABBCCDDEEFF0011),
295+
})
296+
val2 := gFp5.FromPlonky2GoldilocksField([]g.GoldilocksField{
297+
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
298+
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
299+
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
300+
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
301+
g.GoldilocksField(0xFFFFFFFFFFFFFFFF),
302+
})
303+
304+
add := gFp5.Add(val1, val2)
305+
expectedAdd := [5]uint64{1311768471589866989, 1147797413325783839, 1234605620731475846, 9833440832084189711, 12302652064957136911}
306+
for i := 0; i < 5; i++ {
307+
if add[i].Uint64() != expectedAdd[i] {
63308
t.Fatalf("Addition: Expected limb %d to be %x, but got %x", i, expectedAdd[i], add[i])
64309
}
65310
}
66311

67312
sub := gFp5.Sub(val1, val2)
68313
expectedSub := [5]uint64{1311768462999932401, 1147797404735849251, 1234605612141541258, 9833440823494255123, 12302652056367202323}
69314
for i := 0; i < 5; i++ {
70-
if sub[i] != g.FromUint64(expectedSub[i]) {
315+
if sub[i].Uint64() != expectedSub[i] {
71316
t.Fatalf("Subtraction: Expected limb %d to be %x, but got %x", i, expectedSub[i], sub[i])
72317
}
73318
}
74319

75320
mul := gFp5.Mul(val1, val2)
76321
expectedMul := [5]uint64{12801331769143413385, 14031114708135177824, 4192851210753422088, 14031114723597060086, 4193451712464626164}
77322
for i := 0; i < 5; i++ {
78-
if mul[i] != g.FromUint64(expectedMul[i]) {
323+
if mul[i].Uint64() != expectedMul[i] {
79324
t.Fatalf("Multiplication: Expected limb %d to be %x, but got %x", i, expectedMul[i], mul[i])
80325
}
81326
}
@@ -89,7 +334,7 @@ func TestQuinticExtensionAddSubMulSquare(t *testing.T) {
89334
2864528669572451733,
90335
}
91336
for i := 0; i < 5; i++ {
92-
if square[i] != g.FromUint64(expectedSquare[i]) {
337+
if square[i].Uint64() != expectedSquare[i] {
93338
t.Fatalf("Square: Expected limb %d to be %x, but got %x", i, expectedSquare[i], square[i])
94339
}
95340
}

field/goldilocks/branch_hint.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package goldilocks
2+
3+
//go:noescape
4+
func branchHint()

field/goldilocks/branch_hint.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
TEXT ·branchHint(SB),$0
2+
NOP
3+
RET
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ func reverseBytes(b []byte) []byte {
2525
}
2626

2727
func ArrayFromCanonicalLittleEndianBytes(in []byte) ([]Element, error) {
28-
2928
missing := 8 - len(in)%8
3029
if missing == 8 {
3130
missing = 0

0 commit comments

Comments
 (0)