-
Notifications
You must be signed in to change notification settings - Fork 87
Expand file tree
/
Copy pathchecksum.rs
More file actions
114 lines (92 loc) · 2.7 KB
/
checksum.rs
File metadata and controls
114 lines (92 loc) · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use zeroize::Zeroize;
use self::polymod::Polymod;
use super::Error;
/// Size of checksum in bytes
pub const CHECKSUM_SIZE: usize = 6;
/// Checksum value used to verify data integrity
pub(crate) struct Checksum([u8; CHECKSUM_SIZE]);
impl Checksum {
/// Create a checksum for the given human-readable part (hrp) and binary data
pub fn new(hrp: &[u8], data: &[u8]) -> Self {
let mut p = Polymod::compute(hrp, data);
let mut checksum = [0u8; CHECKSUM_SIZE];
p.input_slice(&checksum);
let value = p.finish() ^ 1;
for (i, byte) in checksum.iter_mut().enumerate().take(CHECKSUM_SIZE) {
*byte = ((value >> (5 * (5 - i))) & 0x1f) as u8;
}
Checksum(checksum)
}
/// Verify this checksum matches the given human-readable part (hrp) and binary data
pub fn verify(hrp: &[u8], data: &[u8]) -> Result<(), Error> {
if Polymod::compute(hrp, data).finish() == 1 {
Ok(())
} else {
Err(Error::ChecksumInvalid)
}
}
}
impl AsRef<[u8]> for Checksum {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Drop for Checksum {
fn drop(&mut self) {
self.0.as_mut().zeroize()
}
}
mod polymod {
/// bech32 generator coefficients
const COEFFICIENTS: [u32; 5] = [
0x3b6a_57b2,
0x2650_8e6d,
0x1ea1_19fa,
0x3d42_33dd,
0x2a14_62b3,
];
/// Perform polynomial calculation against the given generator coefficients
pub(crate) struct Polymod(u32);
impl Default for Polymod {
fn default() -> Polymod {
Polymod(1)
}
}
impl Polymod {
pub fn compute(hrp: &[u8], data: &[u8]) -> Self {
let mut p = Polymod::default();
for b in hrp {
p.input_byte(*b >> 5);
}
p.input_byte(0);
for b in hrp {
p.input_byte(*b & 0x1f);
}
p.input_slice(data);
p
}
pub fn input_slice(&mut self, slice: &[u8]) {
for b in slice {
self.input_byte(*b)
}
}
pub fn input_byte(&mut self, byte: u8) {
let b = (self.0 >> 25) as u8;
self.0 = ((self.0 & 0x1ff_ffff) << 5) ^ u32::from(byte);
for (i, c) in COEFFICIENTS.iter().enumerate() {
if (b >> i) & 1 == 1 {
self.0 ^= *c
}
}
}
pub fn finish(self) -> u32 {
self.0
}
}
impl Drop for Polymod {
fn drop(&mut self) {
// TODO: secure zeroize (integers not yet supported by `zeroize` crate)
self.0 = 0;
}
}
}