1pub const GEN_REGULAR: [u128; 5] = [
8 0x19dc500ce73fde210,
9 0x1bfae00def77fe529,
10 0x1fbd920fffe7bee52,
11 0x1739640bdeee3fdad,
12 0x07729a039cfc75f5a,
13];
14
15pub const MD_REGULAR_CONST: u128 = 0x0815c07747a3392e7;
18
19const POLYMOD_INIT: u128 = 0x23181b3;
20const REGULAR_SHIFT: u32 = 60;
21const REGULAR_MASK: u128 = 0x0fffffffffffffff;
22
23fn polymod_step(residue: u128, value: u128) -> u128 {
24 let b = residue >> REGULAR_SHIFT;
25 let mut new_residue = ((residue & REGULAR_MASK) << 5) ^ value;
26 for (i, &g) in GEN_REGULAR.iter().enumerate() {
27 if (b >> i) & 1 != 0 {
28 new_residue ^= g;
29 }
30 }
31 new_residue
32}
33
34pub fn polymod_run(values: &[u8]) -> u128 {
41 let mut residue = POLYMOD_INIT;
42 for &v in values {
43 residue = polymod_step(residue, v as u128);
44 }
45 residue
46}
47
48pub fn hrp_expand(hrp: &str) -> Vec<u8> {
50 let bytes = hrp.as_bytes();
51 let mut out = Vec::with_capacity(bytes.len() * 2 + 1);
52 for &c in bytes {
53 out.push(c >> 5);
54 }
55 out.push(0);
56 for &c in bytes {
57 out.push(c & 31);
58 }
59 out
60}
61
62pub fn bch_create_checksum_regular(hrp: &str, data: &[u8]) -> [u8; 13] {
64 let mut input = hrp_expand(hrp);
65 input.extend_from_slice(data);
66 input.extend(std::iter::repeat_n(0, 13));
67 let polymod = polymod_run(&input) ^ MD_REGULAR_CONST;
68 let mut out = [0u8; 13];
69 for (i, slot) in out.iter_mut().enumerate() {
70 *slot = ((polymod >> (5 * (12 - i))) & 0x1F) as u8;
71 }
72 out
73}
74
75pub fn bch_verify_regular(hrp: &str, data_with_checksum: &[u8]) -> bool {
77 if data_with_checksum.len() < 13 {
78 return false;
79 }
80 let mut input = hrp_expand(hrp);
81 input.extend_from_slice(data_with_checksum);
82 polymod_run(&input) == MD_REGULAR_CONST
83}