mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-19 22:34:46 -07:00
71 lines
1.9 KiB
Rust
71 lines
1.9 KiB
Rust
use crate::xor_bytes::{XOR_LEN, XORBytes};
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
|
pub struct XORIndex(usize);
|
|
|
|
impl XORIndex {
|
|
/// Phase-aligned `XORIndex` for a buffer that conceptually starts
|
|
/// at `offset` in the blk file.
|
|
#[inline]
|
|
pub fn at_offset(offset: usize) -> Self {
|
|
Self(offset & (XOR_LEN - 1))
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn phase(self) -> usize {
|
|
self.0
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn set_phase(&mut self, phase: usize) {
|
|
self.0 = phase & (XOR_LEN - 1);
|
|
}
|
|
|
|
#[inline]
|
|
pub fn add_assign(&mut self, i: usize) {
|
|
self.0 = (self.0 + i) & (XOR_LEN - 1);
|
|
}
|
|
|
|
/// XOR-decode `bytes` in place, advancing the phase. Aligned 8-byte
|
|
/// chunks XOR against the full mask in one go (auto-vectorised by
|
|
/// LLVM); only the head/tail straddling alignment are scalar.
|
|
pub fn bytes<'a>(&mut self, bytes: &'a mut [u8], xor_bytes: XORBytes) -> &'a mut [u8] {
|
|
if xor_bytes.is_identity() {
|
|
return bytes;
|
|
}
|
|
let xb = *xor_bytes;
|
|
let mut phase = self.0;
|
|
let len = bytes.len();
|
|
let mut i = 0;
|
|
|
|
while phase != 0 && i < len {
|
|
bytes[i] ^= xb[phase];
|
|
phase = (phase + 1) & (XOR_LEN - 1);
|
|
i += 1;
|
|
}
|
|
|
|
let body_len = (len - i) & !(XOR_LEN - 1);
|
|
for chunk in bytes[i..i + body_len].chunks_exact_mut(XOR_LEN) {
|
|
for (b, m) in chunk.iter_mut().zip(xb) {
|
|
*b ^= m;
|
|
}
|
|
}
|
|
i += body_len;
|
|
|
|
while i < len {
|
|
bytes[i] ^= xb[phase];
|
|
phase = (phase + 1) & (XOR_LEN - 1);
|
|
i += 1;
|
|
}
|
|
|
|
self.0 = phase;
|
|
bytes
|
|
}
|
|
|
|
/// XOR-decode `buffer` as if it lived at `offset` in the blk file.
|
|
#[inline]
|
|
pub fn decode_at(buffer: &mut [u8], offset: usize, xor_bytes: XORBytes) {
|
|
Self::at_offset(offset).bytes(buffer, xor_bytes);
|
|
}
|
|
}
|