Files
nebula/handshake/fec/gf.go
T

116 lines
2.4 KiB
Go

package fec
// Arithmetic over GF(2^8) with the reducing polynomial x^8+x^4+x^3+x^2+1 (0x11d).
// Addition is XOR. Multiplication uses log/exp tables; the exp table is doubled so
// the sum of two logs never needs reducing mod 255.
const gfPoly = 0x11d
var (
gfExp [510]byte
gfLog [256]byte
)
func init() {
x := 1
for i := range 255 {
gfExp[i] = byte(x)
gfExp[i+255] = byte(x)
gfLog[x] = byte(i)
x <<= 1
if x&0x100 != 0 {
x ^= gfPoly
}
}
}
func gfMul(a, b byte) byte {
if a == 0 || b == 0 {
return 0
}
return gfExp[int(gfLog[a])+int(gfLog[b])]
}
// gfInv returns the multiplicative inverse of a. a must be non-zero.
func gfInv(a byte) byte {
return gfExp[255-int(gfLog[a])]
}
// mulAdd computes dst ^= c*src element-wise. dst must be at least as long as src.
func mulAdd(dst, src []byte, c byte) {
switch c {
case 0:
return
case 1:
for i, s := range src {
dst[i] ^= s
}
return
}
var t [256]byte
lc := int(gfLog[c])
for s := 1; s < 256; s++ {
t[s] = gfExp[int(gfLog[s])+lc]
}
for i, s := range src {
dst[i] ^= t[s]
}
}
// coefficient returns the generator matrix entry for repair symbol index row and
// data symbol index col. Repair rows are a Cauchy matrix 1/(x_row + y_col) with
// x_row = row and y_col = col: rows are always >= k and columns < k so the two
// sets are disjoint, which makes every square submatrix invertible and the
// systematic code [I; C] MDS. A row depends only on its index, never on how many
// repair symbols exist, so new repair symbols can be generated at any time.
func coefficient(row, col int) byte {
return gfInv(byte(row) ^ byte(col))
}
// invert inverts the n x n matrix m in place with Gauss-Jordan elimination.
// It returns false if m is singular.
func invert(m [][]byte) bool {
n := len(m)
inv := make([][]byte, n)
for i := range inv {
inv[i] = make([]byte, n)
inv[i][i] = 1
}
for col := range n {
pivot := -1
for r := col; r < n; r++ {
if m[r][col] != 0 {
pivot = r
break
}
}
if pivot < 0 {
return false
}
m[col], m[pivot] = m[pivot], m[col]
inv[col], inv[pivot] = inv[pivot], inv[col]
scale := gfInv(m[col][col])
for c := range n {
m[col][c] = gfMul(m[col][c], scale)
inv[col][c] = gfMul(inv[col][c], scale)
}
for r := 0; r < n; r++ {
if r == col || m[r][col] == 0 {
continue
}
f := m[r][col]
for c := range n {
m[r][c] ^= gfMul(f, m[col][c])
inv[r][c] ^= gfMul(f, inv[col][c])
}
}
}
copy(m, inv)
return true
}