mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-19 03:25:16 +00:00
157 lines
2.7 KiB
Go
157 lines
2.7 KiB
Go
|
package reedsolomon
|
||
|
|
||
|
import "errors"
|
||
|
|
||
|
type matrix []byte
|
||
|
|
||
|
func genEncMatrixCauchy(d, p int) matrix {
|
||
|
t := d + p
|
||
|
m := make([]byte, t*d)
|
||
|
for i := 0; i < d; i++ {
|
||
|
m[i*d+i] = byte(1)
|
||
|
}
|
||
|
|
||
|
d2 := d * d
|
||
|
for i := d; i < t; i++ {
|
||
|
for j := 0; j < d; j++ {
|
||
|
d := i ^ j
|
||
|
a := inverseTbl[d]
|
||
|
m[d2] = byte(a)
|
||
|
d2++
|
||
|
}
|
||
|
}
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
func gfExp(b byte, n int) byte {
|
||
|
if n == 0 {
|
||
|
return 1
|
||
|
}
|
||
|
if b == 0 {
|
||
|
return 0
|
||
|
}
|
||
|
a := logTbl[b]
|
||
|
ret := int(a) * n
|
||
|
for ret >= 255 {
|
||
|
ret -= 255
|
||
|
}
|
||
|
return byte(expTbl[ret])
|
||
|
}
|
||
|
|
||
|
func genVandMatrix(vm []byte, t, d int) {
|
||
|
for i := 0; i < t; i++ {
|
||
|
for j := 0; j < d; j++ {
|
||
|
vm[i*d+j] = gfExp(byte(i), j)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (m matrix) mul(right matrix, rows, cols int, r []byte) {
|
||
|
for i := 0; i < rows; i++ {
|
||
|
for j := 0; j < cols; j++ {
|
||
|
var v byte
|
||
|
for k := 0; k < cols; k++ {
|
||
|
v ^= gfMul(m[i*cols+k], right[k*cols+j])
|
||
|
}
|
||
|
r[i*cols+j] = v
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func genEncMatrixVand(d, p int) (matrix, error) {
|
||
|
t := d + p
|
||
|
buf := make([]byte, (2*t+4*d)*d)
|
||
|
vm := buf[:t*d]
|
||
|
genVandMatrix(vm, t, d)
|
||
|
top := buf[t*d : (t+d)*d]
|
||
|
copy(top, vm[:d*d])
|
||
|
raw := buf[(t+d)*d : (t+3*d)*d]
|
||
|
im := buf[(t+3*d)*d : (t+4*d)*d]
|
||
|
err := matrix(top).invert(raw, d, im)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
r := buf[(t+4*d)*d : (2*t+4*d)*d]
|
||
|
matrix(vm).mul(im, t, d, r)
|
||
|
return matrix(r), nil
|
||
|
}
|
||
|
|
||
|
// [I|m'] -> [m']
|
||
|
func (m matrix) subMatrix(n int, r []byte) {
|
||
|
for i := 0; i < n; i++ {
|
||
|
off := i * n
|
||
|
copy(r[off:off+n], m[2*off+n:2*(off+n)])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (m matrix) invert(raw matrix, n int, im []byte) error {
|
||
|
// [m] -> [m|I]
|
||
|
for i := 0; i < n; i++ {
|
||
|
t := i * n
|
||
|
copy(raw[2*t:2*t+n], m[t:t+n])
|
||
|
raw[2*t+i+n] = byte(1)
|
||
|
}
|
||
|
err := gauss(raw, n)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
raw.subMatrix(n, im)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m matrix) swap(i, j, n int) {
|
||
|
for k := 0; k < n; k++ {
|
||
|
m[i*n+k], m[j*n+k] = m[j*n+k], m[i*n+k]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func gfMul(a, b byte) byte {
|
||
|
return mulTbl[a][b]
|
||
|
}
|
||
|
|
||
|
var errSingular = errors.New("rs.invert: matrix is singular")
|
||
|
|
||
|
// [m|I] -> [I|m']
|
||
|
func gauss(m matrix, n int) error {
|
||
|
n2 := 2 * n
|
||
|
for i := 0; i < n; i++ {
|
||
|
if m[i*n2+i] == 0 {
|
||
|
for j := i + 1; j < n; j++ {
|
||
|
if m[j*n2+i] != 0 {
|
||
|
m.swap(i, j, n2)
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if m[i*n2+i] == 0 {
|
||
|
return errSingular
|
||
|
}
|
||
|
if m[i*n2+i] != 1 {
|
||
|
d := m[i*n2+i]
|
||
|
scale := inverseTbl[d]
|
||
|
for c := 0; c < n2; c++ {
|
||
|
m[i*n2+c] = gfMul(m[i*n2+c], scale)
|
||
|
}
|
||
|
}
|
||
|
for j := i + 1; j < n; j++ {
|
||
|
if m[j*n2+i] != 0 {
|
||
|
scale := m[j*n2+i]
|
||
|
for c := 0; c < n2; c++ {
|
||
|
m[j*n2+c] ^= gfMul(scale, m[i*n2+c])
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for k := 0; k < n; k++ {
|
||
|
for j := 0; j < k; j++ {
|
||
|
if m[j*n2+k] != 0 {
|
||
|
scale := m[j*n2+k]
|
||
|
for c := 0; c < n2; c++ {
|
||
|
m[j*n2+c] ^= gfMul(scale, m[k*n2+c])
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|