darkfi_sdk/monotree/
bits.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 * Copyright (C) 2021 MONOLOG (Taeho Francis Lim and Jongwhan Lee) MIT License
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20use std::ops::Range;
21
22use super::{
23    utils::{bit, bytes_to_int, len_lcp, nbytes_across},
24    BitsLen,
25};
26use crate::GenericResult;
27
28/// An owned representation of a bit path, compatible with Bits serialization.
29/// Internally stores bits normalized to start at position 0.
30/// Tracks the original offset for correct serialization.
31#[derive(Debug, Clone, PartialEq)]
32pub struct BitsOwned {
33    /// Bits stored normalized (starting at bit 0, MSB-first)
34    path: Vec<u8>,
35    /// Number of valid bits
36    len: BitsLen,
37    /// Original starting bit position (for serialization)
38    offset: BitsLen,
39}
40
41impl BitsOwned {
42    /// Create empty `BitsOwned` with given length and offset
43    #[inline]
44    pub fn new(len: BitsLen, offset: BitsLen) -> Self {
45        let num_bytes = len.div_ceil(8) as usize;
46        Self { path: vec![0u8; num_bytes], len, offset }
47    }
48
49    /// Create from raw normalized bytes (bits start at position 0)
50    #[inline]
51    fn from_raw(path: Vec<u8>, len: BitsLen, offset: BitsLen) -> Self {
52        Self { path, len, offset }
53    }
54
55    #[inline]
56    pub fn len(&self) -> BitsLen {
57        self.len
58    }
59
60    #[inline]
61    pub fn is_empty(&self) -> bool {
62        self.len == 0
63    }
64
65    #[inline]
66    pub fn first(&self) -> bool {
67        debug_assert!(self.is_empty(), "cannot get first bit of empty BitsOwned");
68        self.path[0] & 0x80 != 0
69    }
70
71    /// Serialize to bytes in monotree format: `[start:2][end:2][path_bytes]`
72    /// Shifts bits to match the original offset position.
73    pub fn to_bytes(&self) -> GenericResult<Vec<u8>> {
74        let start = self.offset;
75        let end = self.offset + self.len;
76
77        let byte_start = (start / 8) as usize;
78        let byte_end = end.div_ceil(8) as usize;
79        let num_path_bytes = byte_end - byte_start;
80
81        let mut result = Vec::with_capacity(4 + num_path_bytes);
82        result.extend_from_slice(&start.to_be_bytes());
83        result.extend_from_slice(&end.to_be_bytes());
84
85        if num_path_bytes == 0 {
86            return Ok(result)
87        }
88
89        let bit_shift = (start % 8) as usize;
90
91        if bit_shift == 0 {
92            // Fast path: no shifting needed
93            result.extend_from_slice(&self.path[..num_path_bytes]);
94        } else {
95            // Shift bits right by bit_shift to align with offset
96            for i in 0..num_path_bytes {
97                let hi = if i == 0 { 0 } else { self.path.get(i - 1).copied().unwrap_or(0) };
98                let lo = self.path.get(i).copied().unwrap_or(0);
99                let byte = (hi << (8 - bit_shift)) | (lo >> bit_shift);
100                result.push(byte);
101            }
102        }
103
104        // Mask leading bits (before start)
105        let lead_mask = 0xFFu8 >> (start % 8) as u8;
106        result[4] &= lead_mask;
107
108        // Mask trailing bits (after end)
109        let trail = (end % 8) as u8;
110        if trail != 0 {
111            let trail_mask = 0xFFu8 << (8 - trail);
112            let last_idx = result.len() - 1;
113            result[last_idx] &= trail_mask;
114        }
115
116        Ok(result)
117    }
118}
119
120/// Extract bits from a `Bits` into a normalized `Vec<u8>` (starting at bit 0)
121#[inline]
122fn extract_normalized(bits: &Bits) -> Vec<u8> {
123    let len = bits.len();
124    if len == 0 {
125        return Vec::new();
126    }
127
128    let num_bytes = len.div_ceil(8) as usize;
129    let bit_offset = (bits.range.start % 8) as usize;
130    let byte_start = (bits.range.start / 8) as usize;
131    let byte_end = bits.range.end.div_ceil(8) as usize;
132    let src = &bits.path[byte_start..byte_end];
133
134    let mut result = vec![0u8; num_bytes];
135
136    if bit_offset == 0 {
137        // Fast path: already byte-aligned
138        result[..num_bytes.min(src.len())].copy_from_slice(&src[..num_bytes.min(src.len())]);
139    } else {
140        // Shift left by bit_offset to normalize
141        for (i, bit) in result.iter_mut().enumerate().take(num_bytes) {
142            let hi = src.get(i).copied().unwrap_or(0);
143            let lo = src.get(i + 1).copied().unwrap_or(0);
144            *bit = (hi << bit_offset) | (lo >> (8 - bit_offset));
145        }
146    }
147
148    // Mask trailing bits
149    let trail = (len % 8) as usize;
150    if trail != 0 && !result.is_empty() {
151        let last = result.len() - 1;
152        result[last] &= 0xFF << (8 - trail);
153    }
154
155    result
156}
157
158/// Append normalized bits from src to dst at bit position dst_len
159#[inline]
160fn append_normalized(dst: &mut Vec<u8>, dst_len: BitsLen, src: &[u8], src_len: BitsLen) {
161    if src_len == 0 {
162        return
163    }
164
165    let total_len = dst_len + src_len;
166    let new_bytes = total_len.div_ceil(8) as usize;
167    dst.resize(new_bytes, 0);
168
169    let bit_offset = (dst_len % 8) as usize;
170    let byte_offset = (dst_len / 8) as usize;
171
172    if bit_offset == 0 {
173        // Fast path: byte-aligned append
174        let copy_len = src.len().min(new_bytes - byte_offset);
175        dst[byte_offset..byte_offset + copy_len].copy_from_slice(&src[..copy_len]);
176    } else {
177        // Shift src right by bit_offset and OR into dst
178        for i in 0..src.len() {
179            let shifted_hi = src[i] >> bit_offset;
180            let shifted_lo = src[i] << (8 - bit_offset);
181
182            dst[byte_offset + i] |= shifted_hi;
183            if byte_offset + i + 1 < dst.len() {
184                dst[byte_offset + i + 1] |= shifted_lo;
185            }
186        }
187    }
188}
189
190/// Merge a `BitsOwned` with a `Bits`, appending b's bits after a's.
191#[inline]
192pub fn merge_owned_and_bits(a: &BitsOwned, b: &Bits) -> BitsOwned {
193    let a_len = a.len();
194    let b_len = b.len();
195    let total_len = a_len + b_len;
196
197    if total_len == 0 {
198        return BitsOwned::from_raw(Vec::new(), 0, a.offset);
199    }
200
201    // Start with a copy of a's path
202    let mut path = a.path.clone();
203
204    // Extract and append b's normalized bits
205    let b_norm = extract_normalized(b);
206    append_normalized(&mut path, a_len, &b_norm, b_len);
207
208    BitsOwned::from_raw(path, total_len, a.offset)
209}
210
211#[derive(Debug, Clone, PartialEq)]
212/// `BitVec` implementation based on bytes slice.
213pub struct Bits<'a> {
214    pub path: &'a [u8],
215    pub range: Range<BitsLen>,
216}
217
218impl<'a> Bits<'a> {
219    pub fn new(bytes: &'a [u8]) -> Self {
220        Bits { path: bytes, range: 0..(bytes.len() as BitsLen * 8) }
221    }
222
223    /// Construct `Bits` instance by deserializing bytes slice.
224    pub fn from_bytes(bytes: &'a [u8]) -> Self {
225        let u = std::mem::size_of::<BitsLen>();
226        let start: BitsLen = bytes_to_int(&bytes[..u]);
227        let end: BitsLen = bytes_to_int(&bytes[u..2 * u]);
228        Self { path: &bytes[2 * u..], range: start..end }
229    }
230
231    /// Serialize `Bits` into bytes.
232    pub fn to_bytes(&self) -> GenericResult<Vec<u8>> {
233        let start = (self.range.start / 8) as usize;
234        let end = self.range.end.div_ceil(8) as usize;
235        let mut path = self.path[start..end].to_owned();
236        let r = (self.range.start % 8) as u8;
237        if r != 0 {
238            let mask = 0xffu8 >> r;
239            path[0] &= mask;
240        }
241        let r = (self.range.end % 8) as u8;
242        if r != 0 {
243            let mask = 0xffu8 << (8 - r);
244            let last = path.len() - 1;
245            path[last] &= mask;
246        }
247        Ok([&self.range.start.to_be_bytes(), &self.range.end.to_be_bytes(), &path[..]].concat())
248    }
249
250    /// Get the very first bit.
251    pub fn first(&self) -> bool {
252        bit(self.path, self.range.start)
253    }
254
255    pub fn len(&self) -> BitsLen {
256        self.range.end - self.range.start
257    }
258
259    pub fn is_empty(&self) -> bool {
260        self.len() == 0 || self.path.len() == 0
261    }
262
263    /// Get the first `n` bits.
264    pub fn take(&self, n: BitsLen) -> Self {
265        let x = self.range.start + n;
266        let q = nbytes_across(self.range.start, x);
267        let range = self.range.start..x;
268        Self { path: &self.path[..q as usize], range }
269    }
270
271    /// Skip the first `n` bits.
272    pub fn drop(&self, n: BitsLen) -> Self {
273        let x = self.range.start + n;
274        let q = x / 8;
275        let range = x % 8..self.range.end - 8 * (x / 8);
276        Self { path: &self.path[q as usize..], range }
277    }
278
279    /// Get length of the longest common prefix bits for the given two `Bits`.
280    pub fn len_common_bits(a: &Self, b: &Self) -> BitsLen {
281        len_lcp(a.path, &a.range, b.path, &b.range)
282    }
283
284    /// Convert to `BitsOwned`, preserving the range offset.
285    #[inline]
286    pub fn to_bits_owned(&self) -> BitsOwned {
287        let path = extract_normalized(self);
288        BitsOwned::from_raw(path, self.len(), self.range.start)
289    }
290
291    /// Merge two `Bits` into a new `BitsOwned`, preserving the first's offset.
292    #[inline]
293    pub fn merge(a: &Self, b: &Self) -> BitsOwned {
294        let a_len = a.len();
295        let b_len = b.len();
296        let total_len = a_len + b_len;
297
298        if total_len == 0 {
299            return BitsOwned::from_raw(Vec::new(), 0, a.range.start);
300        }
301
302        // Extract normalized bits from both
303        let mut path = extract_normalized(a);
304        let b_norm = extract_normalized(b);
305
306        // Append b's bits
307        append_normalized(&mut path, a_len, &b_norm, b_len);
308
309        BitsOwned::from_raw(path, total_len, a.range.start)
310    }
311}