boo-rs 0.1.3

Encrypt primitives types at compile time
Documentation
//! This is a separate file to prevent tests from being included by the macros.

use crate::branch::Branch;
use crate::mangle::Mangled;
use crate::utils::{checksum, split_array, xor};

#[test]
fn branch_obscure_hides_mask_target_and_selector_from_the_optimizer() {
    let branch: Branch = syn::parse2(quote::quote! { cond { 1 } else { 2 } }).unwrap();
    let tokens = branch.obscure(0).to_string();

    assert_eq!(tokens.matches("black_box").count(), 3);
}

#[test]
fn xor_round_trips_with_a_salt() {
    let original = [0, 1, 2, 3];
    let mut source = original;
    xor(&mut source, &[34, 52], 42);
    assert_ne!(source, original);

    xor(&mut source, &[34, 52], 42);
    assert_eq!(source, original);
}

#[test]
fn xor_round_trips_with_one_byte_key() {
    let original = [0, 1, 2, 3];
    let mut source = original;
    xor(&mut source, &[47], 7);
    xor(&mut source, &[47], 7);

    assert_eq!(source, original);
}

#[test]
fn xor_empty_key_is_a_no_op_regardless_of_salt() {
    let mut source = [0, 1, 2, 3];
    xor(&mut source, &[], 99);

    assert_eq!(source, [0, 1, 2, 3]);
}

#[test]
fn xor_empty_source() {
    let mut source = [];
    xor(&mut source, &[45, 32, 56], 1);

    assert!(source.is_empty());
}

#[test]
fn different_salts_produce_different_ciphertext() {
    let key = [34, 52];
    let mut a = [0, 1, 2, 3];
    let mut b = [0, 1, 2, 3];
    xor(&mut a, &key, 1);
    xor(&mut b, &key, 2);

    assert_ne!(a, b);
}

#[test]
fn wrong_salt_does_not_recover_the_plaintext() {
    let original = [10, 20, 30, 40];
    let mut source = original;
    xor(&mut source, &[34, 52], 1);
    xor(&mut source, &[34, 52], 2);

    assert_ne!(source, original);
}

#[test]
fn split_array_valid_result() {
    let original = [1, 2, 3, 4, 5];
    let (left, right): ([u8; 2], [u8; 3]) = split_array(original);

    assert_eq!(left, [1, 2]);
    assert_eq!(right, [3, 4, 5]);
}

#[test]
fn checksum_is_deterministic() {
    let bytes = [10, 20, 30, 40];
    assert_eq!(checksum(&bytes), checksum(&bytes));
}

#[test]
fn checksum_detects_a_single_flipped_byte() {
    let original = [10, 20, 30, 40];
    let mut tampered = original;
    tampered[2] ^= 1;

    assert_ne!(checksum(&original), checksum(&tampered));
}

#[test]
fn checksum_detects_a_length_change() {
    assert_ne!(checksum(&[1, 2, 3]), checksum(&[1, 2, 3, 0]));
}

#[test]
fn checksum_of_empty_slice_does_not_panic() {
    let _ = checksum(&[]);
}

#[test]
fn mangle_round_trips() {
    let original = [1u8, 2, 3, 4, 5, 6, 7, 8];
    let mangled = Mangled::new(original);
    mangled.reveal_with(|plain| assert_eq!(*plain, original));
}

#[test]
fn mangle_matches_a_pointer_sized_value() {
    let original = 0x0011_2233_4455_6677_u64.to_ne_bytes();
    let mangled = Mangled::new(original);
    mangled.reveal_with(|plain| assert_eq!(*plain, original));
}

#[test]
fn mangle_covers_a_value_longer_than_the_cookie() {
    let original = [7u8; 64];
    let mangled = Mangled::new(original);
    mangled.reveal_with(|plain| assert_eq!(*plain, original));
}

#[test]
fn mangle_does_not_repeat_its_keystream_within_one_value() {
    let original = [7u8; 64];
    let mangled = Mangled::new(original);
    // Same plaintext byte at every position: if the keystream repeated every 32 bytes (cookie
    // length), both halves of the mangled output would be identical too.
    assert_ne!(mangled.bytes[..32], mangled.bytes[32..]);
}

#[test]
fn mangle_never_reuses_a_keystream_across_two_values() {
    let original = [9u8, 8, 7, 6];
    let a = Mangled::new(original);
    let b = Mangled::new(original);
    assert_ne!(a.bytes, b.bytes);
    a.reveal_with(|plain| assert_eq!(*plain, original));
    b.reveal_with(|plain| assert_eq!(*plain, original));
}