reed_solomon_novelpoly/field/
inc_encode.rs

1#[inline(always)]
2pub fn encode_low(data: &[Additive], k: usize, codeword: &mut [Additive], n: usize) {
3	#[cfg(all(target_feature = "avx", feature = "avx"))]
4	if k >= 16 && k % 8 == 0 && n % 8 == 0 && (n - k) % 8 == 0 {
5		encode_low_faster8(data, k, codeword, n);
6	} else {
7		encode_low_plain(data, k, codeword, n);
8	}
9
10	#[cfg(not(all(target_feature = "avx", feature = "avx")))]
11	encode_low_plain(data, k, codeword, n);
12}
13
14// Encoding alg for k/n < 0.5: message is a power of two
15pub fn encode_low_plain(data: &[Additive], k: usize, codeword: &mut [Additive], n: usize) {
16	assert!(k + k <= n);
17	assert_eq!(codeword.len(), n);
18	assert_eq!(data.len(), n);
19
20	assert!(is_power_of_2(n));
21	assert!(is_power_of_2(k));
22
23	// k | n is guaranteed
24	assert_eq!((n / k) * k, n);
25
26	// move the data to the codeword
27	codeword.copy_from_slice(data);
28
29	// split after the first k
30	let (codeword_first_k, codeword_skip_first_k) = codeword.split_at_mut(k);
31
32	inverse_afft(codeword_first_k, k, 0);
33
34	// dbg!(&codeword_first_k);
35	// the first codeword is now the basis for the remaining transforms
36	// denoted `M_topdash`
37
38	for shift in (k..n).step_by(k) {
39		let codeword_at_shift = &mut codeword_skip_first_k[(shift - k)..shift];
40
41		// copy `M_topdash` to the position we are currently at, the n transform
42		codeword_at_shift.copy_from_slice(codeword_first_k);
43		afft(codeword_at_shift, k, shift);
44	}
45
46	// restore `M` from the derived ones
47	codeword[0..k].copy_from_slice(&data[0..k]);
48}
49
50#[cfg(all(target_feature = "avx", feature = "avx"))]
51pub fn encode_low_faster8(data: &[Additive], k: usize, codeword: &mut [Additive], n: usize) {
52	assert!(k + k <= n);
53	assert_eq!(codeword.len(), n);
54	assert_eq!(data.len(), n); // FIXME, we never read data beyond 0..k
55
56	assert!(is_power_of_2(n));
57	assert!(is_power_of_2(k));
58
59	assert_eq!(k % Additive8x::LANE, 0);
60	assert_eq!(n % Additive8x::LANE, 0);
61	assert_eq!((n - k) % Additive8x::LANE, 0);
62
63	// k | n is guaranteed
64	assert_eq!((n / k) * k, n);
65
66	// move the data to the codeword
67	codeword.copy_from_slice(data);
68
69	// split after the first k
70	let (codeword_first_k, codeword_skip_first_k) = codeword.split_at_mut(k);
71
72	assert!((k >> 1) >= Additive8x::LANE);
73	inverse_afft_faster8(codeword_first_k, k, 0);
74
75	// the first codeword is now the basis for the remaining transforms
76	// denoted `M_topdash`
77
78	for shift in (k..n).step_by(k) {
79		let codeword_at_shift = &mut codeword_skip_first_k[(shift - k)..shift];
80
81		// copy `M_topdash` to the position we are currently at, the n transform
82		codeword_at_shift.copy_from_slice(codeword_first_k);
83		afft_faster8(codeword_at_shift, k, shift);
84	}
85
86	// restore `M` from the derived ones
87
88	codeword[0..k].copy_from_slice(&data[0..k]);
89}
90
91//data: message array. parity: parity array. mem: buffer(size>= n-k)
92//Encoding alg for k/n>0.5: parity is a power of two.
93#[inline(always)]
94pub fn encode_high(data: &[Additive], k: usize, parity: &mut [Additive], mem: &mut [Additive], n: usize) {
95	#[cfg(all(target_feature = "avx", feature = "avx"))]
96	if (n - k) % Additive8x::LANE == 0 && n % Additive8x::LANE == 0 && k % Additive8x::LANE == 0 {
97		encode_high_faster8(data, k, parity, mem, n);
98	} else {
99		encode_high_plain(data, k, parity, mem, n);
100	}
101	#[cfg(not(target_feature = "avx"))]
102	encode_high_plain(data, k, parity, mem, n);
103}
104
105//data: message array. parity: parity array. mem: buffer(size>= n-k)
106//Encoding alg for k/n>0.5: parity is a power of two.
107pub fn encode_high_plain(data: &[Additive], k: usize, parity: &mut [Additive], mem: &mut [Additive], n: usize) {
108	assert!(is_power_of_2(n));
109
110	let t: usize = n - k;
111
112	// mem_zero(&mut parity[0..t]);
113	for i in 0..t {
114		parity[i] = Additive(0);
115	}
116
117	let mut i = t;
118	while i < n {
119		mem[..t].copy_from_slice(&data[(i - t)..t]);
120
121		inverse_afft(mem, t, i);
122		for j in 0..t {
123			parity[j] ^= mem[j];
124		}
125		i += t;
126	}
127	afft(parity, t, 0);
128}
129
130#[cfg(all(target_feature = "avx", feature = "avx"))]
131pub fn encode_high_faster8(data: &[Additive], k: usize, parity: &mut [Additive], mem: &mut [Additive], n: usize) {
132	let t: usize = n - k;
133	assert!(t >= 8);
134	assert_eq!(t % 8, 0);
135
136	for i in 0..t {
137		parity[i] = Additive::zero();
138	}
139
140	let mut i = t;
141	while i < n {
142		mem[..t].copy_from_slice(&data[(i - t)..t]);
143
144		inverse_afft_faster8(mem, t, i);
145		for j in 0..t {
146			parity[j] ^= mem[j];
147		}
148		i += t;
149	}
150	afft_faster8(parity, t, 0);
151}
152
153pub fn encode_sub(bytes: &[u8], n: usize, k: usize) -> Result<Vec<Additive>> {
154	#[cfg(all(target_feature = "avx", feature = "avx"))]
155	if (k % Additive8x::LANE) == 0 && (k >> 1) >= Additive8x::LANE {
156		encode_sub_faster8(bytes, n, k)
157	} else {
158		encode_sub_plain(bytes, n, k)
159	}
160	#[cfg(not(all(target_feature = "avx", feature = "avx")))]
161	encode_sub_plain(bytes, n, k)
162}
163
164/// Bytes shall only contain payload data
165pub fn encode_sub_plain(bytes: &[u8], n: usize, k: usize) -> Result<Vec<Additive>> {
166	assert!(is_power_of_2(n), "Algorithm only works for 2^i sizes for N");
167	assert!(is_power_of_2(k), "Algorithm only works for 2^i sizes for K");
168	assert!(bytes.len() <= k << 1);
169	assert!(k <= n / 2);
170
171	// must be power of 2
172	let bytes_len = bytes.len();
173	let upper_len = if is_power_of_2(bytes_len) {
174		bytes_len
175	} else {
176		let loglen = log2(bytes_len);
177		let upper_len = 1 << loglen;
178
179		if upper_len >= bytes_len {
180			upper_len
181		} else {
182			upper_len << 1
183		}
184	};
185	assert!(is_power_of_2(upper_len));
186	assert!(upper_len >= bytes_len);
187
188	// pad the incoming bytes with trailing 0s
189	// so we get a buffer of size `N` in `GF` symbols
190	let mut elm_data = vec![Additive(0); n];
191
192	for i in 0..((bytes_len + 1) / 2) {
193		elm_data[i] = Additive(Elt::from_be_bytes([
194			bytes.get(2 * i).copied().unwrap_or_default(),
195			bytes.get(2 * i + 1).copied().unwrap_or_default(),
196		]));
197	}
198
199	// update new data bytes with zero padded bytes
200	// `l` is now `GF(2^16)` symbols
201
202	let mut codeword = elm_data.clone();
203	assert_eq!(codeword.len(), n);
204
205	encode_low_plain(&elm_data[..], k, &mut codeword[..], n);
206
207	Ok(codeword)
208}
209
210/// Bytes shall only contain payload data
211#[cfg(all(target_feature = "avx", feature = "avx"))]
212pub fn encode_sub_faster8(bytes: &[u8], n: usize, k: usize) -> Result<Vec<Additive>> {
213	assert!(is_power_of_2(n), "Algorithm only works for 2^i sizes for N");
214	assert!(is_power_of_2(k), "Algorithm only works for 2^i sizes for K");
215	assert!(bytes.len() <= k << 1);
216	assert!(k <= n / 2);
217	assert_eq!(k % Additive8x::LANE, 0);
218	assert!((k >> 1) >= Additive8x::LANE);
219
220	// must be power of 2
221	let bytes_len = bytes.len();
222	let upper_len = if is_power_of_2(bytes_len) {
223		bytes_len
224	} else {
225		let loglen = log2(std::cmp::max(Additive8x::LANE, bytes_len));
226		let upper_len = 1 << loglen;
227
228		if upper_len >= bytes_len {
229			upper_len
230		} else {
231			upper_len << 1
232		}
233	};
234	assert!(is_power_of_2(upper_len));
235	assert!(upper_len >= bytes_len);
236
237	// pad the incoming bytes with trailing 0s
238	// so we get a buffer of size `N` in `GF` symbols
239	let mut elm_data = vec![Additive(0); n];
240
241	for i in 0..((bytes_len + 1) / 2) {
242		elm_data[i] = Additive(Elt::from_be_bytes([
243			bytes.get(2 * i).copied().unwrap_or_default(),
244			bytes.get(2 * i + 1).copied().unwrap_or_default(),
245		]));
246	}
247
248	// update new data bytes with zero padded bytes
249	// `l` is now `GF(2^16)` symbols
250	let elm_len = elm_data.len();
251	assert_eq!(elm_len, n);
252
253	let mut codeword = elm_data.clone();
254	encode_low_faster8(&elm_data[..], k, &mut codeword[..], n);
255
256	Ok(codeword)
257}
258
259#[cfg(all(target_feature = "avx", feature = "avx"))]
260#[cfg(test)]
261mod tests_plain_vs_faster8 {
262	use super::*;
263
264	#[test]
265	fn encode_low_output_plain_eq_faster8() {
266		// k must be larger, since the afft is only accelerated by lower values
267		let n: usize = 32;
268		let k: usize = 16;
269		let data1 = vec![Additive(0x1234); n];
270		let data2 = data1.clone();
271
272		let mut parity1 = vec![Additive::zero(); n];
273		encode_low_plain(&data1[..], k, &mut parity1[..], n);
274
275		let mut parity2 = vec![Additive::zero(); n];
276		encode_low_faster8(&data2[..], k, &mut parity2[..], n);
277
278		assert_eq!(parity1, parity2);
279	}
280
281	#[cfg(all(target_feature = "avx", feature = "avx"))]
282	#[test]
283	fn encode_sub_output_plain_eq_faster8() {
284		let n = 64;
285		let k = 32; // smallest supported size
286		let bytes = vec![0x2A_u8; 64];
287		let bytes = bytes.as_slice();
288		let fe_plain = encode_sub_plain(bytes, n, k).unwrap();
289		let fe_faster8: Vec<Additive> = encode_sub_faster8(bytes, n, k).unwrap();
290
291		assert_eq!(fe_plain, fe_faster8);
292	}
293}