-
Notifications
You must be signed in to change notification settings - Fork 274
Expand file tree
/
Copy pathleopard8_test.go
More file actions
128 lines (110 loc) · 3.79 KB
/
Copy pathleopard8_test.go
File metadata and controls
128 lines (110 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package reedsolomon
import (
"bytes"
"testing"
"github.com/klauspost/cpuid/v2"
)
func TestAddMod8(t *testing.T) {
type testCase struct {
x ffe8
y ffe8
expected ffe8
}
testCases := []testCase{
{x: ffe8(1), y: ffe8(2), expected: ffe8(3)},
{x: ffe8(253), y: ffe8(1), expected: ffe8(254)},
{x: ffe8(254), y: ffe8(2), expected: ffe8(1)},
{x: ffe8(255), y: ffe8(1), expected: ffe8(1)},
// it is expected that the following tests cases return modulus and that
// callers of addMod will convert it to 0.
{x: ffe8(254), y: ffe8(1), expected: ffe8(255)},
{x: ffe8(255), y: ffe8(0), expected: ffe8(255)},
{x: ffe8(255), y: ffe8(255), expected: ffe8(255)},
}
for _, tc := range testCases {
got := addMod8(tc.x, tc.y)
if tc.expected != got {
t.Errorf("expected %v, got %v", tc.expected, got)
}
}
}
func TestGFNIMultiplication(t *testing.T) {
if !cpuid.CPU.Supports(cpuid.GFNI, cpuid.AVX512VL) {
t.Skip("GFNI not supported")
}
// Create a simple encoder to ensure tables are initialized
enc, err := New(4, 2, WithLeopardGF(true))
if err != nil {
t.Fatal(err)
}
_ = enc
// Test simple multiplication: multiply a single byte using both methods
testValue := byte(0x42)
multiplier := ffe8(5) // Use a non-trivial multiplier
// Create test data - single byte repeated 64 times for SIMD alignment
testData := make([]byte, 64)
for i := range testData {
testData[i] = testValue
}
// Test with AVX2 lookup table method
avx2Result := make([]byte, 64)
copy(avx2Result, testData)
avx2Table := &multiply256LUT8[multiplier]
// We need a simple way to call the multiplication - let's use the direct table lookup
for i := range avx2Result {
lo := avx2Result[i] & 0x0f
hi := (avx2Result[i] >> 4) & 0x0f
// First 16 bytes are for low nibble, second 16 bytes for high nibble
avx2Result[i] = (*avx2Table)[lo] ^ (*avx2Table)[16+hi]
}
// Test with GFNI matrix method
gfniResult := make([]byte, 64)
copy(gfniResult, testData)
gfniMatrix := gf2p811dMulMatricesLeo8[multiplier]
// Manually compute what VGF2P8AFFINEQB should produce
for i := range gfniResult {
input := gfniResult[i]
result := byte(0)
// Apply 8x8 matrix transformation according to VGF2P8AFFINEQB spec
// The matrix is stored with byte 0 controlling bit 7, byte 1 controlling bit 6, etc.
matrix := gfniMatrix
for resultBit := range 8 {
// Get the matrix row for this result bit (note: bit 7-i indexing)
row := byte((matrix >> (8 * (7 - resultBit))) & 0xff)
// Compute dot product of input with this row
dotProduct := byte(0)
for inputBit := range 8 {
if (input>>inputBit)&1 == 1 && (row>>inputBit)&1 == 1 {
dotProduct ^= 1
}
}
result |= dotProduct << resultBit
}
gfniResult[i] = result
}
// Verify which result is correct using the reference implementation
correctResult := mulLog8(ffe8(testValue), multiplier)
// Compare results
if !bytes.Equal(avx2Result, gfniResult) {
t.Errorf("GFNI multiplication doesn't match AVX2")
t.Logf("Input: %02x, Multiplier: %d", testValue, multiplier)
t.Logf("AVX2 result: %02x", avx2Result[0])
t.Logf("GFNI result: %02x", gfniResult[0])
t.Logf("Correct result: %02x", correctResult)
if avx2Result[0] == byte(correctResult) {
t.Logf("AVX2 is correct, GFNI is wrong")
} else if gfniResult[0] == byte(correctResult) {
t.Logf("GFNI is correct, AVX2 is wrong")
} else {
t.Logf("Both are wrong!")
}
// Show first few bytes for debugging
for i := range 8 {
t.Logf("Byte %d: AVX2=%02x GFNI=%02x", i, avx2Result[i], gfniResult[i])
}
// Debug the GFNI matrix
t.Logf("GFNI matrix for multiplier %d: %016x", multiplier, gfniMatrix)
}
// NOTE: This test demonstrates the issue - it should be used to verify the fix
t.Logf("This test shows GFNI vs AVX2 differences - used for debugging VGF2P8AFFINEQB immediate values")
}