soft3/bbg/rs/src/lib.rs

// ---
// tags: bbg, rust
// crystal-type: source
// crystal-domain: cyber
// ---
//! bbg โ€” Big Badass Graph: authenticated state with polynomial commitments.
//!
//! BBG has one operation: insert(signal).
//! All semantic validation (A1โ€“A3, focus sufficiency, box ownership,
//! conservation, VDF) is the responsibility of cybergraph.
//! BBG only enforces the structural double-spend invariant via N(x).

pub mod checkpoint;
pub mod dim;
pub mod proof;
pub mod prune;
pub mod query;
pub mod signal;
pub mod state;
pub mod stats;
pub mod storage;
pub mod types;

pub use checkpoint::Checkpoint;
pub use proof::{
    prove_axons_in, prove_axons_out, prove_balances, prove_card, prove_coin, prove_commitment,
    prove_file, prove_location, prove_neuron, prove_particle, prove_signal, prove_time,
    verify_particle, QueryProof,
};
pub use prune::{PruneConfig, PruneState};
pub use query::{
    bbg_query, collect_look_openings, verify_opening, verify_query,
    BbgLookProvider, Dim, ProofLookProvider,
};
pub use signal::{BoxMove, Cyberlink, InsertError, Signal};
pub use state::BbgState;
pub use stats::{GraphStats, STAT_RELATIONS};
pub use types::{IntentRecord, NeuronId, Particle, SignalRecord};

/// The BBG facade: state + checkpoint + pruning policy as a single unit.
pub struct Bbg {
    pub state: BbgState,
    pub checkpoint: Checkpoint,
    pub prune_config: PruneConfig,
    pub prune_state: PruneState,
}

impl Bbg {
    pub fn new() -> Self {
        let state = BbgState::new();
        let checkpoint = Checkpoint::new(&state);
        Self { state, checkpoint, prune_config: PruneConfig::default(), prune_state: PruneState::default() }
    }

    pub fn with_prune_config(mut self, config: PruneConfig) -> Self {
        self.prune_config = config;
        self
    }

    /// Insert a pre-validated signal. Fails only on structural double-spend.
    /// Updates pruning state (last_touched) on success.
    pub fn insert(&mut self, signal: &Signal) -> Result<(), InsertError> {
        self.state.insert(signal)?;
        let epoch = self.state.height / state::EPOCH_BLOCKS;
        for link in &signal.links {
            let aid = state::axon_id(&link.from, &link.to);
            self.prune_state.touch(aid, epoch);
        }
        Ok(())
    }

    /// Finalize the current block: record a time snapshot, increment height,
    /// and run pruning at epoch boundaries.
    pub fn finalize_block(&mut self) {
        let h = self.state.height;
        let root = self.state.root;
        self.state.time.insert(h, root);
        self.state.root = self.state.compute_root();
        self.state.height += 1;
        if self.state.height % state::EPOCH_BLOCKS == 0 {
            let epoch = self.state.height / state::EPOCH_BLOCKS;
            prune::prune(&mut self.state, &mut self.prune_state, &self.prune_config, epoch);
        }
        self.checkpoint = self.checkpoint.advance(&self.state);
    }

    pub fn prove_particle(&self, particle: &Particle) -> Option<QueryProof> {
        prove_particle(&self.state, particle)
    }

    pub fn prove_neuron(&self, id: &NeuronId) -> Option<QueryProof> {
        prove_neuron(&self.state, id)
    }

    pub fn prove_axons_out(&self, particle: &Particle) -> Option<QueryProof> {
        prove_axons_out(&self.state, particle)
    }

    pub fn prove_axons_in(&self, particle: &Particle) -> Option<QueryProof> {
        prove_axons_in(&self.state, particle)
    }

    pub fn prove_location(&self, particle: &Particle) -> Option<QueryProof> {
        prove_location(&self.state, particle)
    }

    pub fn prove_coin(&self, denom: &Particle) -> Option<QueryProof> {
        prove_coin(&self.state, denom)
    }

    pub fn prove_card(&self, card_id: &Particle) -> Option<QueryProof> {
        prove_card(&self.state, card_id)
    }

    pub fn prove_file(&self, particle: &Particle) -> Option<QueryProof> {
        prove_file(&self.state, particle)
    }

    pub fn prove_signal(&self, step: u64) -> Option<QueryProof> {
        prove_signal(&self.state, step)
    }

