@@ -76,7 +76,11 @@ pub trait CorrectableError {
7676 return None ;
7777 }
7878
79- self . residue_error ( ) . map ( |e| Corrector { residue : e. residue ( ) , phantom : PhantomData } )
79+ self . residue_error ( ) . map ( |e| Corrector {
80+ erasures : FieldVec :: new ( ) ,
81+ residue : e. residue ( ) ,
82+ phantom : PhantomData ,
83+ } )
8084 }
8185}
8286
@@ -127,12 +131,40 @@ impl CorrectableError for DecodeError {
127131}
128132
129133/// An error-correction context.
130- pub struct Corrector < Ck > {
134+ pub struct Corrector < Ck : Checksum > {
135+ erasures : FieldVec < usize > ,
131136 residue : Polynomial < Fe32 > ,
132137 phantom : PhantomData < Ck > ,
133138}
134139
135140impl < Ck : Checksum > Corrector < Ck > {
141+ /// A bound on the number of errors and erasures (errors with known location)
142+ /// can be corrected by this corrector.
143+ ///
144+ /// Returns N such that, given E errors and X erasures, corection is possible
145+ /// iff 2E + X <= N.
146+ pub fn singleton_bound ( & self ) -> usize {
147+ // d - 1, where d = [number of consecutive roots] + 2
148+ Ck :: ROOT_EXPONENTS . end ( ) - Ck :: ROOT_EXPONENTS . start ( ) + 1
149+ }
150+
151+ /// TODO
152+ pub fn add_erasures ( & mut self , locs : & [ usize ] ) {
153+ for loc in locs {
154+ // If the user tries to add too many erasures, just ignore them. In
155+ // this case error correction is guaranteed to fail anyway, because
156+ // they will have exceeded the singleton bound. (Otherwise, the
157+ // singleton bound, which is always <= the checksum length, must be
158+ // greater than NO_ALLOC_MAX_LENGTH. So the checksum length must be
159+ // greater than NO_ALLOC_MAX_LENGTH. Then correction will still fail.)
160+ #[ cfg( not( feature = "alloc" ) ) ]
161+ if self . erasures . len ( ) == NO_ALLOC_MAX_LENGTH {
162+ break ;
163+ }
164+ self . erasures . push ( * loc) ;
165+ }
166+ }
167+
136168 /// Returns an iterator over the errors in the string.
137169 ///
138170 /// Returns `None` if it can be determined that there are too many errors to be
@@ -145,29 +177,44 @@ impl<Ck: Checksum> Corrector<Ck> {
145177 /// string may not actually be the intended string.
146178 pub fn bch_errors ( & self ) -> Option < ErrorIterator < Ck > > {
147179 // 1. Compute all syndromes by evaluating the residue at each power of the generator.
148- let syndromes: FieldVec < _ > = Ck :: ROOT_GENERATOR
180+ let syndromes: Polynomial < _ > = Ck :: ROOT_GENERATOR
149181 . powers_range ( Ck :: ROOT_EXPONENTS )
150182 . map ( |rt| self . residue . evaluate ( & rt) )
151183 . collect ( ) ;
152184
185+ // 1a. Compute the "Forney syndrome polynomial" which is the product of the syndrome
186+ // polynomial and the erasure locator. This "erases the erasures" so that B-M
187+ // can find only the errors.
188+ let mut erasure_locator = Polynomial :: with_monic_leading_term ( & [ ] ) ; // 1
189+ for loc in & self . erasures {
190+ let factor: Polynomial < _ > =
191+ [ Ck :: CorrectionField :: ONE , -Ck :: ROOT_GENERATOR . powi ( * loc as i64 ) ]
192+ . iter ( )
193+ . cloned ( )
194+ . collect ( ) ; // alpha^-ix - 1
195+ erasure_locator = erasure_locator. mul_mod_x_d ( & factor, usize:: MAX ) ;
196+ }
197+ let forney_syndromes = erasure_locator. convolution ( & syndromes) ;
198+
153199 // 2. Use the Berlekamp-Massey algorithm to find the connection polynomial of the
154200 // LFSR that generates these syndromes. For magical reasons this will be equal
155201 // to the error locator polynomial for the syndrome.
156- let lfsr = LfsrIter :: berlekamp_massey ( & syndromes [ ..] ) ;
202+ let lfsr = LfsrIter :: berlekamp_massey ( & forney_syndromes . as_inner ( ) [ ..] ) ;
157203 let conn = lfsr. coefficient_polynomial ( ) ;
158204
159205 // 3. The connection polynomial is the error locator polynomial. Use this to get
160206 // the errors.
161- let max_correctable_errors =
162- ( Ck :: ROOT_EXPONENTS . end ( ) - Ck :: ROOT_EXPONENTS . start ( ) + 1 ) / 2 ;
163- if conn. degree ( ) <= max_correctable_errors {
207+ if erasure_locator. degree ( ) + 2 * conn. degree ( ) <= self . singleton_bound ( ) {
208+ // 3a. Compute the "errata locator" which is the product of the error locator
209+ // and the erasure locator. Note that while we used the Forney syndromes
210+ // when calling the BM algorithm, in all other cases we use the ordinary
211+ // unmodified syndromes.
212+ let errata_locator = conn. mul_mod_x_d ( & erasure_locator, usize:: MAX ) ;
164213 Some ( ErrorIterator {
165- evaluator : conn. mul_mod_x_d (
166- & Polynomial :: from ( syndromes) ,
167- Ck :: ROOT_EXPONENTS . end ( ) - Ck :: ROOT_EXPONENTS . start ( ) + 1 ,
168- ) ,
169- locator_derivative : conn. formal_derivative ( ) ,
170- inner : conn. find_nonzero_distinct_roots ( Ck :: ROOT_GENERATOR ) ,
214+ evaluator : errata_locator. mul_mod_x_d ( & syndromes, self . singleton_bound ( ) ) ,
215+ locator_derivative : errata_locator. formal_derivative ( ) ,
216+ erasures : & self . erasures [ ..] ,
217+ errors : conn. find_nonzero_distinct_roots ( Ck :: ROOT_GENERATOR ) ,
171218 a : Ck :: ROOT_GENERATOR ,
172219 c : * Ck :: ROOT_EXPONENTS . start ( ) ,
173220 } )
@@ -206,32 +253,39 @@ impl<Ck: Checksum> Corrector<Ck> {
206253/// caller should fix this before attempting error correction. If it is unknown,
207254/// the caller cannot assume anything about the intended checksum, and should not
208255/// attempt error correction.
209- pub struct ErrorIterator < Ck : Checksum > {
256+ pub struct ErrorIterator < ' c , Ck : Checksum > {
210257 evaluator : Polynomial < Ck :: CorrectionField > ,
211258 locator_derivative : Polynomial < Ck :: CorrectionField > ,
212- inner : super :: polynomial:: RootIter < Ck :: CorrectionField > ,
259+ erasures : & ' c [ usize ] ,
260+ errors : super :: polynomial:: RootIter < Ck :: CorrectionField > ,
213261 a : Ck :: CorrectionField ,
214262 c : usize ,
215263}
216264
217- impl < Ck : Checksum > Iterator for ErrorIterator < Ck > {
265+ impl < ' c , Ck : Checksum > Iterator for ErrorIterator < ' c , Ck > {
218266 type Item = ( usize , Fe32 ) ;
219267
220268 fn next ( & mut self ) -> Option < Self :: Item > {
221269 // Compute -i, which is the location we will return to the user.
222- let neg_i = match self . inner . next ( ) {
223- None => return None ,
224- Some ( 0 ) => 0 ,
225- Some ( x) => Ck :: ROOT_GENERATOR . multiplicative_order ( ) - x,
270+ let neg_i = if self . erasures . is_empty ( ) {
271+ match self . errors . next ( ) {
272+ None => return None ,
273+ Some ( 0 ) => 0 ,
274+ Some ( x) => Ck :: ROOT_GENERATOR . multiplicative_order ( ) - x,
275+ }
276+ } else {
277+ let pop = self . erasures [ 0 ] ;
278+ self . erasures = & self . erasures [ 1 ..] ;
279+ pop
226280 } ;
227281
228282 // Forney's equation, as described in https://en.wikipedia.org/wiki/BCH_code#Forney_algorithm
229283 //
230284 // It is rendered as
231285 //
232- // a^i evaluator(a^-i)
233- // e_k = - ---------------------------------
234- // a^(ci ) locator_derivative(a^-i)
286+ // evaluator(a^-i)
287+ // e_k = - -----------------------------------------
288+ // (a^i)^(c - 1) ) locator_derivative(a^-i)
235289 //
236290 // where here a is `Ck::ROOT_GENERATOR`, c is the first element of the range
237291 // `Ck::ROOT_EXPONENTS`, and both evalutor and locator_derivative are polynomials
@@ -240,8 +294,8 @@ impl<Ck: Checksum> Iterator for ErrorIterator<Ck> {
240294 let a_i = self . a . powi ( neg_i as i64 ) ;
241295 let a_neg_i = a_i. clone ( ) . multiplicative_inverse ( ) ;
242296
243- let num = self . evaluator . evaluate ( & a_neg_i) * & a_i ;
244- let den = a_i. powi ( self . c as i64 ) * self . locator_derivative . evaluate ( & a_neg_i) ;
297+ let num = self . evaluator . evaluate ( & a_neg_i) ;
298+ let den = a_i. powi ( self . c as i64 - 1 ) * self . locator_derivative . evaluate ( & a_neg_i) ;
245299 let ret = -num / den;
246300 match ret. try_into ( ) {
247301 Ok ( ret) => Some ( ( neg_i, ret) ) ,
@@ -263,9 +317,13 @@ mod tests {
263317 match SegwitHrpstring :: new ( s) {
264318 Ok ( _) => panic ! ( "{} successfully, and wrongly, parsed" , s) ,
265319 Err ( e) => {
266- let ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
320+ let mut ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
267321 let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
322+ assert_eq ! ( iter. next( ) , Some ( ( 0 , Fe32 :: X ) ) ) ;
323+ assert_eq ! ( iter. next( ) , None ) ;
268324
325+ ctx. add_erasures ( & [ 0 ] ) ;
326+ let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
269327 assert_eq ! ( iter. next( ) , Some ( ( 0 , Fe32 :: X ) ) ) ;
270328 assert_eq ! ( iter. next( ) , None ) ;
271329 }
@@ -276,9 +334,13 @@ mod tests {
276334 match SegwitHrpstring :: new ( s) {
277335 Ok ( _) => panic ! ( "{} successfully, and wrongly, parsed" , s) ,
278336 Err ( e) => {
279- let ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
337+ let mut ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
280338 let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
339+ assert_eq ! ( iter. next( ) , Some ( ( 6 , Fe32 :: T ) ) ) ;
340+ assert_eq ! ( iter. next( ) , None ) ;
281341
342+ ctx. add_erasures ( & [ 6 ] ) ;
343+ let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
282344 assert_eq ! ( iter. next( ) , Some ( ( 6 , Fe32 :: T ) ) ) ;
283345 assert_eq ! ( iter. next( ) , None ) ;
284346 }
@@ -297,13 +359,42 @@ mod tests {
297359 }
298360 }
299361
300- // Two errors.
301- let s = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mxx " ;
362+ // Two errors; cannot correct .
363+ let s = "bc1qar0srrr7xfkvy5l64qlydnw9re59gtzzwf5mdx " ;
302364 match SegwitHrpstring :: new ( s) {
303365 Ok ( _) => panic ! ( "{} successfully, and wrongly, parsed" , s) ,
304366 Err ( e) => {
305- let ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
367+ let mut ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
306368 assert ! ( ctx. bch_errors( ) . is_none( ) ) ;
369+
370+ // But we can correct it if we inform where an error is.
371+ ctx. add_erasures ( & [ 0 ] ) ;
372+ let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
373+ assert_eq ! ( iter. next( ) , Some ( ( 0 , Fe32 :: X ) ) ) ;
374+ assert_eq ! ( iter. next( ) , Some ( ( 20 , Fe32 :: _3) ) ) ;
375+ assert_eq ! ( iter. next( ) , None ) ;
376+
377+ ctx. add_erasures ( & [ 20 ] ) ;
378+ let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
379+ assert_eq ! ( iter. next( ) , Some ( ( 0 , Fe32 :: X ) ) ) ;
380+ assert_eq ! ( iter. next( ) , Some ( ( 20 , Fe32 :: _3) ) ) ;
381+ assert_eq ! ( iter. next( ) , None ) ;
382+ }
383+ }
384+
385+ // In fact, if we know the locations, we can correct up to 3 errors.
386+ let s = "bc1q9r0srrr7xfkvy5l64qlydnw9re59gtzzwf5mdx" ;
387+ match SegwitHrpstring :: new ( s) {
388+ Ok ( _) => panic ! ( "{} successfully, and wrongly, parsed" , s) ,
389+ Err ( e) => {
390+ let mut ctx = e. correction_context :: < Bech32 > ( ) . unwrap ( ) ;
391+ ctx. add_erasures ( & [ 37 , 0 , 20 ] ) ;
392+ let mut iter = ctx. bch_errors ( ) . unwrap ( ) ;
393+
394+ assert_eq ! ( iter. next( ) , Some ( ( 37 , Fe32 :: C ) ) ) ;
395+ assert_eq ! ( iter. next( ) , Some ( ( 0 , Fe32 :: X ) ) ) ;
396+ assert_eq ! ( iter. next( ) , Some ( ( 20 , Fe32 :: _3) ) ) ;
397+ assert_eq ! ( iter. next( ) , None ) ;
307398 }
308399 }
309400 }
0 commit comments