rs.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. Reed-Solomon Codes over GF(2^8)
  3. Primitive Polynomial: x^8+x^4+x^3+x^2+1
  4. Galois Filed arithmetic using Intel SIMD instructions (AVX2 or SSSE3)
  5. */
  6. package reedsolomon
  7. import "errors"
  8. // Encoder implements for Reed-Solomon Encoding/Reconstructing
  9. type Encoder interface {
  10. // Encode multiply generator-matrix with data
  11. // len(vects) must be equal with num of data+parity
  12. Encode(vects [][]byte) error
  13. // Result of reconst will be put into origin position of vects
  14. // it means if you lost vects[0], after reconst the vects[0]'s data will be back in vects[0]
  15. // Reconstruct repair lost data & parity
  16. // Set vect nil if lost
  17. Reconstruct(vects [][]byte) error
  18. // Reconstruct repair lost data
  19. // Set vect nil if lost
  20. ReconstructData(vects [][]byte) error
  21. // ReconstWithPos repair lost data&parity with has&lost vects position
  22. // Save bandwidth&disk I/O (cmp with Reconstruct, if the lost is less than num of parity)
  23. // As erasure codes, we must know which vect is broken,
  24. // so it's necessary to provide such APIs
  25. // len(has) must equal num of data vects
  26. // Example:
  27. // in 3+2, the whole position: [0,1,2,3,4]
  28. // if lost vects[0]
  29. // the "has" could be [1,2,3] or [1,2,4] or ...
  30. // then you must be sure that vects[1] vects[2] vects[3] have correct data (if the "has" is [1,2,3])
  31. // the "dLost" will be [0]
  32. // ps:
  33. // 1. the above lists are in increasing orders TODO support out-of-order
  34. // 2. each vect has same len, don't set it nil
  35. // so we don't need to make slice
  36. ReconstWithPos(vects [][]byte, has, dLost, pLost []int) error
  37. //// ReconstWithPos repair lost data with survived&lost vects position
  38. //// Don't need to append position of parity lost into "lost"
  39. ReconstDataWithPos(vects [][]byte, has, dLost []int) error
  40. }
  41. func checkCfg(d, p int) error {
  42. if (d <= 0) || (p <= 0) {
  43. return errors.New("rs.New: data or parity <= 0")
  44. }
  45. if d+p >= 256 {
  46. return errors.New("rs.New: data+parity >= 256")
  47. }
  48. return nil
  49. }
  50. // New create an Encoder (vandermonde matrix as Encoding matrix)
  51. func New(data, parity int) (enc Encoder, err error) {
  52. err = checkCfg(data, parity)
  53. if err != nil {
  54. return
  55. }
  56. e, err := genEncMatrixVand(data, parity)
  57. if err != nil {
  58. return
  59. }
  60. return newRS(data, parity, e), nil
  61. }
  62. // NewCauchy create an Encoder (cauchy matrix as Generator Matrix)
  63. func NewCauchy(data, parity int) (enc Encoder, err error) {
  64. err = checkCfg(data, parity)
  65. if err != nil {
  66. return
  67. }
  68. e := genEncMatrixCauchy(data, parity)
  69. return newRS(data, parity, e), nil
  70. }
  71. type encBase struct {
  72. data int
  73. parity int
  74. encode []byte
  75. gen []byte
  76. }
  77. func checkEnc(d, p int, vs [][]byte) (size int, err error) {
  78. total := len(vs)
  79. if d+p != total {
  80. err = errors.New("rs.checkER: vects not match rs args")
  81. return
  82. }
  83. size = len(vs[0])
  84. if size == 0 {
  85. err = errors.New("rs.checkER: vects size = 0")
  86. return
  87. }
  88. for i := 1; i < total; i++ {
  89. if len(vs[i]) != size {
  90. err = errors.New("rs.checkER: vects size mismatch")
  91. return
  92. }
  93. }
  94. return
  95. }
  96. func (e *encBase) Encode(vects [][]byte) (err error) {
  97. d := e.data
  98. p := e.parity
  99. _, err = checkEnc(d, p, vects)
  100. if err != nil {
  101. return
  102. }
  103. dv := vects[:d]
  104. pv := vects[d:]
  105. g := e.gen
  106. for i := 0; i < d; i++ {
  107. for j := 0; j < p; j++ {
  108. if i != 0 {
  109. mulVectAdd(g[j*d+i], dv[i], pv[j])
  110. } else {
  111. mulVect(g[j*d], dv[0], pv[j])
  112. }
  113. }
  114. }
  115. return
  116. }
  117. func mulVect(c byte, a, b []byte) {
  118. t := mulTbl[c]
  119. for i := 0; i < len(a); i++ {
  120. b[i] = t[a[i]]
  121. }
  122. }
  123. func mulVectAdd(c byte, a, b []byte) {
  124. t := mulTbl[c]
  125. for i := 0; i < len(a); i++ {
  126. b[i] ^= t[a[i]]
  127. }
  128. }
  129. func (e *encBase) Reconstruct(vects [][]byte) (err error) {
  130. return e.reconstruct(vects, false)
  131. }
  132. func (e *encBase) ReconstructData(vects [][]byte) (err error) {
  133. return e.reconstruct(vects, true)
  134. }
  135. func (e *encBase) ReconstWithPos(vects [][]byte, has, dLost, pLost []int) error {
  136. return e.reconstWithPos(vects, has, dLost, pLost, false)
  137. }
  138. func (e *encBase) ReconstDataWithPos(vects [][]byte, has, dLost []int) error {
  139. return e.reconstWithPos(vects, has, dLost, nil, true)
  140. }
  141. func (e *encBase) reconst(vects [][]byte, has, dLost, pLost []int, dataOnly bool) (err error) {
  142. d := e.data
  143. em := e.encode
  144. dCnt := len(dLost)
  145. size := len(vects[has[0]])
  146. if dCnt != 0 {
  147. vtmp := make([][]byte, d+dCnt)
  148. for i, p := range has {
  149. vtmp[i] = vects[p]
  150. }
  151. for i, p := range dLost {
  152. if len(vects[p]) == 0 {
  153. vects[p] = make([]byte, size)
  154. }
  155. vtmp[i+d] = vects[p]
  156. }
  157. matrixbuf := make([]byte, 4*d*d+dCnt*d)
  158. m := matrixbuf[:d*d]
  159. for i, l := range has {
  160. copy(m[i*d:i*d+d], em[l*d:l*d+d])
  161. }
  162. raw := matrixbuf[d*d : 3*d*d]
  163. im := matrixbuf[3*d*d : 4*d*d]
  164. err2 := matrix(m).invert(raw, d, im)
  165. if err2 != nil {
  166. return err2
  167. }
  168. g := matrixbuf[4*d*d:]
  169. for i, l := range dLost {
  170. copy(g[i*d:i*d+d], im[l*d:l*d+d])
  171. }
  172. etmp := &encBase{data: d, parity: dCnt, gen: g}
  173. err2 = etmp.Encode(vtmp[:d+dCnt])
  174. if err2 != nil {
  175. return err2
  176. }
  177. }
  178. if dataOnly {
  179. return
  180. }
  181. pCnt := len(pLost)
  182. if pCnt != 0 {
  183. vtmp := make([][]byte, d+pCnt)
  184. g := make([]byte, pCnt*d)
  185. for i, l := range pLost {
  186. copy(g[i*d:i*d+d], em[l*d:l*d+d])
  187. }
  188. for i := 0; i < d; i++ {
  189. vtmp[i] = vects[i]
  190. }
  191. for i, p := range pLost {
  192. if len(vects[p]) == 0 {
  193. vects[p] = make([]byte, size)
  194. }
  195. vtmp[i+d] = vects[p]
  196. }
  197. etmp := &encBase{data: d, parity: pCnt, gen: g}
  198. err2 := etmp.Encode(vtmp[:d+pCnt])
  199. if err2 != nil {
  200. return err2
  201. }
  202. }
  203. return
  204. }
  205. func (e *encBase) reconstWithPos(vects [][]byte, has, dLost, pLost []int, dataOnly bool) (err error) {
  206. d := e.data
  207. p := e.parity
  208. // TODO check more, maybe element in has show in lost & deal with len(has) > d
  209. if len(has) != d {
  210. return errors.New("rs.Reconst: not enough vects")
  211. }
  212. dCnt := len(dLost)
  213. if dCnt > p {
  214. return errors.New("rs.Reconst: not enough vects")
  215. }
  216. pCnt := len(pLost)
  217. if pCnt > p {
  218. return errors.New("rs.Reconst: not enough vects")
  219. }
  220. return e.reconst(vects, has, dLost, pLost, dataOnly)
  221. }
  222. func (e *encBase) reconstruct(vects [][]byte, dataOnly bool) (err error) {
  223. d := e.data
  224. p := e.parity
  225. t := d + p
  226. listBuf := make([]int, t+p)
  227. has := listBuf[:d]
  228. dLost := listBuf[d:t]
  229. pLost := listBuf[t : t+p]
  230. hasCnt, dCnt, pCnt := 0, 0, 0
  231. for i := 0; i < t; i++ {
  232. if vects[i] != nil {
  233. if hasCnt < d {
  234. has[hasCnt] = i
  235. hasCnt++
  236. }
  237. } else {
  238. if i < d {
  239. if dCnt < p {
  240. dLost[dCnt] = i
  241. dCnt++
  242. } else {
  243. return errors.New("rs.Reconst: not enough vects")
  244. }
  245. } else {
  246. if pCnt < p {
  247. pLost[pCnt] = i
  248. pCnt++
  249. } else {
  250. return errors.New("rs.Reconst: not enough vects")
  251. }
  252. }
  253. }
  254. }
  255. if hasCnt != d {
  256. return errors.New("rs.Reconst: not enough vects")
  257. }
  258. dLost = dLost[:dCnt]
  259. pLost = pLost[:pCnt]
  260. return e.reconst(vects, has, dLost, pLost, dataOnly)
  261. }