    pub fn prove_time(&self, height: u64) -> Option<QueryProof> {
        prove_time(&self.state, height)
    }

    pub fn prove_commitment(&self, point: &[u8; 32]) -> Option<QueryProof> {
        prove_commitment(&self.state, point)
    }

    pub fn prove_balances(&self, owner: &[u8; 32], token: &[u8; 32]) -> Option<QueryProof> {
        prove_balances(&self.state, owner, token)
    }

    /// Persist an unsealed intent. Validation (identity signature) is sync's job.
    /// Returns the intent key = H(ฮฝ โ€– h0 โ€– scope_hash).
    pub fn apply_intent(&mut self, intent: &IntentRecord) -> Particle {
        self.state.apply_intent(intent)
    }

    /// Persist a signal header without applying its cyberlinks.
    /// Used when sealing follows a separate intent โ†’ seal lifecycle.
    pub fn apply_signal_record(&mut self, step: u64, record: SignalRecord) {
        self.state.apply_signal_record(step, record);
    }

    /// Committed graph statistics โ€” the bbg โ†’ inf cost/recursion interface.
    /// Authenticated by inclusion in BBG_root.
    pub fn statistics(&self) -> GraphStats {
        self.state.statistics()
    }

    /// Install a tighter (proven) diameter bound from tru. Takes effect on the
    /// next `finalize_block`.
    pub fn set_diameter_bound(&mut self, bound: u64) {
        self.state.set_diameter_bound(bound);
    }
}

impl Default for Bbg {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use signal::BoxMove;
    use types::NeuronRecord;

    fn neuron_id(seed: u8) -> NeuronId { [seed; 32] }
    fn particle(seed: u8) -> Particle { [seed; 32] }

    fn seed_neuron(bbg: &mut Bbg, id: NeuronId, focus: u64) {
        bbg.state.neurons.insert(id, NeuronRecord { focus, karma: 0, stake: 0 });
    }

    fn one_link(neuron: NeuronId, from: Particle, to: Particle) -> Signal {
        Signal {
            neuron,
            links: vec![Cyberlink { from, to, token: particle(0), amount: 1, valence: 1 }],
            box_moves: vec![],
            height: 0,
        }
    }

    #[test]
    fn empty_root_is_deterministic() {
        assert_eq!(BbgState::new().root, BbgState::new().root);
    }

    #[test]
    fn compute_root_is_deterministic() {
        let mut a = Bbg::new();
        let mut b = Bbg::new();
        seed_neuron(&mut a, neuron_id(1), 100);
        seed_neuron(&mut b, neuron_id(1), 100);
        a.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();
        b.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();
        assert_eq!(a.state.compute_root(), b.state.compute_root());
    }

    #[test]
    fn cyberlink_changes_root() {
        let mut bbg = Bbg::new();
        seed_neuron(&mut bbg, neuron_id(1), 100);
        let root_before = bbg.state.root;
        bbg.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();
        assert_ne!(bbg.state.root, root_before);
    }

    #[test]
    fn finalize_block_increments_height() {
        let mut bbg = Bbg::new();
        assert_eq!(bbg.state.height, 0);
        bbg.finalize_block();
        assert_eq!(bbg.state.height, 1);
        bbg.finalize_block();
        assert_eq!(bbg.state.height, 2);
    }

    #[test]
    fn double_spend_is_rejected() {
        let mut bbg = Bbg::new();
        let nullifier = particle(42);
        let mk_signal = || Signal {
            neuron: neuron_id(1),
            links: vec![],
            box_moves: vec![BoxMove { nullifier, commitment: None }],
            height: 0,
        };
        bbg.insert(&mk_signal()).unwrap();
        assert_eq!(bbg.insert(&mk_signal()), Err(InsertError::DoubleSpend));
    }

    #[test]
    fn prove_and_verify_particle_roundtrip() {
        let mut bbg = Bbg::new();
        seed_neuron(&mut bbg, neuron_id(1), 100);
        bbg.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();

        let proof = bbg.prove_particle(&particle(3)).expect("particle proof must exist");
        assert!(verify_particle(&proof, &bbg.state.root, &particle(3)));
    }

    #[test]
    fn prove_particle_returns_none_for_unknown_cid() {
        assert!(Bbg::new().prove_particle(&particle(255)).is_none());
    }

