taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

gf_poly.go (4361B)


      1 // go-qrcode
      2 // Copyright 2014 Tom Harwood
      3 
      4 package reedsolomon
      5 
      6 import (
      7 	"fmt"
      8 	"log"
      9 
     10 	bitset "github.com/skip2/go-qrcode/bitset"
     11 )
     12 
     13 // gfPoly is a polynomial over GF(2^8).
     14 type gfPoly struct {
     15 	// The ith value is the coefficient of the ith degree of x.
     16 	// term[0]*(x^0) + term[1]*(x^1) + term[2]*(x^2) ...
     17 	term []gfElement
     18 }
     19 
     20 // newGFPolyFromData returns |data| as a polynomial over GF(2^8).
     21 //
     22 // Each data byte becomes the coefficient of an x term.
     23 //
     24 // For an n byte input the polynomial is:
     25 // data[n-1]*(x^n-1) + data[n-2]*(x^n-2) ... + data[0]*(x^0).
     26 func newGFPolyFromData(data *bitset.Bitset) gfPoly {
     27 	numTotalBytes := data.Len() / 8
     28 	if data.Len()%8 != 0 {
     29 		numTotalBytes++
     30 	}
     31 
     32 	result := gfPoly{term: make([]gfElement, numTotalBytes)}
     33 
     34 	i := numTotalBytes - 1
     35 	for j := 0; j < data.Len(); j += 8 {
     36 		result.term[i] = gfElement(data.ByteAt(j))
     37 		i--
     38 	}
     39 
     40 	return result
     41 }
     42 
     43 // newGFPolyMonomial returns term*(x^degree).
     44 func newGFPolyMonomial(term gfElement, degree int) gfPoly {
     45 	if term == gfZero {
     46 		return gfPoly{}
     47 	}
     48 
     49 	result := gfPoly{term: make([]gfElement, degree+1)}
     50 	result.term[degree] = term
     51 
     52 	return result
     53 }
     54 
     55 func (e gfPoly) data(numTerms int) []byte {
     56 	result := make([]byte, numTerms)
     57 
     58 	i := numTerms - len(e.term)
     59 	for j := len(e.term) - 1; j >= 0; j-- {
     60 		result[i] = byte(e.term[j])
     61 		i++
     62 	}
     63 
     64 	return result
     65 }
     66 
     67 // numTerms returns the number of
     68 func (e gfPoly) numTerms() int {
     69 	return len(e.term)
     70 }
     71 
     72 // gfPolyMultiply returns a * b.
     73 func gfPolyMultiply(a, b gfPoly) gfPoly {
     74 	numATerms := a.numTerms()
     75 	numBTerms := b.numTerms()
     76 
     77 	result := gfPoly{term: make([]gfElement, numATerms+numBTerms)}
     78 
     79 	for i := 0; i < numATerms; i++ {
     80 		for j := 0; j < numBTerms; j++ {
     81 			if a.term[i] != 0 && b.term[j] != 0 {
     82 				monomial := gfPoly{term: make([]gfElement, i+j+1)}
     83 				monomial.term[i+j] = gfMultiply(a.term[i], b.term[j])
     84 
     85 				result = gfPolyAdd(result, monomial)
     86 			}
     87 		}
     88 	}
     89 
     90 	return result.normalised()
     91 }
     92 
     93 // gfPolyRemainder return the remainder of numerator / denominator.
     94 func gfPolyRemainder(numerator, denominator gfPoly) gfPoly {
     95 	if denominator.equals(gfPoly{}) {
     96 		log.Panicln("Remainder by zero")
     97 	}
     98 
     99 	remainder := numerator
    100 
    101 	for remainder.numTerms() >= denominator.numTerms() {
    102 		degree := remainder.numTerms() - denominator.numTerms()
    103 		coefficient := gfDivide(remainder.term[remainder.numTerms()-1],
    104 			denominator.term[denominator.numTerms()-1])
    105 
    106 		divisor := gfPolyMultiply(denominator,
    107 			newGFPolyMonomial(coefficient, degree))
    108 
    109 		remainder = gfPolyAdd(remainder, divisor)
    110 	}
    111 
    112 	return remainder.normalised()
    113 }
    114 
    115 // gfPolyAdd returns a + b.
    116 func gfPolyAdd(a, b gfPoly) gfPoly {
    117 	numATerms := a.numTerms()
    118 	numBTerms := b.numTerms()
    119 
    120 	numTerms := numATerms
    121 	if numBTerms > numTerms {
    122 		numTerms = numBTerms
    123 	}
    124 
    125 	result := gfPoly{term: make([]gfElement, numTerms)}
    126 
    127 	for i := 0; i < numTerms; i++ {
    128 		switch {
    129 		case numATerms > i && numBTerms > i:
    130 			result.term[i] = gfAdd(a.term[i], b.term[i])
    131 		case numATerms > i:
    132 			result.term[i] = a.term[i]
    133 		default:
    134 			result.term[i] = b.term[i]
    135 		}
    136 	}
    137 
    138 	return result.normalised()
    139 }
    140 
    141 func (e gfPoly) normalised() gfPoly {
    142 	numTerms := e.numTerms()
    143 	maxNonzeroTerm := numTerms - 1
    144 
    145 	for i := numTerms - 1; i >= 0; i-- {
    146 		if e.term[i] != 0 {
    147 			break
    148 		}
    149 
    150 		maxNonzeroTerm = i - 1
    151 	}
    152 
    153 	if maxNonzeroTerm < 0 {
    154 		return gfPoly{}
    155 	} else if maxNonzeroTerm < numTerms-1 {
    156 		e.term = e.term[0 : maxNonzeroTerm+1]
    157 	}
    158 
    159 	return e
    160 }
    161 
    162 func (e gfPoly) string(useIndexForm bool) string {
    163 	var str string
    164 	numTerms := e.numTerms()
    165 
    166 	for i := numTerms - 1; i >= 0; i-- {
    167 		if e.term[i] > 0 {
    168 			if len(str) > 0 {
    169 				str += " + "
    170 			}
    171 
    172 			if !useIndexForm {
    173 				str += fmt.Sprintf("%dx^%d", e.term[i], i)
    174 			} else {
    175 				str += fmt.Sprintf("a^%dx^%d", gfLogTable[e.term[i]], i)
    176 			}
    177 		}
    178 	}
    179 
    180 	if len(str) == 0 {
    181 		str = "0"
    182 	}
    183 
    184 	return str
    185 }
    186 
    187 // equals returns true if e == other.
    188 func (e gfPoly) equals(other gfPoly) bool {
    189 	var minecPoly *gfPoly
    190 	var maxecPoly *gfPoly
    191 
    192 	if e.numTerms() > other.numTerms() {
    193 		minecPoly = &other
    194 		maxecPoly = &e
    195 	} else {
    196 		minecPoly = &e
    197 		maxecPoly = &other
    198 	}
    199 
    200 	numMinTerms := minecPoly.numTerms()
    201 	numMaxTerms := maxecPoly.numTerms()
    202 
    203 	for i := 0; i < numMinTerms; i++ {
    204 		if e.term[i] != other.term[i] {
    205 			return false
    206 		}
    207 	}
    208 
    209 	for i := numMinTerms; i < numMaxTerms; i++ {
    210 		if maxecPoly.term[i] != 0 {
    211 			return false
    212 		}
    213 	}
    214 
    215 	return true
    216 }