soft3/lens/ikat/src/lib.rs

//! cyb-lens-ikat โ€” Ikat polynomial commitment.
//!
//! Ring-aware commitment over jali's R_q = F_p[x]/(x^n+1).
//! NTT decomposes ring operations into n independent Goldilocks operations.
//! Ikat commits the NTT evaluation slots via Brakedown, batching multiple
//! ring elements into a single commitment.
//!
//! The ring-awareness shows in how data is prepared: ring elements are
//! converted to NTT form before commitment, and multiple ring polynomials
//! can be batched into one multilinear polynomial over the NTT slots.
//!
//! Implements Lens<Goldilocks> โ€” the NTT slots are Goldilocks scalars.
//!
//! See specs/polynomial-ring.md for the full specification.

pub use cyb_lens_core::{Commitment, Field, Lens, MultilinearPoly, Opening, Transcript};

use cyb_lens_brakedown::Brakedown;
use jali::ntt;
use jali::ring::RingElement;
use nebu::Goldilocks;

/// Ikat polynomial commitment โ€” ring-aware Brakedown over NTT slots.
pub struct Ikat;

impl Ikat {
    /// Convert a ring element to its NTT slot representation.
    /// Returns n Goldilocks scalars (the NTT evaluation points).
    pub fn ring_to_ntt_slots(ring_elem: &RingElement) -> Vec<Goldilocks> {
        let mut elem = ring_elem.clone();
        if !elem.is_ntt {
            ntt::to_ntt(&mut elem);
        }
        elem.coeffs[..elem.n].to_vec()
    }

    /// Batch multiple ring elements into a single multilinear polynomial.
    ///
    /// Given m ring elements of dimension n, produces a multilinear polynomial
    /// of size m ร— n over Goldilocks. The NTT structure means all n slots
    /// of each ring element are committed together, enabling ring-aware
    /// verification.
    pub fn batch_rings(elements: &[RingElement]) -> MultilinearPoly<Goldilocks> {
        assert!(!elements.is_empty());
        let n = elements[0].n;

        let mut all_slots = Vec::with_capacity(elements.len() * n);
        for elem in elements {
            assert_eq!(elem.n, n, "all ring elements must have same dimension");
            all_slots.extend_from_slice(&Self::ring_to_ntt_slots(elem));
        }

        // Pad to power of 2
        let total = all_slots.len().next_power_of_two();
        all_slots.resize(total, Goldilocks::ZERO);

        MultilinearPoly::new(all_slots)
    }

    /// Commit to a batch of ring elements.
    pub fn commit_rings(elements: &[RingElement]) -> (Commitment, MultilinearPoly<Goldilocks>) {
        let poly = Self::batch_rings(elements);
        let commitment = Brakedown::commit(&poly);
        (commitment, poly)
    }
}

/// Ikat delegates to Brakedown for the base Lens operations.
/// The ring-awareness is in how data enters the system (via ring_to_ntt_slots
/// and batch_rings), not in the commit/open/verify mechanics.
impl Lens<Goldilocks> for Ikat {
    fn commit(poly: &MultilinearPoly<Goldilocks>) -> Commitment {
        Brakedown::commit(poly)
    }

    fn open(
        poly: &MultilinearPoly<Goldilocks>,
        point: &[Goldilocks],
        transcript: &mut Transcript,
    ) -> Opening {
        Brakedown::open(poly, point, transcript)
    }

    fn verify(
        commitment: &Commitment,
        point: &[Goldilocks],
        value: Goldilocks,
        proof: &Opening,
        transcript: &mut Transcript,
    ) -> bool {
        Brakedown::verify(commitment, point, value, proof, transcript)
    }

    fn batch_open(
        poly: &MultilinearPoly<Goldilocks>,
        points: &[(Vec<Goldilocks>, Goldilocks)],
        transcript: &mut Transcript,
    ) -> Opening {
        Brakedown::batch_open(poly, points, transcript)
    }

    fn batch_verify(
        commitment: &Commitment,
        points: &[(Vec<Goldilocks>, Goldilocks)],
        proof: &Opening,
        transcript: &mut Transcript,
    ) -> bool {
        Brakedown::batch_verify(commitment, points, proof, transcript)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ntt_slots_roundtrip() {
        // Create a ring element, convert to NTT slots, verify dimensions
        let mut elem = RingElement::new(1024);
        elem.coeffs[0] = Goldilocks::new(1);
        elem.coeffs[1] = Goldilocks::new(2);

        let slots = Ikat::ring_to_ntt_slots(&elem);
        assert_eq!(slots.len(), 1024);
    }

    #[test]
    fn batch_rings_power_of_two() {
        let elem1 = RingElement::new(1024);
        let elem2 = RingElement::new(1024);
        let poly = Ikat::batch_rings(&[elem1, elem2]);
        assert!(poly.len().is_power_of_two());
        assert!(poly.len() >= 2048); // 2 elements ร— 1024 slots
    }

    #[test]
    fn commit_rings_works() {
        let mut elem = RingElement::new(1024);
        elem.coeffs[0] = Goldilocks::new(42);
        let (commitment, poly) = Ikat::commit_rings(&[elem]);

        // Commitment should be deterministic
        let mut elem2 = RingElement::new(1024);
        elem2.coeffs[0] = Goldilocks::new(42);
        let (commitment2, _) = Ikat::commit_rings(&[elem2]);
        assert_eq!(commitment, commitment2);

        // Should be verifiable via normal Lens interface
        let point = vec![Goldilocks::ZERO; poly.num_vars];
        let value = poly.evaluate(&point);

        let mut pt = Transcript::new(b"ikat-ring");
        let proof = Ikat::open(&poly, &point, &mut pt);
        let mut vt = Transcript::new(b"ikat-ring");
        assert!(Ikat::verify(&commitment, &point, value, &proof, &mut vt));
    }

    #[test]
    fn ikat_brakedown_equivalence_on_raw_poly() {
        // For raw multilinear polys, Ikat and Brakedown are identical
        let evals: Vec<Goldilocks> = (0..16).map(|i| Goldilocks::new(i + 1)).collect();
        let poly = MultilinearPoly::new(evals);
        assert_eq!(Ikat::commit(&poly), Brakedown::commit(&poly));
    }

    #[test]
    fn roundtrip_4var() {
        let evals: Vec<Goldilocks> = (0..16).map(|i| Goldilocks::new(i * 7 + 5)).collect();
        let poly = MultilinearPoly::new(evals);
        let point: Vec<Goldilocks> = (0..4).map(|i| Goldilocks::new(i + 2)).collect();
        let commitment = Ikat::commit(&poly);
        let value = poly.evaluate(&point);

        let mut pt = Transcript::new(b"ikat-4");
        let proof = Ikat::open(&poly, &point, &mut pt);
        let mut vt = Transcript::new(b"ikat-4");
        assert!(Ikat::verify(&commitment, &point, value, &proof, &mut vt));
    }
}

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/bbg/rs/src/lib.rs
soft3/radio/iroh-docs/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