mirror of
https://github.com/42wim/matterbridge.git
synced 2024-11-30 14:42:00 -08:00
217 lines
4.3 KiB
Go
217 lines
4.3 KiB
Go
|
// go-qrcode
|
||
|
// Copyright 2014 Tom Harwood
|
||
|
|
||
|
package reedsolomon
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
|
||
|
bitset "github.com/skip2/go-qrcode/bitset"
|
||
|
)
|
||
|
|
||
|
// gfPoly is a polynomial over GF(2^8).
|
||
|
type gfPoly struct {
|
||
|
// The ith value is the coefficient of the ith degree of x.
|
||
|
// term[0]*(x^0) + term[1]*(x^1) + term[2]*(x^2) ...
|
||
|
term []gfElement
|
||
|
}
|
||
|
|
||
|
// newGFPolyFromData returns |data| as a polynomial over GF(2^8).
|
||
|
//
|
||
|
// Each data byte becomes the coefficient of an x term.
|
||
|
//
|
||
|
// For an n byte input the polynomial is:
|
||
|
// data[n-1]*(x^n-1) + data[n-2]*(x^n-2) ... + data[0]*(x^0).
|
||
|
func newGFPolyFromData(data *bitset.Bitset) gfPoly {
|
||
|
numTotalBytes := data.Len() / 8
|
||
|
if data.Len()%8 != 0 {
|
||
|
numTotalBytes++
|
||
|
}
|
||
|
|
||
|
result := gfPoly{term: make([]gfElement, numTotalBytes)}
|
||
|
|
||
|
i := numTotalBytes - 1
|
||
|
for j := 0; j < data.Len(); j += 8 {
|
||
|
result.term[i] = gfElement(data.ByteAt(j))
|
||
|
i--
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// newGFPolyMonomial returns term*(x^degree).
|
||
|
func newGFPolyMonomial(term gfElement, degree int) gfPoly {
|
||
|
if term == gfZero {
|
||
|
return gfPoly{}
|
||
|
}
|
||
|
|
||
|
result := gfPoly{term: make([]gfElement, degree+1)}
|
||
|
result.term[degree] = term
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
func (e gfPoly) data(numTerms int) []byte {
|
||
|
result := make([]byte, numTerms)
|
||
|
|
||
|
i := numTerms - len(e.term)
|
||
|
for j := len(e.term) - 1; j >= 0; j-- {
|
||
|
result[i] = byte(e.term[j])
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// numTerms returns the number of
|
||
|
func (e gfPoly) numTerms() int {
|
||
|
return len(e.term)
|
||
|
}
|
||
|
|
||
|
// gfPolyMultiply returns a * b.
|
||
|
func gfPolyMultiply(a, b gfPoly) gfPoly {
|
||
|
numATerms := a.numTerms()
|
||
|
numBTerms := b.numTerms()
|
||
|
|
||
|
result := gfPoly{term: make([]gfElement, numATerms+numBTerms)}
|
||
|
|
||
|
for i := 0; i < numATerms; i++ {
|
||
|
for j := 0; j < numBTerms; j++ {
|
||
|
if a.term[i] != 0 && b.term[j] != 0 {
|
||
|
monomial := gfPoly{term: make([]gfElement, i+j+1)}
|
||
|
monomial.term[i+j] = gfMultiply(a.term[i], b.term[j])
|
||
|
|
||
|
result = gfPolyAdd(result, monomial)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result.normalised()
|
||
|
}
|
||
|
|
||
|
// gfPolyRemainder return the remainder of numerator / denominator.
|
||
|
func gfPolyRemainder(numerator, denominator gfPoly) gfPoly {
|
||
|
if denominator.equals(gfPoly{}) {
|
||
|
log.Panicln("Remainder by zero")
|
||
|
}
|
||
|
|
||
|
remainder := numerator
|
||
|
|
||
|
for remainder.numTerms() >= denominator.numTerms() {
|
||
|
degree := remainder.numTerms() - denominator.numTerms()
|
||
|
coefficient := gfDivide(remainder.term[remainder.numTerms()-1],
|
||
|
denominator.term[denominator.numTerms()-1])
|
||
|
|
||
|
divisor := gfPolyMultiply(denominator,
|
||
|
newGFPolyMonomial(coefficient, degree))
|
||
|
|
||
|
remainder = gfPolyAdd(remainder, divisor)
|
||
|
}
|
||
|
|
||
|
return remainder.normalised()
|
||
|
}
|
||
|
|
||
|
// gfPolyAdd returns a + b.
|
||
|
func gfPolyAdd(a, b gfPoly) gfPoly {
|
||
|
numATerms := a.numTerms()
|
||
|
numBTerms := b.numTerms()
|
||
|
|
||
|
numTerms := numATerms
|
||
|
if numBTerms > numTerms {
|
||
|
numTerms = numBTerms
|
||
|
}
|
||
|
|
||
|
result := gfPoly{term: make([]gfElement, numTerms)}
|
||
|
|
||
|
for i := 0; i < numTerms; i++ {
|
||
|
switch {
|
||
|
case numATerms > i && numBTerms > i:
|
||
|
result.term[i] = gfAdd(a.term[i], b.term[i])
|
||
|
case numATerms > i:
|
||
|
result.term[i] = a.term[i]
|
||
|
default:
|
||
|
result.term[i] = b.term[i]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result.normalised()
|
||
|
}
|
||
|
|
||
|
func (e gfPoly) normalised() gfPoly {
|
||
|
numTerms := e.numTerms()
|
||
|
maxNonzeroTerm := numTerms - 1
|
||
|
|
||
|
for i := numTerms - 1; i >= 0; i-- {
|
||
|
if e.term[i] != 0 {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
maxNonzeroTerm = i - 1
|
||
|
}
|
||
|
|
||
|
if maxNonzeroTerm < 0 {
|
||
|
return gfPoly{}
|
||
|
} else if maxNonzeroTerm < numTerms-1 {
|
||
|
e.term = e.term[0 : maxNonzeroTerm+1]
|
||
|
}
|
||
|
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
func (e gfPoly) string(useIndexForm bool) string {
|
||
|
var str string
|
||
|
numTerms := e.numTerms()
|
||
|
|
||
|
for i := numTerms - 1; i >= 0; i-- {
|
||
|
if e.term[i] > 0 {
|
||
|
if len(str) > 0 {
|
||
|
str += " + "
|
||
|
}
|
||
|
|
||
|
if !useIndexForm {
|
||
|
str += fmt.Sprintf("%dx^%d", e.term[i], i)
|
||
|
} else {
|
||
|
str += fmt.Sprintf("a^%dx^%d", gfLogTable[e.term[i]], i)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if len(str) == 0 {
|
||
|
str = "0"
|
||
|
}
|
||
|
|
||
|
return str
|
||
|
}
|
||
|
|
||
|
// equals returns true if e == other.
|
||
|
func (e gfPoly) equals(other gfPoly) bool {
|
||
|
var minecPoly *gfPoly
|
||
|
var maxecPoly *gfPoly
|
||
|
|
||
|
if e.numTerms() > other.numTerms() {
|
||
|
minecPoly = &other
|
||
|
maxecPoly = &e
|
||
|
} else {
|
||
|
minecPoly = &e
|
||
|
maxecPoly = &other
|
||
|
}
|
||
|
|
||
|
numMinTerms := minecPoly.numTerms()
|
||
|
numMaxTerms := maxecPoly.numTerms()
|
||
|
|
||
|
for i := 0; i < numMinTerms; i++ {
|
||
|
if e.term[i] != other.term[i] {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for i := numMinTerms; i < numMaxTerms; i++ {
|
||
|
if maxecPoly.term[i] != 0 {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|