use vyre::ir::Program;
use vyre_primitives::graph::program_graph::ProgramGraphShape;
use vyre_primitives::predicate::edge_kind;
use crate::security::flow_composition::dataflow_hit_program;
#[cfg(test)]
use crate::security::flow_composition::{any_dataflow_hit_cpu_ref, dataflow_reach_step_cpu_ref};
pub(crate) const OP_ID: &str = "vyre-libs::security::flows_to_to_sink";
#[must_use]
pub fn flows_to_to_sink(
shape: ProgramGraphShape,
source_buf: &str,
sink_buf: &str,
reach_buf: &str,
hits_buf: &str,
out_scalar_buf: &str,
) -> Program {
dataflow_hit_program(
OP_ID,
shape,
source_buf,
sink_buf,
reach_buf,
hits_buf,
out_scalar_buf,
)
}
#[must_use]
#[cfg(test)]
pub(crate) fn cpu_ref(
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
source: &[u32],
sink: &[u32],
) -> u32 {
let reach = dataflow_reach_step_cpu_ref(
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
source,
);
any_dataflow_hit_cpu_ref(&reach, sink)
}
inventory::submit! {
crate::harness::OpEntry {
id: OP_ID,
build: || flows_to_to_sink(ProgramGraphShape::new(4, 3), "source", "sink", "reach", "hits", "out_scalar"),
test_inputs: Some(|| {
let to_bytes = vyre_primitives::wire::pack_u32_slice;
vec![vec![
to_bytes(&[0, 0, 0, 0]), to_bytes(&[0, 1, 2, 3, 3]), to_bytes(&[1, 2, 3]), to_bytes(&[
edge_kind::ASSIGNMENT,
edge_kind::ASSIGNMENT,
edge_kind::ASSIGNMENT,
]), to_bytes(&[0, 0, 0, 0]), to_bytes(&[0b0001]), to_bytes(&[0b0001]), to_bytes(&[0b0010]), to_bytes(&[0b0000]), to_bytes(&[0b0000]), ]]
}),
expected_output: Some(|| {
let to_bytes = vyre_primitives::wire::pack_u32_slice;
vec![vec![
to_bytes(&[0b0011]), to_bytes(&[0b0010]), to_bytes(&[0b0001]), ]]
}),
category: Some("security"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::security::flow_composition::linear_dataflow;
#[test]
fn one_hop_source_reaches_sink_returns_one() {
let (off, tgt, msk) = linear_dataflow(4);
let source = [0b0001u32]; let sink = [0b0010u32]; let result = cpu_ref(4, &off, &tgt, &msk, &source, &sink);
assert_eq!(result, 1);
}
#[test]
fn two_hops_unreachable_in_one_step_returns_zero() {
let (off, tgt, msk) = linear_dataflow(4);
let source = [0b0001u32]; let sink = [0b0100u32]; let result = cpu_ref(4, &off, &tgt, &msk, &source, &sink);
assert_eq!(result, 0);
}
#[test]
fn empty_source_returns_zero() {
let (off, tgt, msk) = linear_dataflow(4);
let source = [0u32];
let sink = [0b0010u32];
let result = cpu_ref(4, &off, &tgt, &msk, &source, &sink);
assert_eq!(result, 0);
}
#[test]
fn empty_sink_returns_zero() {
let (off, tgt, msk) = linear_dataflow(4);
let source = [0b0001u32];
let sink = [0u32];
let result = cpu_ref(4, &off, &tgt, &msk, &source, &sink);
assert_eq!(result, 0);
}
}