    #[test]
    fn statistics_count_nodes_and_relations() {
        let mut bbg = Bbg::new();
        seed_neuron(&mut bbg, neuron_id(1), 100);
        bbg.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();

        let s = bbg.statistics();
        // particle(3) target + axon-particle H(2,3) = 2 nodes
        assert_eq!(s.node_count, s.relation_sizes[stats::rel::PARTICLES]);
        assert_eq!(s.relation_sizes[stats::rel::AXONS_OUT], 1);
        assert_eq!(s.relation_sizes[stats::rel::AXONS_IN], 1);
        assert_eq!(s.relation_sizes[stats::rel::NEURONS], 1);
    }

    #[test]
    fn diameter_bound_defaults_to_node_count_minus_one() {
        let mut bbg = Bbg::new();
        seed_neuron(&mut bbg, neuron_id(1), 100);
        bbg.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();
        let s = bbg.statistics();
        assert_eq!(s.diameter_bound, s.node_count.saturating_sub(1));
    }

    #[test]
    fn installed_diameter_bound_is_used_and_changes_root() {
        let mut bbg = Bbg::new();
        seed_neuron(&mut bbg, neuron_id(1), 100);
        bbg.insert(&one_link(neuron_id(1), particle(2), particle(3))).unwrap();
        let root_before = bbg.state.compute_root();
        // Default for 2 nodes is node_count-1 = 1; install a distinct (sound
        // upper) bound to show the committed value flows into the root.
        bbg.set_diameter_bound(8);
        assert_eq!(bbg.statistics().diameter_bound, 8);
        assert_ne!(bbg.state.compute_root(), root_before);
    }

    #[test]
    fn empty_graph_stats_are_zero() {
        let s = Bbg::new().statistics();
        assert_eq!(s.node_count, 0);
        assert_eq!(s.max_degree, 0);
        assert_eq!(s.diameter_bound, 0); // node_count.saturating_sub(1) on empty
    }
}

Homonyms

