pax_global_header00006660000000000000000000000064152105121640014507gustar00rootroot0000000000000052 comment=13ea8697750a7ea512f9c28a48afa8530fec6aab golang-github-yeqown-reedsolomon-1.0.0/000077500000000000000000000000001521051216400201005ustar00rootroot00000000000000golang-github-yeqown-reedsolomon-1.0.0/README.md000066400000000000000000000000331521051216400213530ustar00rootroot00000000000000# reed solomon encoding libgolang-github-yeqown-reedsolomon-1.0.0/binary/000077500000000000000000000000001521051216400213645ustar00rootroot00000000000000golang-github-yeqown-reedsolomon-1.0.0/binary/binary.go000066400000000000000000000125501521051216400232020ustar00rootroot00000000000000// Package binary ... // thanks to https://github.com/skip2/go-qrcode/blob/master/bitset/bitset.go // I cannot do any better for now, so I just learn and write it again~ package binary import ( "bytes" "fmt" "log" ) const ( byteTrue byte = '1' byteFalse byte = '0' ) var ( // format string format = "Binary length: %d, bits: %s" ) // New ... func New(booleans ...bool) *Binary { b := &Binary{ bits: make([]byte, 0), lenBits: 0, } b.AppendBools(booleans...) return b } // NewFromBinaryString ... generate Bitset from binary string // auto get length func NewFromBinaryString(s string) (*Binary, error) { var n = len(s) / 8 if len(s)%8 != 0 { n++ } b := &Binary{ bits: make([]byte, n), // prealloc memory, reducing useless space lenBits: 0, } for _, c := range s { switch c { case '1': b.AppendBools(true) case '0': b.AppendBools(false) case ' ': // skip space blank continue default: err := fmt.Errorf("invalid char %c in NewFromBinaryString", c) return nil, err } } return b, nil } // Binary struct contains bits stream and methods to be called from outside // exsample: // b.Len() // b.Subset(start, end) // b.At(pos) type Binary struct { bits []byte // 1byte = 8bit lenBits int // len(bits) * 8 } // ensureCapacity ensures the Bitset can store an additional |numBits|. // // The underlying array is expanded if necessary. To prevent frequent // reallocation, expanding the underlying array at least doubles its capacity. // // then no need to use append ~ will no panic (out of range) func (b *Binary) ensureCapacity(numBits int) { numBits += b.lenBits newNumBytes := numBits / 8 if numBits%8 != 0 { newNumBytes++ } // if larger enough if len(b.bits) >= newNumBytes { return } // larger capcity, about 3 times of current capcity b.bits = append(b.bits, make([]byte, newNumBytes+2*len(b.bits))...) } // At .get boolean value from func (b *Binary) At(pos int) bool { if pos < 0 || pos >= b.lenBits { panic("out range of bits") } return (b.bits[pos/8]&(0x80>>uint(pos%8)) != 0) } // Subset do the same work like slice[start:end] func (b *Binary) Subset(start, end int) (*Binary, error) { if start > end || end > b.lenBits { err := fmt.Errorf("Out of range start=%d end=%d lenBits=%d", start, end, b.lenBits) return nil, err } result := New() result.ensureCapacity(end - start) for i := start; i < end; i++ { if b.At(i) { result.bits[result.lenBits/8] |= 0x80 >> uint(result.lenBits%8) } result.lenBits++ } return result, nil } // Append other bitset link another Bitset to after the b func (b *Binary) Append(other *Binary) { b.ensureCapacity(other.Len()) for i := 0; i < other.lenBits; i++ { if other.At(i) { b.bits[b.lenBits/8] |= 0x80 >> uint(b.lenBits%8) } b.lenBits++ } } // AppendUint32 other bitset link another Bitset to after the b func (b *Binary) AppendUint32(value uint32, numBits int) { b.ensureCapacity(numBits) if numBits > 32 { log.Panicf("numBits %d out of range 0-32", numBits) } for i := numBits - 1; i >= 0; i-- { if value&(1<> uint(b.lenBits%8) } b.lenBits++ } } // AppendBytes ... func (b *Binary) AppendBytes(byts ...byte) { for _, byt := range byts { b.AppendByte(byt, 8) } } // AppendByte ... specified num bits to append func (b *Binary) AppendByte(byt byte, numBits int) error { if numBits > 8 || numBits < 0 { return fmt.Errorf("numBits out of range 0-8") } b.ensureCapacity(numBits) // append bit in byte for i := numBits - 1; i >= 0; i-- { // 0x01 << left shift count // 0x80 >> right shift count if byt&(0x01<> uint(b.lenBits%8) } b.lenBits++ } return nil } // AppendBools append multi bool after the bit stream of b func (b *Binary) AppendBools(booleans ...bool) { b.ensureCapacity(len(booleans)) for _, bv := range booleans { if bv { b.bits[b.lenBits/8] |= 0x80 >> uint(b.lenBits%8) } b.lenBits++ } } // AppendNumBools appends num bits of value value. func (b *Binary) AppendNumBools(num int, boolean bool) { booleans := make([]bool, num) // if not false just append if boolean { for i := 0; i < num; i++ { booleans[i] = boolean } } b.AppendBools(booleans...) } // IterFunc used by func b.VisitAll ... type IterFunc func(pos int, v bool) // VisitAll loop the b.bits stream and send value into IterFunc func (b *Binary) VisitAll(f IterFunc) { for pos := 0; pos < b.Len(); pos++ { f(pos, b.At(pos)) } } // String for printing func (b *Binary) String() string { var ( bitstr []byte vb byte ) b.VisitAll(func(pos int, v bool) { vb = byteFalse if v { vb = byteTrue } bitstr = append(bitstr, vb) }) return fmt.Sprintf(format, b.Len(), string(bitstr)) } // Len ... func (b *Binary) Len() int { return b.lenBits } // Bytes ... func (b *Binary) Bytes() []byte { numBytes := b.lenBits / 8 if b.lenBits%8 != 0 { numBytes++ } return b.bits[:numBytes] } // EqualTo ... func (b *Binary) EqualTo(other *Binary) bool { if b.lenBits != other.lenBits { return false } numByte := b.lenBits / 8 if !bytes.Equal(b.bits[:numByte], other.bits[:numByte]) { return false } for pos := numByte * 8; pos < b.lenBits; pos++ { if b.At(pos) != other.At(pos) { return false } } return true } // Copy ... func (b *Binary) Copy() *Binary { return &Binary{ bits: b.bits, lenBits: b.lenBits, } } golang-github-yeqown-reedsolomon-1.0.0/binary/binary_test.go000066400000000000000000000302551521051216400242430ustar00rootroot00000000000000package binary import ( "reflect" "testing" ) func TestNew(t *testing.T) { type args struct { booleans []bool } tests := []struct { name string args args want *Binary }{ { name: "case 0", args: args{ // 10001 0x88 booleans: []bool{true, false, false, false, true}, }, want: &Binary{ bits: []byte{0x88}, lenBits: 5, }, }, { name: "case 1", args: args{ // 1111 1111 1111 0xff 0xf0 booleans: []bool{true, true, true, true, true, true, true, true, true, true, true, true}, }, want: &Binary{ bits: []byte{0xff, 0xf0}, lenBits: 12, }, }, { name: "case 2", args: args{ // 0 booleans: []bool{}, }, want: &Binary{ bits: []byte{}, lenBits: 0, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := New(tt.args.booleans...); !reflect.DeepEqual(got, tt.want) { t.Errorf("New() = %v, want %v", got, tt.want) } }) } } func TestNewFromBinaryString(t *testing.T) { type args struct { s string } tests := []struct { name string args args want *Binary wantErr bool }{ { name: "case 0", args: args{ s: "10011000 1111", }, want: &Binary{ bits: []byte{0x98, 0xf0}, lenBits: 12, }, wantErr: false, }, { name: "case 1, invalid char", args: args{ s: "10011000 c111", }, want: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewFromBinaryString(tt.args.s) if (err != nil) != tt.wantErr { t.Errorf("NewFromBinaryString() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("NewFromBinaryString() = %v, want %v", got, tt.want) } }) } } func TestBinary_ensureCapacity(t *testing.T) { type args struct { numBits int } tests := []struct { name string b *Binary args args }{ { name: "case 0, 0 numBits", b: New(), args: args{ numBits: 0, }, }, { name: "case 1, 8 numBits", b: New(), args: args{ numBits: 8, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.b.ensureCapacity(tt.args.numBits) if cap(tt.b.bits) < tt.args.numBits { t.Errorf("could not ensureCapcity") } }) } } func TestBinary_At(t *testing.T) { type args struct { pos int } tests := []struct { name string b *Binary args args want bool }{ { name: "case 0, pos 0 of len 4", b: New(true, false, true, false), // 1010 args: args{pos: 0}, want: true, }, // { // name: "case 1, pos 4 of len 4", // b: New(true, false, true, false), // 1010, this should panic or not? // args: args{pos: 4}, // want: false, // }, { name: "case 2, pos 3 of len 4", b: New(true, false, true, false), // 1010 args: args{pos: 3}, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.b.At(tt.args.pos); got != tt.want { t.Errorf("Binary.At() = %v, want %v", got, tt.want) } }) } } func TestBinary_Subset(t *testing.T) { type args struct { start int end int } tests := []struct { name string b *Binary args args want *Binary wantErr bool }{ { name: "case 0", b: New(true, true, true, true, false, false, false, false, true, false), // 0xf0 0x80, (0b1111000010) args: args{ start: 0, end: 10, }, want: New(true, true, true, true, false, false, false, false, true, false), wantErr: false, }, { name: "case 1", b: New(true, true, true, true, false, false, false, false, true, false), // 0xf0 0x80, (0b1111000010) args: args{ start: 4, end: 9, }, want: New(false, false, false, false, true), wantErr: false, }, { name: "case 2", b: New(true, true, true, true, false, false, false, false, true, false), // 0xf0 0x80, (0b1111000010) args: args{ start: 3, end: 8, }, want: New(true, false, false, false, false), wantErr: false, }, // { // name: "case 2", // // 0xf0 0x80, (0b1111000010) // b: New(true, true, true, true, false, false, false, false, true, false), // args: args{ // start: 3, // end: 14, // }, // want: nil, // wantErr: true, // }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := tt.b.Subset(tt.args.start, tt.args.end) if (err != nil) != tt.wantErr { t.Errorf("Binary.Subset() error = %v, wantErr %v", err, tt.wantErr) return } if !got.EqualTo(tt.want) { t.Errorf("Binary.Subset() = %v, want %v", got, tt.want) } }) } } func TestBinary_Append(t *testing.T) { type args struct { other *Binary } tests := []struct { name string b *Binary args args equalTo string }{ { name: "case 0", b: New(true), args: args{ other: New(false, false, false), }, equalTo: "1000", }, { name: "case 0", b: New(true), args: args{ other: New(false, false, false), }, equalTo: "1000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.b.Append(tt.args.other) e, _ := NewFromBinaryString(tt.equalTo) if !tt.b.EqualTo(e) { t.Errorf("Binary.Append() = %v, want %v", tt.b, e) } }) } } func TestBinary_AppendBytes(t *testing.T) { type args struct { byts []byte } tests := []struct { name string b *Binary args args want *Binary }{ { name: "case 0", b: &Binary{ bits: []byte{0xff, 0xc0}, lenBits: 12, }, args: args{ byts: []byte{0xff, 0x00}, }, want: &Binary{ bits: []byte{0xff, 0xcf, 0xf0, 0x00}, lenBits: 28, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.b.AppendBytes(tt.args.byts...) if !tt.want.EqualTo(tt.b) { t.Errorf("Binary.AppendBytes want: %v, got: %v", tt.want, tt.b) } }) } } func TestBinary_AppendByte(t *testing.T) { type args struct { byt byte numBits int } tests := []struct { name string b *Binary args args wantErr bool want string }{ { name: "case 0", b: New(), args: args{ byt: 0xff, numBits: 8, }, want: "1111 1111", wantErr: false, }, { name: "case 1", b: New(), args: args{ byt: 0xff, numBits: 0, }, want: "", wantErr: false, }, { name: "case 2", b: New(), args: args{ byt: 0xff, numBits: 9, }, want: "", wantErr: true, }, { name: "case 3", b: New(true, false, true), args: args{ byt: 0xff, numBits: 3, }, want: "101 111", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := tt.b.AppendByte(tt.args.byt, tt.args.numBits); (err != nil) != tt.wantErr { t.Errorf("Binary.AppendByte() error = %v, wantErr %v", err, tt.wantErr) } if wantB, _ := NewFromBinaryString(tt.want); !wantB.EqualTo(tt.b) { t.Errorf("Binary.AppendByte() got = %v, want %v", tt.b, wantB) } }) } } func TestBinary_AppendBools(t *testing.T) { type args struct { booleans []bool } tests := []struct { name string b *Binary args args wantLen int }{ { name: "case 0", b: New(), args: args{ booleans: []bool{true, true, false}, }, wantLen: 3, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.b.AppendBools(tt.args.booleans...); tt.b.Len() != tt.wantLen { t.Errorf("Binary.AppendBools() wantLen: %d, but %d", tt.wantLen, tt.b.Len()) } }) } } func TestBinary_AppendNumBools(t *testing.T) { type args struct { num int boolean bool } tests := []struct { name string b *Binary args args want string }{ { name: "case 0", b: New(false, true, false), args: args{ num: 4, boolean: true, }, want: "0101111", }, { name: "case 0", b: New(false, true, false), args: args{ num: 3, boolean: false, }, want: "010000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.b.AppendNumBools(tt.args.num, tt.args.boolean) if wantB, _ := NewFromBinaryString(tt.want); !wantB.EqualTo(tt.b) { t.Errorf("Binary.AppendNumBools() want: %v, but %v", wantB, tt.b) } }) } } func TestBinary_VisitAll(t *testing.T) { type args struct { f IterFunc } tests := []struct { name string b *Binary args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.b.VisitAll(tt.args.f) }) } } func TestBinary_String(t *testing.T) { tests := []struct { name string b *Binary want string }{ { name: "case 0", b: New(true, false, true, false), want: "Binary length: 4, bits: 1010", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.b.String(); got != tt.want { t.Errorf("Binary.String() = %v, want %v", got, tt.want) } }) } } func TestBinary_Len(t *testing.T) { tests := []struct { name string b *Binary want int }{ { name: "case 0", b: New([]bool{true, false, true, false, true, false}...), want: 6, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.b.Len(); got != tt.want { t.Errorf("Binary.Len() = %v, want %v", got, tt.want) } }) } } func TestBinary_EqualTo(t *testing.T) { type args struct { other string } tests := []struct { name string b1 *Binary b2 *Binary want bool }{ { name: "case 0", b1: &Binary{ bits: []byte{0x88, 0xc0}, lenBits: 10, }, b2: &Binary{ bits: []byte{0x88, 0xc1}, lenBits: 10, }, want: true, }, { name: "case 1", b1: &Binary{ bits: []byte{0x88, 0xc1}, lenBits: 16, }, b2: &Binary{ bits: []byte{0xff, 0xc1}, lenBits: 16, }, want: false, }, { name: "case 2", b1: &Binary{ bits: []byte{0x88, 0xc1}, lenBits: 16, }, b2: &Binary{ bits: []byte{0x88, 0xc1}, lenBits: 10, }, want: false, }, { name: "case 2", b1: &Binary{ bits: []byte{0x88, 0xc1}, lenBits: 16, }, b2: &Binary{ bits: []byte{0x88, 0xcf}, lenBits: 16, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.b1.EqualTo(tt.b2); got != tt.want { t.Errorf("Binary.EqualTo() want: %v, got: %v, b1: %v, b2: %v", tt.want, got, tt.b1, tt.b2) } }) } } func TestBinary_Copy(t *testing.T) { type fields struct { bits []byte lenBits int } tests := []struct { name string fields fields want *Binary }{ { name: "case 0", fields: fields{ bits: []byte{0x12, 0x34}, lenBits: 16, }, want: &Binary{ bits: []byte{0x12, 0x34}, lenBits: 16, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b := &Binary{ bits: tt.fields.bits, lenBits: tt.fields.lenBits, } got := b.Copy() b.AppendByte(0x33, 8) if !reflect.DeepEqual(got, tt.want) { t.Errorf("Binary.Copy() = %v, want %v", got, tt.want) } if b.EqualTo(got) { t.Errorf("Binary.Copy() changed b: %v, but copy %v changed too", b, got) } }) } } func TestBinary_AppendUint32(t *testing.T) { type fields struct { bits []byte lenBits int } type args struct { value uint32 numBits int } tests := []struct { name string fields fields args args want *Binary }{ { name: "case 0", fields: fields{ bits: []byte{0x22}, lenBits: 8, }, args: args{ value: 0xf12f, numBits: 9, }, want: &Binary{ bits: []byte{0x22, 0x97, 0x80}, lenBits: 17, }, }, { name: "case 2", fields: fields{ bits: []byte{0x22}, lenBits: 8, }, args: args{ value: 0xf12f, numBits: 13, }, want: &Binary{ bits: []byte{0x22, 0x89, 0x78}, lenBits: 21, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b := &Binary{ bits: tt.fields.bits, lenBits: tt.fields.lenBits, } t.Logf("origin binary: %v", b) b.AppendUint32(tt.args.value, tt.args.numBits) if !b.EqualTo(tt.want) { t.Errorf("Binary.AppendUint32(): %v, want: %v", b, tt.want) } }) } } golang-github-yeqown-reedsolomon-1.0.0/galois_field.go000066400000000000000000000022351521051216400230520ustar00rootroot00000000000000package reedsolomon // ref to https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders // ref to https://www.jianshu.com/p/8208aad537bb // gf.go Galois Fields var ( gfLog = []byte{} gfExp = []byte{} ) const prim = 0x011d // init calls all initial funcs func init() { initTables() } // init gfExp and gfLog array func initTables() { gfExp = make([]byte, 512) gfLog = make([]byte, 256) var ( x uint16 = 1 ) for i := 0; i < 255; i++ { gfExp[i] = byte(x) gfLog[x] = byte(i) x <<= 1 // x overflow 256 if (x & 0x100) != 0 { x ^= prim } } for i := 255; i < 512; i++ { gfExp[i] = gfExp[i-255] } } // multpy func gfMul(x, y byte) byte { if x == 0 || y == 0 { return 0 } // byte max: 256 but exp cap is 512 return gfExp[uint(gfLog[x])+uint(gfLog[y])] } // divide // func gfDiv(x, y byte) byte { // if y == 0 { // panic("zero division error") // } // if x == 0 { // return 0 // } // return gfExp[(uint(gfLog[x])+255-uint(gfLog[y]))%255] // } // // inverse // func gfInverse(x byte) byte { // return gfExp[255-uint(gfLog[x])] // } // // pow // func gfPow(x, power byte) byte { // return gfExp[(gfLog[x]*power)%255] // } golang-github-yeqown-reedsolomon-1.0.0/galois_field_test.go000066400000000000000000000032151521051216400241100ustar00rootroot00000000000000package reedsolomon import ( "testing" ) // table ref to: https://www.thonky.com/qr-code-tutorial/log-antilog-table func Test_initTables(t *testing.T) { initTables() tests := []struct { name string expIdx int expWant byte logIdx int logWant byte }{ { name: "case 0", expIdx: 0, expWant: 1, logIdx: 1, logWant: 0, }, { name: "case 1", expIdx: 255, expWant: 1, logIdx: 255, logWant: 175, }, { name: "case 2", expIdx: 300, expWant: gfExp[300%255], logIdx: 246, logWant: 173, }, { name: "case 3", expIdx: 380, expWant: 51, logIdx: 246, logWant: 173, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if v := gfExp[tt.expIdx]; v != tt.expWant { t.Errorf("gfExp[%d]: %v, want: %v", tt.expIdx, v, tt.expWant) } if v := gfLog[tt.logIdx]; v != tt.logWant { t.Errorf("gfLog[%d]: %v, want: %v", tt.logIdx, v, tt.logWant) } }) } } func Test_gfMul(t *testing.T) { initTables() type args struct { x byte y byte } tests := []struct { name string args args want byte }{ { name: "case 0", args: args{ x: 98, y: 7, }, want: 51, }, { name: "case 1", args: args{ x: 1, y: 98, }, want: 98, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Logf("log x: %v, y: %v", gfLog[tt.args.x], gfLog[tt.args.y]) // expIdx := uint(gfLog[tt.args.x]) + uint(gfLog[tt.args.y]) // t.Logf("exp[%d]: %v", expIdx, gfExp[expIdx]) if got := gfMul(tt.args.x, tt.args.y); got != tt.want { t.Errorf("gfMul() = %v, want %v", got, tt.want) } }) } } golang-github-yeqown-reedsolomon-1.0.0/go.mod000066400000000000000000000000451521051216400212050ustar00rootroot00000000000000module github.com/yeqown/reedsolomon golang-github-yeqown-reedsolomon-1.0.0/polynomial.go000066400000000000000000000034021521051216400226110ustar00rootroot00000000000000package reedsolomon // generator polynomial // (x-a^1) * (x - a^2) * .... * (x -a^numECWords-1) func rsGenPoly(numECWords int) []byte { var generator = []byte{1} for i := 0; i < numECWords; i++ { generator = polyMul(generator, []byte{1, gfExp[i]}) } return generator } // 将一个多项式和一个标量相乘 func polyScale(poly []byte, x byte) []byte { result := make([]byte, len(poly)) for i := 0; i < len(poly); i++ { result[i] = gfMul(poly[i], x) } return result } func polyAdd(poly1, poly2 []byte) []byte { size1 := len(poly1) size2 := len(poly2) size := size1 if size2 > size1 { size = size2 } result := make([]byte, size) for i := 0; i < size1; i++ { result[i] = byte(poly1[i]) } for i := 0; i < size2; i++ { result[i] ^= byte(poly2[i]) } return result } // mul polynomial func polyMul(poly1, poly2 []byte) []byte { result := make([]byte, len(poly1)+len(poly2)-1) for i := 0; i < len(poly1); i++ { for j := 0; j < len(poly2); j++ { result[i+j] ^= gfMul(poly1[i], poly2[j]) } } return result } // func polyEval(poly []byte, x byte) byte { // y := poly[0] // for i := 1; i < len(poly); i++ { // y = gfMul(y, x) ^ poly[i] // } // return y // } // ref to: https://www.thonky.com/qr-code-tutorial/show-division-steps?msg_coeff=12%2C34%2C56%2C23&num_ecc_blocks=3 func polyDiv(dividend, divisor []byte) []byte { if len(dividend) == 0 { panic("could not div with 0 length dividend") } var ( leadTerm = dividend[0] reminder, a, b []byte ) reminder = dividend for i := 0; i < len(dividend); i++ { // step a: generator * leadTerm a = polyScale(divisor, leadTerm) // step b, xor operation b = polyAdd(reminder, a) // discard lead term of b reminder = b[1:] leadTerm = reminder[0] } return reminder } golang-github-yeqown-reedsolomon-1.0.0/polynomial_test.go000066400000000000000000000027601521051216400236560ustar00rootroot00000000000000package reedsolomon import ( "reflect" "testing" ) func Test_rsGenPoly(t *testing.T) { type args struct { numECWords int } tests := []struct { name string args args want []byte }{ { name: "case 0", args: args{ numECWords: 2, }, want: []byte{1, 3, 2}, }, { name: "case 0", args: args{ numECWords: 3, }, want: []byte{1, 7, 14, 8}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := rsGenPoly(tt.args.numECWords); !reflect.DeepEqual(got, tt.want) { t.Errorf("rsGenPoly() = %v, want %v", got, tt.want) } }) } } func Test_polyDiv(t *testing.T) { type args struct { dividend []byte divisor []byte } tests := []struct { name string args args want []byte }{ { name: "case 0", args: args{ dividend: []byte{12, 34, 56, 23}, divisor: rsGenPoly(3), }, want: []byte{107, 77, 39}, }, { name: "case 1", args: args{ dividend: []byte{32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236}, divisor: rsGenPoly(10), }, want: []byte{87, 86, 68, 17, 99, 235, 189, 232, 98, 195}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Logf("divisor %v", tt.args.divisor) got := polyDiv(tt.args.dividend, tt.args.divisor) // if !reflect.DeepEqual(got, tt.want) { // t.Errorf("polyDiv() got = %v, want %v", got, tt.want) // } if !reflect.DeepEqual(got, tt.want) { t.Errorf("polyDiv() got = %v, want %v", got, tt.want) } }) } } golang-github-yeqown-reedsolomon-1.0.0/reedsolomon.go000066400000000000000000000014301521051216400227530ustar00rootroot00000000000000// Package reedsolomon ... // ref to doc: https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders#Polynomial_division // ref to project: github.com/skip2/go-qrcode/reedsolomon package reedsolomon import ( "github.com/yeqown/reedsolomon/binary" ) type word byte // 8bit as a word // Encode ... func Encode(bin *binary.Binary, numECWords int) *binary.Binary { if bin.Len()%8 != 0 { panic("could not deal with binary times 8bits") } // generate polynomial generator := rsGenPoly(numECWords) // poly div remainder := polyDiv(bin.Bytes(), generator) // append error correction stream bout := bin.Copy() bout.AppendBytes(remainder...) return bout } // Decode ... // TODO: finish this ~ func Decode(bin *binary.Binary, numECWords int) *binary.Binary { return nil } golang-github-yeqown-reedsolomon-1.0.0/reedsolomon_test.go000066400000000000000000000031601521051216400240140ustar00rootroot00000000000000// Package reedsolomon ... // ref to doc: http://www.drdobbs.com/testing/error-correction-with-reed-solomon/240157266 // ref to project: github.com/skip2/go-qrcode/reedsolomon package reedsolomon import ( "reflect" "testing" "github.com/yeqown/reedsolomon/binary" ) // func TestEncode(t *testing.T) { // /* 10 error correction // x10 + α251x9 + α67x8 + α46x7 + α61x6 + α118x5 + α70x4+ α64x3 + α94x2 + α32x + α45 // */ // bin := binary.New() // bin.AppendBytes([]byte{ // 0x40, 0xd2, 0x75, 0x47, 0x76, 0x17, 0x32, 0x06, // 0x27, 0x26, 0x96, 0xc6, 0xc6, 0x96, 0x70, 0xec}...) // t.Logf("bin: %v\n", bin.Bytes()) // bout := Encode(bin, 10) // // want remainder: 0xbc 0x2a 0x90 0x13 0x6b 0xaf 0xef 0xfd 0x4b 0xe0 // t.Logf("bout %v\n", bout.Bytes()) // } func TestEncode(t *testing.T) { type args struct { bin *binary.Binary numECWords int data []byte } tests := []struct { name string args args want *binary.Binary wantData []byte }{ { name: "case 0", args: args{ bin: binary.New(), numECWords: 10, data: []byte{32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236}, }, want: binary.New(), wantData: []byte{87, 86, 68, 17, 99, 235, 189, 232, 98, 195}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.args.bin.AppendBytes(tt.args.data...) tt.want.AppendBytes(tt.args.data...) tt.want.AppendBytes(tt.wantData...) if got := Encode(tt.args.bin, tt.args.numECWords); !reflect.DeepEqual(got, tt.want) { t.Errorf("Encode() = %3v, want %3v", got.Bytes(), tt.want.Bytes()) } }) } }