mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-19 03:25:16 +00:00
a1bcc15458
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4080
242 lines
5.0 KiB
Go
242 lines
5.0 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE.bsd file.
|
||
|
||
// Package gf256 implements arithmetic over the Galois Field GF(256).
|
||
package gf256
|
||
|
||
import "strconv"
|
||
|
||
// A Field represents an instance of GF(256) defined by a specific polynomial.
|
||
type Field struct {
|
||
log [256]byte // log[0] is unused
|
||
exp [510]byte
|
||
}
|
||
|
||
// NewField returns a new field corresponding to the polynomial poly
|
||
// and generator α. The Reed-Solomon encoding in QR codes uses
|
||
// polynomial 0x11d with generator 2.
|
||
//
|
||
// The choice of generator α only affects the Exp and Log operations.
|
||
func NewField(poly, α int) *Field {
|
||
if poly < 0x100 || poly >= 0x200 || reducible(poly) {
|
||
panic("gf256: invalid polynomial: " + strconv.Itoa(poly))
|
||
}
|
||
|
||
var f Field
|
||
x := 1
|
||
for i := 0; i < 255; i++ {
|
||
if x == 1 && i != 0 {
|
||
panic("gf256: invalid generator " + strconv.Itoa(α) +
|
||
" for polynomial " + strconv.Itoa(poly))
|
||
}
|
||
f.exp[i] = byte(x)
|
||
f.exp[i+255] = byte(x)
|
||
f.log[x] = byte(i)
|
||
x = mul(x, α, poly)
|
||
}
|
||
f.log[0] = 255
|
||
for i := 0; i < 255; i++ {
|
||
if f.log[f.exp[i]] != byte(i) {
|
||
panic("bad log")
|
||
}
|
||
if f.log[f.exp[i+255]] != byte(i) {
|
||
panic("bad log")
|
||
}
|
||
}
|
||
for i := 1; i < 256; i++ {
|
||
if f.exp[f.log[i]] != byte(i) {
|
||
panic("bad log")
|
||
}
|
||
}
|
||
|
||
return &f
|
||
}
|
||
|
||
// nbit returns the number of significant in p.
|
||
func nbit(p int) uint {
|
||
n := uint(0)
|
||
for ; p > 0; p >>= 1 {
|
||
n++
|
||
}
|
||
return n
|
||
}
|
||
|
||
// polyDiv divides the polynomial p by q and returns the remainder.
|
||
func polyDiv(p, q int) int {
|
||
np := nbit(p)
|
||
nq := nbit(q)
|
||
for ; np >= nq; np-- {
|
||
if p&(1<<(np-1)) != 0 {
|
||
p ^= q << (np - nq)
|
||
}
|
||
}
|
||
return p
|
||
}
|
||
|
||
// mul returns the product x*y mod poly, a GF(256) multiplication.
|
||
func mul(x, y, poly int) int {
|
||
z := 0
|
||
for x > 0 {
|
||
if x&1 != 0 {
|
||
z ^= y
|
||
}
|
||
x >>= 1
|
||
y <<= 1
|
||
if y&0x100 != 0 {
|
||
y ^= poly
|
||
}
|
||
}
|
||
return z
|
||
}
|
||
|
||
// reducible reports whether p is reducible.
|
||
func reducible(p int) bool {
|
||
// Multiplying n-bit * n-bit produces (2n-1)-bit,
|
||
// so if p is reducible, one of its factors must be
|
||
// of np/2+1 bits or fewer.
|
||
np := nbit(p)
|
||
for q := 2; q < int(1<<(np/2+1)); q++ {
|
||
if polyDiv(p, q) == 0 {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// Add returns the sum of x and y in the field.
|
||
func (f *Field) Add(x, y byte) byte {
|
||
return x ^ y
|
||
}
|
||
|
||
// Exp returns the the base-α exponential of e in the field.
|
||
// If e < 0, Exp returns 0.
|
||
func (f *Field) Exp(e int) byte {
|
||
if e < 0 {
|
||
return 0
|
||
}
|
||
return f.exp[e%255]
|
||
}
|
||
|
||
// Log returns the base-α logarithm of x in the field.
|
||
// If x == 0, Log returns -1.
|
||
func (f *Field) Log(x byte) int {
|
||
if x == 0 {
|
||
return -1
|
||
}
|
||
return int(f.log[x])
|
||
}
|
||
|
||
// Inv returns the multiplicative inverse of x in the field.
|
||
// If x == 0, Inv returns 0.
|
||
func (f *Field) Inv(x byte) byte {
|
||
if x == 0 {
|
||
return 0
|
||
}
|
||
return f.exp[255-f.log[x]]
|
||
}
|
||
|
||
// Mul returns the product of x and y in the field.
|
||
func (f *Field) Mul(x, y byte) byte {
|
||
if x == 0 || y == 0 {
|
||
return 0
|
||
}
|
||
return f.exp[int(f.log[x])+int(f.log[y])]
|
||
}
|
||
|
||
// An RSEncoder implements Reed-Solomon encoding
|
||
// over a given field using a given number of error correction bytes.
|
||
type RSEncoder struct {
|
||
f *Field
|
||
c int
|
||
gen []byte
|
||
lgen []byte
|
||
p []byte
|
||
}
|
||
|
||
func (f *Field) gen(e int) (gen, lgen []byte) {
|
||
// p = 1
|
||
p := make([]byte, e+1)
|
||
p[e] = 1
|
||
|
||
for i := 0; i < e; i++ {
|
||
// p *= (x + Exp(i))
|
||
// p[j] = p[j]*Exp(i) + p[j+1].
|
||
c := f.Exp(i)
|
||
for j := 0; j < e; j++ {
|
||
p[j] = f.Mul(p[j], c) ^ p[j+1]
|
||
}
|
||
p[e] = f.Mul(p[e], c)
|
||
}
|
||
|
||
// lp = log p.
|
||
lp := make([]byte, e+1)
|
||
for i, c := range p {
|
||
if c == 0 {
|
||
lp[i] = 255
|
||
} else {
|
||
lp[i] = byte(f.Log(c))
|
||
}
|
||
}
|
||
|
||
return p, lp
|
||
}
|
||
|
||
// NewRSEncoder returns a new Reed-Solomon encoder
|
||
// over the given field and number of error correction bytes.
|
||
func NewRSEncoder(f *Field, c int) *RSEncoder {
|
||
gen, lgen := f.gen(c)
|
||
return &RSEncoder{f: f, c: c, gen: gen, lgen: lgen}
|
||
}
|
||
|
||
// ECC writes to check the error correcting code bytes
|
||
// for data using the given Reed-Solomon parameters.
|
||
func (rs *RSEncoder) ECC(data []byte, check []byte) {
|
||
if len(check) < rs.c {
|
||
panic("gf256: invalid check byte length")
|
||
}
|
||
if rs.c == 0 {
|
||
return
|
||
}
|
||
|
||
// The check bytes are the remainder after dividing
|
||
// data padded with c zeros by the generator polynomial.
|
||
|
||
// p = data padded with c zeros.
|
||
var p []byte
|
||
n := len(data) + rs.c
|
||
if len(rs.p) >= n {
|
||
p = rs.p
|
||
} else {
|
||
p = make([]byte, n)
|
||
}
|
||
copy(p, data)
|
||
for i := len(data); i < len(p); i++ {
|
||
p[i] = 0
|
||
}
|
||
|
||
// Divide p by gen, leaving the remainder in p[len(data):].
|
||
// p[0] is the most significant term in p, and
|
||
// gen[0] is the most significant term in the generator,
|
||
// which is always 1.
|
||
// To avoid repeated work, we store various values as
|
||
// lv, not v, where lv = log[v].
|
||
f := rs.f
|
||
lgen := rs.lgen[1:]
|
||
for i := 0; i < len(data); i++ {
|
||
c := p[i]
|
||
if c == 0 {
|
||
continue
|
||
}
|
||
q := p[i+1:]
|
||
exp := f.exp[f.log[c]:]
|
||
for j, lg := range lgen {
|
||
if lg != 255 { // lgen uses 255 for log 0
|
||
q[j] ^= exp[lg]
|
||
}
|
||
}
|
||
}
|
||
copy(check, p[len(data):])
|
||
rs.p = p
|
||
}
|