vyre 0.1.0

GPU bytecode condition engine
Documentation
use crate::support::{build_index_from_source, is_gpu_available};

#[cfg(feature = "gpu")]
fn evaluate_gpu(source: &str, input: &[u8]) -> Vec<String> {
    let index = build_index_from_source(source);
    let (device, queue) = super::support::acquire_device().expect("gpu available");
    index
        .scan_with_device(input, &device, &queue)
        .expect("gpu scan")
        .into_iter()
        .map(|m| m.rule_name)
        .collect()
}

fn scan_cpu(source: &str, input: &[u8]) -> Vec<String> {
    build_index_from_source(source)
        .scan_cpu(input)
        .expect("cpu scan")
        .into_iter()
        .map(|m| m.rule_name)
        .collect()
}

fn assert_gpu_cpu_match(source: &str, yes_input: &[u8], no_input: &[u8]) {
    let cpu_yes = scan_cpu(source, yes_input);
    let cpu_no = scan_cpu(source, no_input);
    if !is_gpu_available() {
        return;
    }
    #[cfg(feature = "gpu")]
    {
        let gpu_yes = evaluate_gpu(source, yes_input);
        let gpu_no = evaluate_gpu(source, no_input);
        assert_eq!(gpu_yes, cpu_yes);
        assert_eq!(gpu_no, cpu_no);
    }
}

macro_rules! gpu_case {
    ($name:ident, $source:expr, $yes:expr, $no:expr) => {
        #[test]
        fn $name() {
            assert_gpu_cpu_match($source, $yes, $no);
        }
    };
}

gpu_case!(gpu_case_bool_true, r#"rule t { condition: true }"#, b"input", b"");
gpu_case!(gpu_case_bool_false, r#"rule t { condition: false }"#, b"", b"input");
gpu_case!(gpu_case_and_true, r#"rule t { strings: $a="a" $b="b" condition: $a and $b }"#, b"ab", b"a");
gpu_case!(gpu_case_or_true, r#"rule t { strings: $a="x" $b="y" condition: $a or $b }"#, b"y", b"z");
gpu_case!(gpu_case_not, r#"rule t { strings: $a="a" condition: not $a }"#, b"z", b"a");
gpu_case!(gpu_case_arith_eq, r#"rule t { condition: (3 + 4) == 7 }"#, b"x", b"");
gpu_case!(gpu_case_arith_ne, r#"rule t { condition: (10 - 3) != 8 }"#, b"x", b"");
gpu_case!(gpu_case_arith_lt, r#"rule t { condition: (1 + 1) < 3 }"#, b"x", b"");
gpu_case!(gpu_case_arith_gt, r#"rule t { condition: (6 - 2) > 3 }"#, b"x", b"");
gpu_case!(gpu_case_arith_lte, r#"rule t { condition: (4 * 2) <= 8 }"#, b"x", b"");
gpu_case!(gpu_case_arith_gte, r#"rule t { condition: (9 - 4) >= 5 }"#, b"x", b"");
gpu_case!(gpu_case_div_mod_zero, r#"rule t { condition: (7 % 0) == 0 and (7 \\ 0) == 0 }"#, b"x", b"");
gpu_case!(gpu_case_bitwise, r#"rule t { condition: (0xAA & 0x0F) == 0x0A }"#, b"x", b"");
gpu_case!(gpu_case_bit_or, r#"rule t { condition: (0xAA | 0x0F) == 0xBF }"#, b"x", b"");
gpu_case!(gpu_case_shift, r#"rule t { condition: (1 << 4) == 16 }"#, b"x", b"");
gpu_case!(gpu_case_filesize, r#"rule t { condition: filesize == 4 }"#, b"abcd", b"abc");
gpu_case!(gpu_case_string_match, r#"rule t { strings: $a="abc" condition: $a }"#, b"xxabc", b"xxab");
gpu_case!(gpu_case_string_count, r#"rule t { strings: $a="a" condition: #a == 3 }"#, b"aba", b"aa");
gpu_case!(gpu_case_string_length, r#"rule t { strings: $a="abc" condition: #a == 1 and !a[0] == 3 }"#, b"abc", b"xabc");
gpu_case!(gpu_case_string_offset, r#"rule t { strings: $a="abc" condition: @a[0] == 2 }"#, b"xxabc", b"abc");
gpu_case!(gpu_case_string_in, r#"rule t { strings: $a="abc" condition: $a in (0..10) }"#, b"abc", b"zzzz");
gpu_case!(gpu_case_string_at, r#"rule t { strings: $a="abc" condition: $a at 0 }"#, b"abc", b"zabc");
gpu_case!(gpu_case_all_of, r#"rule t { strings: $a="a" $b="b" condition: all of them }"#, b"ab", b"a");
gpu_case!(gpu_case_any_of, r#"rule t { strings: $a="a" $b="b" condition: any of them }"#, b"b", b"z");
gpu_case!(gpu_case_count_of, r#"rule t { strings: $a="a" $b="b" $c="c" condition: 2 of them }"#, b"abc", b"a");
gpu_case!(gpu_case_for_any, r#"rule t { strings: $a="a" condition: for any i in (0..2) : ( $a at i ) }"#, b"aa", b"ba");
gpu_case!(gpu_case_for_all, r#"rule t { strings: $a="a" condition: for all i in (0..0) : ( $a at i ) }"#, b"a", b"ba");
gpu_case!(gpu_case_for_n, r#"rule t { strings: $a="a" condition: for any i in (0..4) : ( @a[i] == 0 ) }"#, b"aaaa", b"bbbb");
gpu_case!(gpu_case_uint16, r#"rule t { condition: uint16(0) == 0x5A4D }"#, b"MZ", b"ZM");
gpu_case!(gpu_case_uint32, r#"rule t { condition: uint32(0) == 0x11223344 }"#, &0x11223344u32.to_le_bytes(), b"xxxx");
gpu_case!(gpu_case_int16, r#"rule t { condition: int16(0) == -2 }"#, &[0xFE,0xFF], &[0x02,0x00]);
gpu_case!(gpu_case_entrypoint, r#"rule t { condition: entrypoint >= 0 }"#, b"abc", b"");
gpu_case!(gpu_case_entropy_ctx, r#"rule t { condition: entropy == 0 }"#, b"abc", b"");
gpu_case!(gpu_case_sections_ctx, r#"rule t { condition: num_sections >= 0 }"#, b"abc", b"");
gpu_case!(gpu_case_imports_ctx, r#"rule t { condition: num_imports >= 0 }"#, b"abc", b"");
gpu_case!(gpu_case_signature_ctx, r#"rule t { condition: has_signature >= 0 }"#, b"abc", b"");
gpu_case!(gpu_case_magic_ctx, r#"rule t { condition: magic_u32 != 0 }"#, b"abc", b"");
gpu_case!(gpu_case_64bit_ctx, r#"rule t { condition: is_64bit >= 0 }"#, b"abc", b"");