168 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			168 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | #ifndef CORRECT_REED_SOLOMON_FIELD
 | ||
|  | #define CORRECT_REED_SOLOMON_FIELD
 | ||
|  | #include "rs_common.h"
 | ||
|  | 
 | ||
|  | /*
 | ||
|  | field_t field_create(field_operation_t primitive_poly); | ||
|  | void field_destroy(field_t field); | ||
|  | field_element_t field_add(field_t field, field_element_t l, field_element_t r); | ||
|  | field_element_t field_sub(field_t field, field_element_t l, field_element_t r); | ||
|  | field_element_t field_sum(field_t field, field_element_t elem, uint16_t n); | ||
|  | field_element_t field_mul(field_t field, field_element_t l, field_element_t r); | ||
|  | field_element_t field_div(field_t field, field_element_t l, field_element_t r); | ||
|  | field_logarithm_t field_mul_log(field_t field, field_logarithm_t l, field_logarithm_t r); | ||
|  | field_logarithm_t field_div_log(field_t field, field_logarithm_t l, field_logarithm_t r); | ||
|  | field_element_t field_mul_log_element(field_t field, field_logarithm_t l, field_logarithm_t r); | ||
|  | field_element_t field_pow(field_t field, field_element_t elem, int pow); | ||
|  | */ | ||
|  | 
 | ||
