cfx_addr/
utils.rs

1// Copyright 2021 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4//
5// Modification based on https://github.com/hlb8122/rust-bitcoincash-addr in MIT License.
6// A copy of the original license is included in LICENSE.rust-bitcoincash-addr.
7
8use crate::types::DecodingError;
9#[cfg(not(feature = "std"))]
10use alloc::vec::Vec;
11
12// The polymod function is used to calculate the checksum of the address.
13pub fn polymod(v: &[u8]) -> u64 {
14    let mut c = 1;
15    for d in v {
16        let c0 = (c >> 35) as u8;
17        c = ((c & 0x07ffffffff) << 5) ^ u64::from(*d);
18        if c0 & 0x01 != 0 {
19            c ^= 0x98f2bc8e61;
20        }
21        if c0 & 0x02 != 0 {
22            c ^= 0x79b76d99e2;
23        }
24        if c0 & 0x04 != 0 {
25            c ^= 0xf33e5fb3c4;
26        }
27        if c0 & 0x08 != 0 {
28            c ^= 0xae2eabe2a8;
29        }
30        if c0 & 0x10 != 0 {
31            c ^= 0x1e4f43e470;
32        }
33    }
34    c ^ 1
35}
36
37/// The checksum calculation includes the lower 5 bits of each character of the
38/// prefix.
39/// - e.g. "bit..." becomes 2,9,20,...
40// Expand the address prefix for the checksum operation.
41pub fn expand_prefix(prefix: &str) -> Vec<u8> {
42    let mut ret: Vec<u8> = prefix.chars().map(|c| (c as u8) & 0x1f).collect();
43    ret.push(0);
44    ret
45}
46
47// This method assume that data is valid string of inbits.
48// When pad is true, any remaining bits are padded and encoded into a new byte;
49// when pad is false, any remaining bits are checked to be zero and discarded.
50pub fn convert_bits(
51    data: &[u8], inbits: u8, outbits: u8, pad: bool,
52) -> Result<Vec<u8>, DecodingError> {
53    assert!(inbits <= 8 && outbits <= 8);
54    let num_bytes = (data.len() * inbits as usize + outbits as usize - 1)
55        / outbits as usize;
56    let mut ret = Vec::with_capacity(num_bytes);
57    let mut acc: u16 = 0; // accumulator of bits
58    let mut num: u8 = 0; // num bits in acc
59    let groupmask = (1 << outbits) - 1;
60    for d in data.iter() {
61        // We push each input chunk into a 16-bit accumulator
62        acc = (acc << inbits) | u16::from(*d);
63        num += inbits;
64        // Then we extract all the output groups we can
65        while num >= outbits {
66            // Store only the highest outbits.
67            ret.push((acc >> (num - outbits)) as u8);
68            // Clear the highest outbits.
69            acc &= !(groupmask << (num - outbits));
70            num -= outbits;
71        }
72    }
73    if pad {
74        // If there's some bits left, pad and add it
75        if num > 0 {
76            ret.push((acc << (outbits - num)) as u8);
77        }
78    } else {
79        // FIXME: add unit tests for it.
80        // If there's some bits left, figure out if we need to remove padding
81        // and add it
82        let padding = ((data.len() * inbits as usize) % outbits as usize) as u8;
83        if num >= inbits || acc != 0 {
84            return Err(DecodingError::InvalidPadding {
85                from_bits: inbits,
86                padding_bits: padding,
87                padding: acc,
88            });
89        }
90    }
91    Ok(ret)
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    #[cfg(not(feature = "std"))]
98    extern crate alloc;
99    #[cfg(not(feature = "std"))]
100    use alloc::vec;
101
102    #[test]
103    fn test_expand_prefix() {
104        assert_eq!(expand_prefix("cfx"), vec![0x03, 0x06, 0x18, 0x00]);
105
106        assert_eq!(
107            expand_prefix("cfxtest"),
108            vec![0x03, 0x06, 0x18, 0x14, 0x05, 0x13, 0x14, 0x00]
109        );
110
111        assert_eq!(
112            expand_prefix("net17"),
113            vec![0x0e, 0x05, 0x14, 0x11, 0x17, 0x00]
114        );
115    }
116
117    #[test]
118    fn test_convert_bits() {
119        // 00000000 --> 0, 0, 0, 0, 0, 0, 0, 0
120        assert_eq!(convert_bits(&[0], 8, 1, false), Ok(vec![0; 8]));
121
122        // 00000000 --> 000, 000, 00_
123        assert_eq!(convert_bits(&[0], 8, 3, false), Ok(vec![0, 0])); // 00_ is dropped
124        assert_eq!(convert_bits(&[0], 8, 3, true), Ok(vec![0, 0, 0])); // 00_ becomes 000
125
126        // 00000001 --> 000, 000, 01_
127        assert!(convert_bits(&[1], 8, 3, false).is_err()); // 01_ != 0 (ignored incomplete chunk must be 0)
128        assert_eq!(convert_bits(&[1], 8, 3, true), Ok(vec![0, 0, 2])); // 01_ becomes 010
129
130        // 00000001 --> 0000000, 1______
131        assert_eq!(convert_bits(&[1], 8, 7, true), Ok(vec![0, 64])); // 1______ becomes 1000000
132
133        // 0, 0, 0, 0, 0, 0, 0, 0 --> 00000000
134        assert_eq!(convert_bits(&[0; 8], 1, 8, false), Ok(vec![0]));
135
136        // 000, 000, 010 -> 00000001, 0_______
137        assert_eq!(convert_bits(&[0, 0, 2], 3, 8, false), Ok(vec![1])); // 0_______ is dropped
138        assert_eq!(convert_bits(&[0, 0, 2], 3, 8, true), Ok(vec![1, 0])); // 0_______ becomes 00000000
139
140        // 000, 000, 011 -> 00000001, 1_______
141        assert!(convert_bits(&[0, 0, 3], 3, 8, false).is_err()); // 1_______ != 0 (ignored incomplete chunk must be 0)
142
143        // 00000000, 00000001, 00000010, 00000011, 00000100 -->
144        // 00000, 00000, 00000, 10000, 00100, 00000, 11000, 00100
145        assert_eq!(
146            convert_bits(&[0, 1, 2, 3, 4], 8, 5, false),
147            Ok(vec![0, 0, 0, 16, 4, 0, 24, 4])
148        );
149
150        // 00000000, 00000001, 00000010 -->
151        // 00000, 00000, 00000, 10000, 0010_
152        assert!(convert_bits(&[0, 1, 2], 8, 5, false).is_err()); // 0010_ != 0 (ignored incomplete chunk must be 0)
153
154        assert_eq!(
155            convert_bits(&[0, 1, 2], 8, 5, true),
156            Ok(vec![0, 0, 0, 16, 4])
157        ); // 0010_ becomes 00100
158
159        // 00000, 00000, 00000, 10000, 00100, 00000, 11000, 00100 -->
160        // 00000000, 00000001, 00000010, 00000011, 00000100
161        assert_eq!(
162            convert_bits(&[0, 0, 0, 16, 4, 0, 24, 4], 5, 8, false),
163            Ok(vec![0, 1, 2, 3, 4])
164        );
165
166        // 00000, 00000, 00000, 10000, 00100 -->
167        // 00000000, 00000001, 00000010, 0_______
168        assert_eq!(
169            convert_bits(&[0, 0, 0, 16, 4], 5, 8, false),
170            Ok(vec![0, 1, 2])
171        ); // 0_______ is dropped
172
173        assert_eq!(
174            convert_bits(&[0, 0, 0, 16, 4], 5, 8, true),
175            Ok(vec![0, 1, 2, 0])
176        ); // 0_______ becomes 00000000
177    }
178}