use vyre_foundation::ir::Program;
use vyre_primitives::bitset::and::bitset_and;
use vyre_primitives::bitset::bitset_words;
use vyre_primitives::reduce::count::reduce_count;
use crate::security::flow_composition::fuse_security_flow;
pub(crate) const OP_ID: &str = "vyre-libs::security::sink_intersection";
#[must_use]
pub fn sink_intersection(
node_count: u32,
query_set: &str,
sink_set: &str,
intersect_buf: &str,
out_scalar: &str,
) -> Program {
let words = bitset_words(node_count);
fuse_security_flow(
OP_ID,
&[
bitset_and(query_set, sink_set, intersect_buf, words),
reduce_count(intersect_buf, out_scalar, words),
],
out_scalar,
)
}
#[must_use]
#[cfg(test)]
pub(crate) fn cpu_ref(query_set: &[u32], sink_set: &[u32]) -> u32 {
vyre_primitives::reduce::count::cpu_ref(&vyre_primitives::bitset::and::cpu_ref(
query_set, sink_set,
))
}
pub struct SinkIntersection;
impl vyre_spec::soundness::SoundnessTagged for SinkIntersection {
fn soundness(&self) -> vyre_spec::soundness::Soundness {
vyre_spec::soundness::Soundness::Exact
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn full_overlap_counts_all_set_bits() {
assert_eq!(cpu_ref(&[0b1111], &[0b1111]), 4);
}
#[test]
fn no_overlap_returns_zero() {
assert_eq!(cpu_ref(&[0b1010], &[0b0101]), 0);
}
#[test]
fn partial_overlap_counts_intersection() {
assert_eq!(cpu_ref(&[0b1110], &[0b0111]), 2);
}
#[test]
fn distributes_across_words() {
assert_eq!(cpu_ref(&[0xFF00, 0x00FF], &[0xFFFF, 0xFFFF]), 16);
}
}