Decoding Linear Codes over Chain Rings Given by Parity Check Matrices
Abstract
:1. Introduction
2. Preliminaries
3. Decoding via Parity Check
3.1. First Step: Computing
3.2. Second Step: Computing
3.3. General Step: Computing
Algorithm 1: Syndrome decoding. |
|
0 | 1 | a | ||
0 | ||||
0 | 3 |
0 | 1 | a | ||
0 | ||||
0 |
4. Parity Check and Encoders
Algorithm 2: Smith normal form for finite chain rings. |
|
Algorithm 3: Generating matrix computation from a parity check matrix. |
|
Author Contributions
Funding
Institutional Review Board Statement
Informed Consent Statement
Data Availability Statement
Conflicts of Interest
Appendix A. Decoding via Encoders
Appendix B. SageMath Code
- p,nu,r␣=␣2,3,2
- #p,nu,r␣=␣2,5,1
- #p,nu,r␣=␣3,3,1
- if␣r␣==␣1:
- ␣␣␣␣F␣=␣GF(p)
- ␣␣␣␣R␣=␣IntegerModRing(p^nu)
- else:
- ␣␣␣␣F.<a>␣=␣GF(p^r)
- ␣␣␣␣R.<a>␣=␣IntegerModRing(p^nu).extension(F.modulus())
- #␣p,nu,r␣=␣2,3,2
- splitting_structure␣=␣[[R(0),R(5*a+4),R(3*a+7),R(4*a+3)],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(3*a+6),R(1*a+5),R(2*a+7)],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(5*a+6),R(5*a+1),R(6*a+1)]]␣+␣[p]
- #␣p,nu,r␣=␣2,5,1
- #splitting_structure␣=␣[[R(0),R(7)],
- #␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(5)],
- #␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(3)],
- #␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(1)],
- #␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(3)]]␣+␣[p]
- #␣p,nu,r␣=␣3,3,1
- #splitting_structure␣=␣[[R(0),R(7),R(8)],
- #␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(25),R(17)],
- #␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣[R(0),R(19),R(11)]]␣+␣[p]
- mm␣=␣splitting_structure[nu]
- def␣proj(rr):
- ␣␣␣␣if␣r␣==␣1:
- ␣␣␣␣␣␣␣␣return(F(rr))
- ␣␣␣␣else:
- ␣␣␣␣␣␣␣␣return␣F(rr.list())
- def␣splitting(ff,splitting_list␣=␣[R(ele)␣for␣ele␣in␣F.list()]):
- ␣␣␣␣if␣ff.parent()␣==␣F:
- ␣␣␣␣␣␣␣␣if␣(len(splitting_list)␣!=
- ␣␣␣␣␣␣␣␣␣␣␣␣F.cardinality())␣or␣([proj(r_)
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣r_␣in␣splitting_list]␣!=
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣F.list()):
- ␣␣␣␣␣␣␣␣␣␣␣␣return␣’Incorrect␣splitting’
- ␣␣␣␣␣␣␣␣return␣splitting_list[F.list().index(ff)]
- ␣␣␣␣elif␣isinstance(ff,sage.modules.free_module_element.FreeModuleElement):
- ␣␣␣␣␣␣␣␣ff_␣=␣ff.list()
- ␣␣␣␣␣␣␣␣aux␣=␣[splitting(ele,␣splitting_list)␣for␣ele␣in␣ff_]
- ␣␣␣␣␣␣␣␣output␣=␣vector(R,aux)
- ␣␣␣␣␣␣␣␣return␣output
- ␣␣␣␣elif␣isinstance(ff,sage.matrix.matrix0.Matrix):
- ␣␣␣␣␣␣␣␣n_rows␣=␣ff.nrows()
- ␣␣␣␣␣␣␣␣ff_␣=␣ff.list()
- ␣␣␣␣␣␣␣␣aux␣=␣[splitting(ele,␣splitting_list)␣for␣ele␣in␣ff_]
- ␣␣␣␣␣␣␣␣output␣=␣matrix(R,n_rows,aux)
- ␣␣␣␣␣␣␣␣return␣output
- ␣␣␣␣else:
- ␣␣␣␣␣␣␣␣return␣’Type␣non␣supported’
- def␣m_adic(rr,splitting_structure):
- ␣␣␣␣mm_␣=␣splitting_structure[nu]
- ␣␣␣␣if␣rr.parent()␣==␣R:
- ␣␣␣␣␣␣␣␣rr_␣=␣rr
- ␣␣␣␣␣␣␣␣output␣=␣[]
- ␣␣␣␣␣␣␣␣for␣ii␣in␣range(nu):
- ␣␣␣␣␣␣␣␣␣␣␣␣if␣r␣==␣1:
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣output␣+=␣[proj(R(ZZ(rr_)//mm^ii))]
- ␣␣␣␣␣␣␣␣␣␣␣␣else:
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣output␣+=␣[proj(R([ZZ(ele)//mm_^ii
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ele␣in␣(rr_).list()]))]
- ␣␣␣␣␣␣␣␣␣␣␣␣rr_␣=␣rr_␣-␣mm_^ii*splitting(output[-1],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[ii])
- ␣␣␣␣␣␣␣␣return␣output
- ␣␣␣␣elif␣isinstance(rr,
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣sage.modules.free_module_element.FreeModuleElement):
- ␣␣␣␣␣␣␣␣rr_␣=␣rr.list()
- ␣␣␣␣␣␣␣␣aux␣=␣[m_adic(ele,␣splitting_structure)␣for␣ele␣in␣rr_]
- ␣␣␣␣␣␣␣␣output␣=␣[vector(F,[aux[jj][ii]
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣jj␣in␣range(len(rr_))])
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ii␣in␣range(nu)]
- ␣␣␣␣␣␣␣␣return␣output
- ␣␣␣␣elif␣isinstance(rr,
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣sage.matrix.matrix0.Matrix):
- ␣␣␣␣␣␣␣␣n_rows␣=␣rr.nrows()
- ␣␣␣␣␣␣␣␣rr_␣=␣rr.list()
- ␣␣␣␣␣␣␣␣aux␣=␣[m_adic(ele,␣splitting_structure)␣for␣ele␣in␣rr_]
- ␣␣␣␣␣␣␣␣output␣=␣[matrix(F,n_rows,[aux[jj][ii]
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣jj␣in␣range(len(rr_))])
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ii␣in␣range(nu)]
- ␣␣␣␣␣␣␣␣return␣output
- ␣␣␣␣else:
- ␣␣␣␣␣␣␣␣return␣’Type␣non␣supported’
- def␣inv_m_adic(rr,splitting_structure):
- ␣␣␣␣mm_␣=␣splitting_structure[nu]
- ␣␣␣␣return␣sum(splitting(rr[ii],splitting_structure[ii])*mm_^ii
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ii␣in␣range(nu))
- from␣sage.rings.finite_rings.hom_finite_field␣import␣FiniteFieldHomomorphism_generic
- def␣GoppaCodeConstructor(n_,t_,F_):
- ␣␣␣␣m_␣=␣ceil(n_.log(F_.cardinality()))
- ␣␣␣␣k_␣=␣n␣-␣2*m_*t_
- ␣␣␣␣L_␣=␣GF(F_.cardinality()^m_)
- ␣␣␣␣embFL_␣=␣FiniteFieldHomomorphism_generic(Hom(F_,L_))
- ␣␣␣␣secLF_␣=␣embFL_.section()
- ␣␣␣␣V_,␣from_V_,␣to_V_␣=␣L_.vector_space(embFL_,␣map=True)
- ␣␣␣␣R_.<x>␣=␣PolynomialRing(L_)
- ␣␣␣␣tg␣=␣cputime()
- ␣␣␣␣print(’Starting␣generation’)
- ␣␣␣␣tt␣=␣cputime()
- ␣␣␣␣g_␣=␣R_(x^(2*t_))␣+␣R_.random_element(2*t_-1)
- ␣␣␣␣while␣not(g_.is_irreducible()):
- ␣␣␣␣␣␣␣␣g_␣=␣R_(x^(2*t_))␣+␣R_.random_element(2*t_-1)
- ␣␣␣␣print(’Goppa␣polynomial’,cputime(tt))
- ␣␣␣␣#␣Goppa␣points
- ␣␣␣␣tt␣=␣cputime()
- ␣␣␣␣pts_␣=␣[]
- ␣␣␣␣aux␣=␣L_.list()
- ␣␣␣␣for␣ii␣in␣range(n_):
- ␣␣␣␣␣␣␣␣ind␣=␣ZZ.random_element(len(aux))
- ␣␣␣␣␣␣␣␣pts_␣+=␣[aux[ind]]
- ␣␣␣␣␣␣␣␣aux.remove(aux[ind])
- ␣␣␣␣print(’Points’,cputime(tt))
- ␣␣␣␣tt␣=␣cputime()
- ␣␣␣␣Htilde␣=␣matrix.vandermonde(pts_).transpose()[0:2*t_]
- ␣␣␣␣Htilde␣*=␣diagonal_matrix([g_(ele)^(-1)␣for␣ele␣in␣pts_])
- ␣␣␣␣print(cputime(tt))
- ␣␣␣␣tt␣=␣cputime()
- ␣␣␣␣aux␣=␣[]
- ␣␣␣␣for␣cc␣in␣range(Htilde.nrows()):
- ␣␣␣␣␣␣␣␣aux2␣=␣Htilde[cc]
- ␣␣␣␣␣␣␣␣aux3␣=␣[]
- ␣␣␣␣␣␣␣␣for␣ele␣in␣aux2:
- ␣␣␣␣␣␣␣␣␣␣␣␣aux3␣+=␣[to_V_(ele).list()]
- ␣␣␣␣␣␣␣␣aux␣+=␣(matrix(aux3).transpose()).list()
- ␣␣␣␣Hhat␣=␣matrix(F_,len(aux)/n_,aux).rref()
- ␣␣␣␣Paux␣=␣random_matrix(F,n_-k_)
- ␣␣␣␣while␣Paux.is_singular()␣==␣True:
- ␣␣␣␣␣␣␣␣Paux␣=␣random_matrix(F,n_-k_)
- ␣␣␣␣H_␣=␣Hhat.transpose()*Paux
- ␣␣␣␣print(’Parity␣check␣matrix’,␣cputime(tt))
- ␣␣␣␣print(’Generation␣success’,␣cputime(tg))
- ␣␣␣␣return␣H_,[L_,␣g_,␣pts_,␣embFL_,␣secLF_]
- def␣GoppaCodeDecoder(received_,GoppaDecodingData_):
- ␣␣␣␣L_␣=␣GoppaDecodingData_[0]
- ␣␣␣␣g_␣=␣GoppaDecodingData_[1]
- ␣␣␣␣pts_␣=␣GoppaDecodingData_[2]
- ␣␣␣␣t_␣=␣floor(g_.degree()/2)
- ␣␣␣␣R_.<x>␣=␣PolynomialRing(L_)
- ␣␣␣␣synd_poly␣=␣sum(received_[ii]*R_(x␣-␣pts_[ii]).inverse_mod(g_)
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ii␣in␣range(len(received_)))
- ␣␣␣␣remainders␣=␣[g_,synd_poly]
- ␣␣␣␣coefs␣=␣[R_(0),R_(1)]
- ␣␣␣␣while␣remainders[-1].degree()␣>=␣t_:
- ␣␣␣␣␣␣␣␣cociente,resto␣=␣remainders[-2].quo_rem(remainders[-1])
- ␣␣␣␣␣␣␣␣remainders␣+=␣[resto]
- ␣␣␣␣␣␣␣␣coefs␣+=␣[coefs[-2]␣-␣coefs[-1]*cociente]
- ␣␣␣␣locator␣=␣coefs[-1]
- ␣␣␣␣evaluator␣=␣remainders[-1]
- ␣␣␣␣error_␣=␣[]
- ␣␣␣␣for␣ii␣in␣range(len(pts_)):
- ␣␣␣␣␣␣␣␣root_␣=␣pts_[ii]
- ␣␣␣␣␣␣␣␣if␣locator(root_)␣==␣0:
- ␣␣␣␣␣␣␣␣␣␣␣␣error_␣+=␣[evaluator(root_)/locator.derivative()(root_)]
- ␣␣␣␣␣␣␣␣else:
- ␣␣␣␣␣␣␣␣␣␣␣␣error_␣+=␣[L_(0)]
- ␣␣␣␣return␣vector(error_)
- length,␣correction_capability␣=␣60,␣3
- #length,␣correction_capability␣=␣256,␣7
- #length,␣correction_capability␣=␣20,␣2
- n,t␣=␣length,␣correction_capability
- Decoding_info␣=␣[]
- blocks␣=␣[]
- for␣ii␣in␣range(nu):
- ␣␣␣␣parity_check,decoding_data␣=␣GoppaCodeConstructor(n,t,F)
- ␣␣␣␣blocks␣+=␣[mm^ii*splitting(parity_check,
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[ii])
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣+␣sum(mm^jj*splitting(random_matrix(F,
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣parity_check.nrows(),
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣parity_check.ncols()),
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[jj])
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣jj␣in␣range(ii+1,nu))]
- ␣␣␣␣Decoding_info␣+=␣[decoding_data]
- H␣=␣block_matrix(1,blocks)
- error␣=␣zero_vector(R,n)
- for␣ll␣in␣range(nu):
- ␣␣␣␣xi␣=␣zero_vector(F,n)
- ␣␣␣␣while␣xi.hamming_weight()␣<␣t:
- ␣␣␣␣␣␣␣␣xi␣=␣xi.list()
- ␣␣␣␣␣␣␣␣jj␣=␣floor(n*random())
- ␣␣␣␣␣␣␣␣xi[jj]␣=␣F.random_element()
- ␣␣␣␣␣␣␣␣xi␣=␣vector(xi)
- ␣␣␣␣error␣+=␣splitting(xi,
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[ll])*mm^ll
- received␣=␣error
- error,␣error.hamming_weight()
- syndrome␣=␣[received*H.subdivision(0,ii)␣for␣ii␣in␣range(nu)]
- sigma␣=␣[m_adic(ele,splitting_structure)␣for␣ele␣in␣syndrome]
- Theta␣=␣[m_adic(H.subdivision(0,ii),
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure)␣for␣ii␣in␣range(nu)]
- xi␣=␣[]
- for␣ii␣in␣range(nu):
- ␣␣␣␣delta␣=␣m_adic(
- ␣␣␣␣␣␣␣␣sum(splitting(sigma[nu-1-ii][jj],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[jj])*mm^jj
- ␣␣␣␣␣␣␣␣␣␣␣␣for␣jj␣in␣range(nu-1-ii,nu))
- ␣␣␣␣␣␣␣␣-␣sum(sum(splitting(xi[ll],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[ll])*
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting(Theta[nu-1-ii][jj-ll],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[jj-ll])*mm^jj
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ll␣in␣range(jj-nu+ii+2))
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣jj␣in␣range(nu-1-ii,nu-1))
- ␣␣␣␣␣␣␣␣-␣sum(splitting(xi[ll],␣splitting_structure[ll])*
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting(Theta[nu-1-ii][nu-1-ll],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣splitting_structure[nu-1-ll])*mm^(nu-1)
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ll␣in␣range(ii)),␣splitting_structure)[nu-1]
- ␣␣␣␣rec_aux␣=␣Theta[nu-1-ii][nu-1-ii].solve_left(delta)
- ␣␣␣␣error_L␣=␣GoppaCodeDecoder([Decoding_info[nu-1-ii][3](ele)
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ele␣in␣rec_aux],
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣Decoding_info[nu-1-ii])
- ␣␣␣␣xi␣+=␣[vector([Decoding_info[nu-1-ii][4](ele)
- ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for␣ele␣in␣error_L.list()])]
- computed_error␣=␣inv_m_adic(xi,␣splitting_structure)
References
- Hammons, A.R.; Kumar, P.V.; Calderbank, A.R.; Sloane, N.J.; Sole, P. The ℤ4-linearity of kerdock, preparata, goethals, and related codes. IEEE Trans. Inf. Theory 1994, 40, 301–319. [Google Scholar] [CrossRef]
- Wood, J.A. Duality for modules over finite rings and applications to coding theory. Am. J. Math. 1999, 121, 555–575. [Google Scholar] [CrossRef] [Green Version]
- Gómez-Torrecillas, J.; Hieta-Aho, E.; Lobillo, F.J.; López-Permouth, S.; Navarro, G. Some remarks on non projective Frobenius algebras and linear codes. Des. Codes Cryptogr. 2020, 88, 1–15. [Google Scholar] [CrossRef] [Green Version]
- Feng, C.; Nóbrega, R.W.; Kschischang, F.R.; Silva, D. Communication over finite-ring matrix channels. In Proceedings of the 2013 IEEE International Symposium on Information Theory, Istanbul, Turkey, 7–12 July 2013; pp. 2890–2894. [Google Scholar]
- Feng, C.; Nóbrega, R.W.; Kschischang, F.R.; Silva, D. Communication over finite-chain-ring matrix channels. IEEE Trans. Inf. Theory 2014, 60, 5899–5917. [Google Scholar] [CrossRef] [Green Version]
- Babu, N.S.; Zimmermann, K.-H. Decoding of linear codes over Galois rings. IEEE Trans. Inf. Theory 2001, 47, 1599–1603. [Google Scholar] [CrossRef]
- Greferath, M.; Vellbinger, U. Efficient decoding of ℤpk-linear codes. IEEE Trans. Inf. Theory 1998, 44, 1288–1291. [Google Scholar] [CrossRef]
- Dinh, H.Q.; Lopez-Permouth, S.R. Cyclic and negacyclic codes over finite chain rings. IEEE Trans. Inf. Theory 2004, 50, 1728–1744. [Google Scholar] [CrossRef]
- McDonald, B.R. Finite Rings with Identity; Marcel Dekker: New York, NY, USA, 1974. [Google Scholar]
- Albrecht, M.R.; Bernstein, D.J.; Chou, T.; Cid, C.; Gilcher, J.; Lange, T.; Maram, V.; von Maurich, I.; Misoczki, R.; Niederhagen, R.; et al. Classic McEliece: Conservative Code-Based Cryptography; Technical Report; NIST’s Post-Quantum Cryptography Standardization Project: Gaithersburg, MD, USA, 2020. [Google Scholar]
- Brown, W.C. Matrices over Commutative Rings; Number 169 in Monographs and Textbooks in Pure and Applied Mathematics; Marcel Dekker, Inc.: New York, NY, USA, 1993. [Google Scholar]
- The Sage Developers. SageMath, the Sage Mathematics Software System (Version 9.1). 2020. Available online: https://www.sagemath.org (accessed on 6 August 2021).
Publisher’s Note: MDPI stays neutral with regard to jurisdictional claims in published maps and institutional affiliations. |
© 2021 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https://creativecommons.org/licenses/by/4.0/).
Share and Cite
Gómez-Torrecillas, J.; Lobillo, F.J.; Navarro, G. Decoding Linear Codes over Chain Rings Given by Parity Check Matrices. Mathematics 2021, 9, 1878. https://doi.org/10.3390/math9161878
Gómez-Torrecillas J, Lobillo FJ, Navarro G. Decoding Linear Codes over Chain Rings Given by Parity Check Matrices. Mathematics. 2021; 9(16):1878. https://doi.org/10.3390/math9161878
Chicago/Turabian StyleGómez-Torrecillas, José, F. J. Lobillo, and Gabriel Navarro. 2021. "Decoding Linear Codes over Chain Rings Given by Parity Check Matrices" Mathematics 9, no. 16: 1878. https://doi.org/10.3390/math9161878