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).div_ceil(outbits as usize);
55    let mut ret = Vec::with_capacity(num_bytes);
56    let mut acc: u16 = 0; // accumulator of bits
57    let mut num: u8 = 0; // num bits in acc
58    let groupmask = (1 << outbits) - 1;
59    for d in data.iter() {
60        // We push each input chunk into a 16-bit accumulator
61        acc = (acc << inbits) | u16::from(*d);
62        num += inbits;
63        // Then we extract all the output groups we can
64        while num >= outbits {
65            // Store only the highest outbits.
66            ret.push((acc >> (num - outbits)) as u8);
67            // Clear the highest outbits.
68            acc &= !(groupmask << (num - outbits));
69            num -= outbits;
70        }
71    }
72    if pad {
73        // If there's some bits left, pad and add it
74        if num > 0 {
75            ret.push((acc << (outbits - num)) as u8);
76        }
77    } else {
78        // FIXME: add unit tests for it.
79        // If there's some bits left, figure out if we need to remove padding
80        // and add it
81        let padding = ((data.len() * inbits as usize) % outbits as usize) as u8;
82        if num >= inbits || acc != 0 {
83            return Err(DecodingError::InvalidPadding {
84                from_bits: inbits,
85                padding_bits: padding,
86                padding: acc,
87            });
88        }
89    }
90    Ok(ret)
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    #[cfg(not(feature = "std"))]
97    extern crate alloc;
98    #[cfg(not(feature = "std"))]
99    use alloc::vec;
100
101    #[test]
102    fn test_expand_prefix() {
103        assert_eq!(expand_prefix("cfx"), vec![0x03, 0x06, 0x18, 0x00]);
104
105        assert_eq!(
106            expand_prefix("cfxtest"),
107            vec![0x03, 0x06, 0x18, 0x14, 0x05, 0x13, 0x14, 0x00]
108        );
109
110        assert_eq!(
111            expand_prefix("net17"),
112            vec![0x0e, 0x05, 0x14, 0x11, 0x17, 0x00]
113        );
114    }
115
116    #[test]
117    fn test_convert_bits() {
118        // 00000000 --> 0, 0, 0, 0, 0, 0, 0, 0
119        assert_eq!(convert_bits(&[0], 8, 1, false), Ok(vec![0; 8]));
120
121        // 00000000 --> 000, 000, 00_
122        assert_eq!(convert_bits(&[0], 8, 3, false), Ok(vec![0, 0])); // 00_ is dropped
123        assert_eq!(convert_bits(&[0], 8, 3, true), Ok(vec![0, 0, 0])); // 00_ becomes 000
124
125        // 00000001 --> 000, 000, 01_
126        assert!(convert_bits(&[1], 8, 3, false).is_err()); // 01_ != 0 (ignored incomplete chunk must be 0)
127        assert_eq!(convert_bits(&[1], 8, 3, true), Ok(vec![0, 0, 2])); // 01_ becomes 010
128
129        // 00000001 --> 0000000, 1______
130        assert_eq!(convert_bits(&[1], 8, 7, true), Ok(vec![0, 64])); // 1______ becomes 1000000
131
132        // 0, 0, 0, 0, 0, 0, 0, 0 --> 00000000
133        assert_eq!(convert_bits(&[0; 8], 1, 8, false), Ok(vec![0]));
134
135        // 000, 000, 010 -> 00000001, 0_______
136        assert_eq!(convert_bits(&[0, 0, 2], 3, 8, false), Ok(vec![1])); // 0_______ is dropped
137        assert_eq!(convert_bits(&[0, 0, 2], 3, 8, true), Ok(vec![1, 0])); // 0_______ becomes 00000000
138
139        // 000, 000, 011 -> 00000001, 1_______
140        assert!(convert_bits(&[0, 0, 3], 3, 8, false).is_err()); // 1_______ != 0 (ignored incomplete chunk must be 0)
141
142        // 00000000, 00000001, 00000010, 00000011, 00000100 -->
143        // 00000, 00000, 00000, 10000, 00100, 00000, 11000, 00100
144        assert_eq!(
145            convert_bits(&[0, 1, 2, 3, 4], 8, 5, false),
146            Ok(vec![0, 0, 0, 16, 4, 0, 24, 4])
147        );
148
149        // 00000000, 00000001, 00000010 -->
150        // 00000, 00000, 00000, 10000, 0010_
151        assert!(convert_bits(&[0, 1, 2], 8, 5, false).is_err()); // 0010_ != 0 (ignored incomplete chunk must be 0)
152
153        assert_eq!(
154            convert_bits(&[0, 1, 2], 8, 5, true),
155            Ok(vec![0, 0, 0, 16, 4])
156        ); // 0010_ becomes 00100
157
158        // 00000, 00000, 00000, 10000, 00100, 00000, 11000, 00100 -->
159        // 00000000, 00000001, 00000010, 00000011, 00000100
160        assert_eq!(
161            convert_bits(&[0, 0, 0, 16, 4, 0, 24, 4], 5, 8, false),
162            Ok(vec![0, 1, 2, 3, 4])
163        );
164
165        // 00000, 00000, 00000, 10000, 00100 -->
166        // 00000000, 00000001, 00000010, 0_______
167        assert_eq!(
168            convert_bits(&[0, 0, 0, 16, 4], 5, 8, false),
169            Ok(vec![0, 1, 2])
170        ); // 0_______ is dropped
171
172        assert_eq!(
173            convert_bits(&[0, 0, 0, 16, 4], 5, 8, true),
174            Ok(vec![0, 1, 2, 0])
175        ); // 0_______ becomes 00000000
176    }
177}