|  | static inline field_element_t field_mul_log_element(field_t field, field_logarithm_t l, field_logarithm_t r) { | ||
|  |     // like field_mul_log, but returns a field_element_t
 | ||
|  |     // because we are doing lookup here, we can safely skip the wrapover check
 | ||
|  |     field_operation_t res = (field_operation_t)l + (field_operation_t)r; | ||
|  |     return field.exp[res]; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_t field_create(field_operation_t primitive_poly) { | ||
|  |     // in GF(2^8)
 | ||
|  |     // log and exp
 | ||
|  |     // bits are in GF(2), compute alpha^val in GF(2^8)
 | ||
|  |     // exp should be of size 512 so that it can hold a "wraparound" which prevents some modulo ops
 | ||
|  |     // log should be of size 256. no wraparound here, the indices into this table are field elements
 | ||
|  |     field_element_t *exp = os_mem_malloc(IOT_WQ_VTB_MID, 512 * sizeof(field_element_t)); | ||
|  |     field_logarithm_t *log = os_mem_malloc(IOT_WQ_VTB_MID, 256 * sizeof(field_logarithm_t)); | ||
|  | 
 | ||
|  |     // assume alpha is a primitive element, p(x) (primitive_poly) irreducible in GF(2^8)
 | ||
|  |     // addition is xor
 | ||
|  |     // subtraction is addition (also xor)
 | ||
|  |     // e.g. x^5 + x^4 + x^4 + x^2 + 1 = x^5 + x^2 + 1
 | ||
|  |     // each row of exp contains the field element found by exponentiating
 | ||
|  |     //   alpha by the row index
 | ||
|  |     // each row of log contains the coefficients of
 | ||
|  |     //   alpha^7 + alpha^6 + alpha^5 + alpha^4 + alpha^3 + alpha^2 + alpha + 1
 | ||
|  |     // as 8 bits packed into one byte
 | ||
|  | 
 | ||
|  |     field_operation_t element = 1; | ||
|  |     exp[0] = (field_element_t)element; | ||
|  |     log[0] = (field_logarithm_t)0;  // really, it's undefined. we shouldn't ever access this
 | ||
|  |     for (field_operation_t i = 1; i < 512; i++) { | ||
|  |         element = element * 2; | ||
|  |         element = (element > 255) ? (element ^ primitive_poly) : element; | ||
|  |         exp[i] = (field_element_t)element; | ||
|  |         if (i < 256) { | ||
|  |             log[element] = (field_logarithm_t)i; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     field_t field; | ||
|  |     *(field_element_t **)&field.exp = exp; | ||
|  |     *(field_logarithm_t **)&field.log = log; | ||
|  | 
 | ||
|  |     return field; | ||
|  | } | ||
|  | 
 | ||
|  | static inline void field_destroy(field_t field) { | ||
|  |     os_mem_free(*(field_element_t **)&field.exp); | ||
|  |     os_mem_free(*(field_element_t **)&field.log); | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_element_t field_add(field_t field, field_element_t l, field_element_t r) { | ||
|  |     return l ^ r; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_element_t field_sub(field_t field, field_element_t l, field_element_t r) { | ||
|  |     return l ^ r; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_element_t field_sum(field_t field, field_element_t elem, uint16_t n) { | ||
|  |     // we'll do a closed-form expression of the sum, although we could also
 | ||
|  |     //   choose to call field_add n times
 | ||
|  | 
 | ||
|  |     // since the sum is actually the bytewise XOR operator, this suggests two
 | ||
|  |     // kinds of values: n odd, and n even
 | ||
|  | 
 | ||
|  |     // if you sum once, you have coeff
 | ||
|  |     // if you sum twice, you have coeff XOR coeff = 0
 | ||
|  |     // if you sum thrice, you are back at coeff
 | ||
|  |     // an even number of XORs puts you at 0
 | ||
|  |     // an odd number of XORs puts you back at your value
 | ||
|  | 
 | ||
|  |     // so, just throw away all the even n
 | ||
|  |     return (n % 2) ? elem : 0; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_element_t field_mul(field_t field, field_element_t l, field_element_t r) { | ||
|  |     if (l == 0 || r == 0) { | ||
|  |         return 0; | ||
|  |     } | ||
|  |     // multiply two field elements by adding their logarithms.
 | ||
|  |     // yep, get your slide rules out
 | ||
|  |     field_operation_t res = (field_operation_t)field.log[l] + (field_operation_t)field.log[r]; | ||
|  | 
 | ||
|  |     // if coeff exceeds 255, we would normally have to wrap it back around
 | ||
|  |     // alpha^255 = 1; alpha^256 = alpha^255 * alpha^1 = alpha^1
 | ||
|  |     // however, we've constructed exponentiation table so that
 | ||
|  |     //   we can just directly lookup this result
 | ||
|  |     // the result must be clamped to [0, 511]
 | ||
|  |     // the greatest we can see at this step is alpha^255 * alpha^255
 | ||
|  |     //   = alpha^510
 | ||
|  |     return field.exp[res]; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_element_t field_div(field_t field, field_element_t l, field_element_t r) { | ||
|  |     if (l == 0) { | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (r == 0) { | ||
|  |         // XXX ???
 | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     // division as subtraction of logarithms
 | ||
|  | 
 | ||
|  |     // if rcoeff is larger, then log[l] - log[r] wraps under
 | ||
|  |     // so, instead, always add 255. in some cases, we'll wrap over, but
 | ||
|  |     // that's ok because the exp table runs up to 511.
 | ||
|  |     field_operation_t res = (field_operation_t)255 + (field_operation_t)field.log[l] - (field_operation_t)field.log[r]; | ||
|  |     return field.exp[res]; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_logarithm_t field_mul_log(field_t field, field_logarithm_t l, field_logarithm_t r) { | ||
|  |     // this function performs the equivalent of field_mul on two logarithms
 | ||
|  |     // we save a little time by skipping the lookup step at the beginning
 | ||
|  |     field_operation_t res = (field_operation_t)l + (field_operation_t)r; | ||
|  | 
 | ||
|  |     // because we arent using the table, the value we return must be a valid logarithm
 | ||
|  |     // which we have decided must live in [0, 255] (they are 8-bit values)
 | ||
|  |     // ensuring this makes it so that multiple muls will not reach past the end of the
 | ||
|  |     // exp table whenever we finally convert back to an element
 | ||
|  |     if (res > 255) { | ||
|  |         return (field_logarithm_t)(res - 255); | ||
|  |     } | ||
|  |     return (field_logarithm_t)res; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_logarithm_t field_div_log(field_t field, field_logarithm_t l, field_logarithm_t r) { | ||
|  |     // like field_mul_log, this performs field_div without going through a field_element_t
 | ||
|  |     field_operation_t res = (field_operation_t)255 + (field_operation_t)l - (field_operation_t)r; | ||
|  |     if (res > 255) { | ||
|  |         return (field_logarithm_t)(res - 255); | ||
|  |     } | ||
|  |     return (field_logarithm_t)res; | ||
|  | } | ||
|  | 
 | ||
|  | static inline field_element_t field_pow(field_t field, field_element_t elem, int pow) { | ||
|  |     // take the logarithm, multiply, and then "exponentiate"
 | ||
|  |     // n.b. the exp table only considers powers of alpha, the primitive element
 | ||
|  |     // but here we have an arbitrary coeff
 | ||
|  |     field_logarithm_t log = field.log[elem]; | ||
|  |     int res_log = log * pow; | ||
|  |     int mod = res_log % 255; | ||
|  |     if (mod < 0) { | ||
|  |         mod += 255; | ||
|  |     } | ||
|  |     return field.exp[mod]; | ||
|  | } | ||
|  | #endif
 |