#![allow(clippy::needless_range_loop)]
use core::panic;
use crate::{PenisBlock, PrivateBlock, State};
use alloc::vec::Vec;
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Penis(pub Vec<PenisBlock>);
impl Penis {
pub fn encode_compact(&self) -> Vec<u8> {
let estimated_capacity = self.0.iter().map(|block| block.encoded_size() + 1).sum();
let mut encoded_bytes = Vec::with_capacity(estimated_capacity);
for block in &self.0 {
match block {
PenisBlock::Private(private_block) => {
encoded_bytes.push(1);
for &value in &private_block.psa {
encoded_bytes.extend(&value.to_be_bytes());
}
encoded_bytes.extend(private_block.state.finalize().as_ref());
}
PenisBlock::Public(raw_block) => {
encoded_bytes.push(0);
encoded_bytes.extend(raw_block);
}
}
}
encoded_bytes
}
pub fn decode_compact(compact_bytes: &[u8]) -> Self {
let mut penis_blocks = Vec::new();
let mut i = 0;
while i < compact_bytes.len() {
let block_type = compact_bytes[i];
i += 1;
match block_type {
1 => {
let mut psa = [0u32; 16];
for j in 0..16 {
let base_ptr = i + j * 4;
psa[j] = u32::from_be_bytes([
compact_bytes[base_ptr],
compact_bytes[base_ptr + 1],
compact_bytes[base_ptr + 2],
compact_bytes[base_ptr + 3],
]);
}
i += 64;
let state = State::from_bytes(&compact_bytes[i..i + 32]);
penis_blocks.push(PenisBlock::Private(PrivateBlock { psa, state }));
i += 32;
}
0 => {
let mut raw_block = [0u8; 64];
raw_block.copy_from_slice(&compact_bytes[i..i + 64]);
penis_blocks.push(PenisBlock::Public(raw_block));
i += 64;
}
_ => panic!("Unknown block type"),
}
}
Self(penis_blocks)
}
pub fn encode_u32(&self) -> Vec<u32> {
let estimated_capacity = self
.0
.iter()
.map(|block| block.encoded_size() / 4 + 1)
.sum();
let mut encoded_bytes = Vec::with_capacity(estimated_capacity);
for block in &self.0 {
match block {
PenisBlock::Private(private_block) => {
encoded_bytes.push(1);
encoded_bytes.extend(private_block.psa);
encoded_bytes.extend(private_block.state.finalize_u32().as_ref());
}
PenisBlock::Public(raw_block) => {
encoded_bytes.push(0);
encoded_bytes.extend(raw_block.iter().map(|&x| x as u32));
}
}
}
encoded_bytes
}
pub fn decode_u32(u32_data: &[u32]) -> Self {
let mut penis_blocks = Vec::new();
let mut i = 0;
while i < u32_data.len() {
let block_type = u32_data[i];
i += 1;
match block_type {
1 => {
let mut psa = [0u32; 16];
psa.copy_from_slice(&u32_data[i..i + 16]);
let state_data = &u32_data[i + 16..i + 24];
let state = State {
a: state_data[0],
b: state_data[1],
c: state_data[2],
d: state_data[3],
e: state_data[4],
f: state_data[5],
g: state_data[6],
h: state_data[7],
};
penis_blocks.push(PenisBlock::Private(PrivateBlock { psa, state }));
i += 24;
}
0 => {
let mut raw_block = [0u8; 64];
for j in 0..16 {
let bytes = u32_data[i + j].to_be_bytes();
raw_block[j * 4..j * 4 + 4].copy_from_slice(&bytes);
}
penis_blocks.push(PenisBlock::Public(raw_block));
i += 16;
}
_ => panic!("Unknown block type"),
}
}
Self(penis_blocks)
}
pub fn encode_sparse(&self) -> Vec<u8> {
let mut encoded_bytes = Vec::new();
let mut last_proc = 0; let mut current_type = self.0[0].type_flag();
while last_proc < self.0.len() {
let mut consec = 1;
while last_proc + consec < self.0.len()
&& self.0[last_proc + consec].type_flag() == current_type
{
consec += 1;
}
if consec < 64 {
encoded_bytes.push((current_type << 7) | (consec as u8));
} else {
encoded_bytes.push((current_type << 7) | (1 << 6));
let length_field: u64 = consec as u64;
encoded_bytes.extend(&length_field.to_be_bytes());
}
for i in 0..consec {
match &self.0[last_proc + i] {
PenisBlock::Private(private_block) => {
for &value in &private_block.psa {
encoded_bytes.extend(&value.to_be_bytes());
}
encoded_bytes.extend(private_block.state.finalize().as_ref());
}
PenisBlock::Public(raw_block) => {
encoded_bytes.extend(raw_block);
}
}
}
last_proc += consec;
if last_proc >= self.0.len() {
break;
}
current_type = self.0[last_proc].type_flag();
}
encoded_bytes
}
pub fn decode_sparse(sparse_bytes: &[u8]) -> Self {
let mut penis_blocks = Vec::new();
let mut i = 0;
while i < sparse_bytes.len() {
let header = sparse_bytes[i];
i += 1;
let block_type = (header & 0x80) >> 7;
let length_flag = (header & 0x40) >> 6;
let consecutive_count: usize = if length_flag == 0 {
(header & 0b111111).into()
} else {
if (header & 0b111111) != 0 {
panic!("Invalid format: RFU field must be zero");
}
let mut extended_length_bytes = [0u8; 8];
extended_length_bytes[0..8].copy_from_slice(&sparse_bytes[i..i + 8]);
i += 8;
let len = u64::from_be_bytes(extended_length_bytes) as usize;
if len < 64 {
panic!("Invalid format: length when in extended length must be at least 64");
}
len
};
if consecutive_count == 0 {
panic!("Invalid format: consecutive_count cannot be zero");
}
for _ in 0..consecutive_count {
match block_type {
1 => {
let mut psa = [0u32; 16];
for j in 0..16 {
psa[j] = u32::from_be_bytes([
sparse_bytes[i],
sparse_bytes[i + 1],
sparse_bytes[i + 2],
sparse_bytes[i + 3],
]);
i += 4;
}
let state = State::from_bytes(&sparse_bytes[i..i + 32]);
i += 32;
penis_blocks.push(PenisBlock::Private(PrivateBlock { psa, state }));
}
0 => {
let mut raw_block = [0u8; 64];
raw_block.copy_from_slice(&sparse_bytes[i..i + 64]);
i += 64;
penis_blocks.push(PenisBlock::Public(raw_block));
}
_ => unreachable!("Unknown block type"),
}
}
}
Self(penis_blocks)
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use super::*;
#[test]
fn test_sparse_encoding() {
let private1 = PrivateBlock {
psa: [1u32; 16],
state: State {
a: 0x1111,
b: 0x2222,
c: 0x3333,
d: 0x4444,
e: 0x5555,
f: 0x6666,
g: 0x7777,
h: 0x8888,
},
};
let private2 = PrivateBlock {
psa: [2u32; 16],
state: State {
a: 0x1111,
b: 0x2222,
c: 0x3333,
d: 0x4444,
e: 0x5555,
f: 0x6666,
g: 0x7777,
h: 0x8888,
},
};
let private3 = PrivateBlock {
psa: [3u32; 16],
state: State {
a: 0x1111,
b: 0x2222,
c: 0x3333,
d: 0x4444,
e: 0x5555,
f: 0x6666,
g: 0x7777,
h: 0x8888,
},
};
let public1 = [1u8; 64];
let public2 = [2u8; 64];
let public3 = [3u8; 64];
let public4 = [4u8; 64];
let penis = Penis(vec![
PenisBlock::Public(public1),
PenisBlock::Public(public2),
PenisBlock::Private(private1),
PenisBlock::Private(private2),
PenisBlock::Public(public3),
PenisBlock::Private(private3),
PenisBlock::Public(public4),
]);
let encoded = penis.encode_sparse();
let decoded = Penis::decode_sparse(&encoded);
assert_eq!(penis, decoded);
let expected_length = 5 + (4 * 64) + (3 * 96);
assert_eq!(encoded.len(), expected_length);
}
#[test]
fn test_sparse_encoding_long_sequence() {
let public_blocks: Vec<PenisBlock> = (0..100)
.map(|i| PenisBlock::Public([i as u8; 64]))
.collect();
let private_blocks: Vec<PenisBlock> = (0..70)
.map(|i| {
PenisBlock::Private(PrivateBlock {
psa: [i as u32; 16],
state: State {
a: 0x1111,
b: 0x2222,
c: 0x3333,
d: 0x4444,
e: 0x5555,
f: 0x6666,
g: 0x7777,
h: 0x8888,
},
})
})
.collect();
let mut all_blocks = Vec::new();
all_blocks.extend(public_blocks);
all_blocks.extend(private_blocks);
let penis = Penis(all_blocks);
let encoded = penis.encode_sparse();
let decoded = Penis::decode_sparse(&encoded);
assert_eq!(penis, decoded);
let expected_length = (1 + 8) + (100 * 64) + (1 + 8) + (70 * 96);
assert_eq!(encoded.len(), expected_length);
assert_eq!(encoded[0] & 0x40, 0x40);
}
#[test]
fn test_compact_encoding() {
let private = PrivateBlock {
psa: [0xDEADBEEF; 16],
state: State {
a: 0x67452301,
b: 0xEFCDAB89,
c: 0x98BADCFE,
d: 0x10325476,
e: 0xC3D2E1F0,
f: 0x1F83D9AB,
g: 0x2B87E4CD,
h: 0x3C9BE0F1,
},
};
let public = [0xAA; 64];
let penis = Penis(vec![
PenisBlock::Public(public),
PenisBlock::Private(private),
PenisBlock::Public(public),
]);
let encoded = penis.encode_compact();
let decoded = Penis::decode_compact(&encoded);
assert_eq!(penis, decoded);
let expected_length = (1 + 64) + (1 + 96) + (1 + 64);
assert_eq!(encoded.len(), expected_length);
}
#[test]
#[should_panic(expected = "Invalid format: RFU field must be zero")]
fn test_sparse_decode_invalid_rfu() {
let mut encoded = vec![0b01100000];
encoded.extend([0u8; 8]); Penis::decode_sparse(&encoded);
}
#[test]
#[should_panic(expected = "Invalid format: consecutive_count cannot be zero")]
fn test_sparse_decode_zero_count() {
let encoded = vec![0b00000000]; Penis::decode_sparse(&encoded);
}
#[test]
#[should_panic(expected = "Invalid format: length when in extended length must be at least 64")]
fn test_sparse_decode_zero_count_long() {
let mut encoded = vec![0b11000000];
encoded.extend([0u8; 8]); Penis::decode_sparse(&encoded);
}
#[test]
#[should_panic(expected = "length when in extended length must be at least 64")]
fn test_sparse_decode_invalid_len_long() {
let mut encoded = vec![0b11000000];
encoded.extend((1u64).to_be_bytes()); Penis::decode_sparse(&encoded);
}
#[test]
#[should_panic(expected = "index out of bounds: the len is 1 but the index is 1")]
fn test_sparse_decode_invalid_format() {
let encoded = vec![0b10000001];
Penis::decode_sparse(&encoded);
}
#[test]
#[should_panic(expected = "index out of bounds: the len is 9 but the index is 9")]
fn test_sparse_decode_invalid_format_long() {
let mut encoded = vec![0b11000000];
encoded.extend((64u64).to_be_bytes()); Penis::decode_sparse(&encoded);
}
#[test]
#[should_panic]
fn test_sparse_decode_truncated_data() {
let mut encoded = vec![];
encoded.push(0b00000010); encoded.extend([1u8; 64]); Penis::decode_sparse(&encoded);
}
}