cyb/optica/src/lib.rs
soft3/strata/src/lib.rs
cyb/honeycrisp/src/lib.rs
warriors/trisha/honeycrisp/lib.rs
warriors/trisha/wgpu/lib.rs
soft3/glia/import/lib.rs
soft3/foculus/src/lib.rs
soft3/nox/rs/lib.rs
soft3/cybergraph/src/lib.rs
soft3/tru/rs/lib.rs
soft3/mudra/src/lib.rs
soft3/glia/run/lib.rs
cyb/prysm/rs/lib.rs
warriors/trisha/rs/lib.rs
cyb/src-tauri/src/lib.rs
soft3/mir/src/lib.rs
soft3/lens/src/lib.rs
neural/trident/src/lib.rs
neural/rune/rs/subject/lib.rs
cyb/cyb/cyb-services/src/lib.rs
soft3/strata/nebu/rs/lib.rs
soft3/lens/core/src/lib.rs
neural/rs/mir-format/src/lib.rs
soft3/zheng/rs/src/lib.rs
neural/rune/rs/interp/lib.rs
soft3/radio/iroh-willow/src/lib.rs
neural/rune/rs/parse/lib.rs
neural/eidos/rs/src/lib.rs
neural/rs/darwin-sys/src/lib.rs
soft3/radio/iroh-gossip/src/lib.rs
soft3/radio/iroh-ffi/src/lib.rs
soft3/radio/iroh-car/src/lib.rs
soft3/radio/iroh-relay/src/lib.rs
soft3/radio/iroh-docs/src/lib.rs
soft3/lens/ikat/src/lib.rs
neural/rune/rs/lex/lib.rs
cyb/honeycrisp/aruminium/src/lib.rs
soft3/hemera/rs/src/lib.rs
neural/rune/rs/ast/lib.rs
soft3/radio/iroh-blobs/src/lib.rs
cyb/honeycrisp/acpu/src/lib.rs
soft3/lens/porphyry/src/lib.rs
cyb/honeycrisp/rane/src/lib.rs
neural/rune/rs/compile/lib.rs
neural/rune/rs/parse-pure/lib.rs
neural/rs/codegen/src/lib.rs
soft3/lens/binius/src/lib.rs
neural/rune/rs/prysm/lib.rs
neural/rs/link/src/lib.rs
neural/rune/rs/mold/lib.rs
soft3/strata/proof/src/lib.rs
soft3/lens/brakedown/src/lib.rs
soft3/strata/kuro/rs/lib.rs
soft3/lens/assayer/src/lib.rs
neural/rs/core/src/lib.rs
neural/rs/macros/src/lib.rs
soft3/radio/cyber-bao/src/lib.rs
soft3/strata/compute/src/lib.rs
soft3/radio/iroh-base/src/lib.rs
soft3/radio/iroh-dns-server/src/lib.rs
neural/rune/rs/lower/lib.rs
soft3/strata/ext/src/lib.rs
soft3/strata/core/src/lib.rs
soft3/hemera/wgsl/src/lib.rs
soft3/radio/iroh/src/lib.rs
cyb/honeycrisp/unimem/src/lib.rs
cyb/evy/crates/evy_engine_tasks/src/lib.rs
cyb/evy/crates/evy_dialect/src/lib.rs
cyb/wysm/crates/wasi/src/lib.rs
cyb/wysm/crates/fuzz/src/lib.rs
soft3/strata/genies/rs/src/lib.rs
cyb/evy/crates/evy_platform_caps/src/lib.rs
neural/inf/rs/oracle/src/lib.rs
soft3/strata/jali/wgsl/src/lib.rs
cyb/evy/forks/bevy_transform/src/lib.rs
soft3/tape/impl/rust/src/lib.rs
cyb/wysm/crates/wasmi/src/lib.rs
cyb/evy/forks/bevy_render/src/lib.rs
cyb/evy/crates/evy_ecs_storage/src/lib.rs
cyb/evy/forks/naga/src/lib.rs
soft3/strata/trop/wgsl/src/lib.rs
cyb/wysm/crates/c_api/artifact/lib.rs
cyb/evy/forks/bevy_ecs/src/lib.rs
cyb/wysm/crates/ir/src/lib.rs
cyb/evy/forks/bevy_animation/src/lib.rs
cyb/evy/forks/bevy_sprite_render/src/lib.rs
cyb/wysm/crates/c_api/src/lib.rs
neural/inf/rs/parse/src/lib.rs
soft3/strata/trop/rs/src/lib.rs
soft3/strata/kuro/wgsl/src/lib.rs
neural/trident/editor/zed/src/lib.rs
cyb/evy/forks/bevy_mesh/src/lib.rs
cyb/evy/crates/evy_radio/src/lib.rs
cyb/evy/forks/bevy_anti_alias/src/lib.rs
soft3/strata/jali/rs/src/lib.rs
cyb/wysm/crates/wast/src/lib.rs
neural/inf/rs/plan/src/lib.rs
neural/rs/tests/macro-integration/src/lib.rs
soft3/radio/iroh-ffi/iroh-js/src/lib.rs
cyb/evy/forks/bevy_image/src/lib.rs
cyb/evy/forks/bevy_post_process/src/lib.rs
neural/inf/rs/source/src/lib.rs
cyb/wysm/crates/core/src/lib.rs
cyb/evy/crates/evy_diagnostic/src/lib.rs
cyb/evy/crates/evy_engine_dispatch/src/lib.rs
cyb/evy/forks/bevy_pbr/src/lib.rs
cyb/evy/forks/bevy_gizmos/src/lib.rs
cyb/evy/forks/bevy_gizmos_render/src/lib.rs
soft3/radio/iroh/bench/src/lib.rs
neural/inf/rs/lex/src/lib.rs
neural/inf/rs/ast/src/lib.rs
soft3/strata/genies/wgsl/src/lib.rs
soft3/strata/nebu/wgsl/src/lib.rs
cyb/wysm/crates/collections/src/lib.rs
neural/inf/rs/lower/src/lib.rs
cyb/evy/forks/bevy_sprite/src/lib.rs
cyb/evy/forks/bevy_diagnostic/src/lib.rs
neural/inf/rs/eval/src/lib.rs
cyb/wysm/crates/c_api/macro/lib.rs
cyb/evy/forks/bevy_tasks/src/lib.rs
cyb/evy/forks/bevy_core_pipeline/src/lib.rs
cyb/evy/crates/evy_prysm_core/src/lib.rs
neural/inf/rs/value/src/lib.rs
cyb/evy/crates/evy_engine_core/src/lib.rs
soft3/radio/tests/integration/src/lib.rs
bootloader/go-cyber/cw/packages/cyber-std-test/src/lib.rs
bootloader/go-cyber/cw/contracts/std-test/src/lib.rs
bootloader/go-cyber/cw/contracts/graph-filter/src/lib.rs
bootloader/go-cyber/cw/packages/cyber-std/src/lib.rs

Graph