vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Specification for the `decode.base64` operation.
use crate::{Convention, DataType, OpSignature, OpSpec};

/// Location-agnostic operation metadata.
pub const VYRE_OP_METADATA: vyre_spec::OpMetadata = vyre_spec::OpMetadata {
    id: "decode.base64",
    layer: vyre_spec::Layer::L2,
    category: vyre_spec::MetadataCategory::A,
    version: 1,
    description: "decode base64",
    signature: "(Bytes) -> Bytes",
    strictness: "strict",
    archetype_signature: "(Bytes) -> Bytes",
};

/// Golden samples for this op.
pub const GOLDEN: &[vyre_spec::GoldenSample] = &[vyre_spec::GoldenSample {
    op_id: "decode.base64",
    input: b"",
    expected: b"",
    reason: "empty input round-trips to empty output (RFC 4648 §4)",
}];

/// Known-answer tests for this op, derived from RFC 4648 §10 test vectors.
pub const KAT: &[vyre_spec::KatVector] = &[
    vyre_spec::KatVector {
        input: b"",
        expected: b"",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"Zg==",
        expected: b"f",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"Zm8=",
        expected: b"fo",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"Zm9v",
        expected: b"foo",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"Zm9vYg==",
        expected: b"foob",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"Zm9vYmE=",
        expected: b"fooba",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"Zm9vYmFy",
        expected: b"foobar",
        source: "RFC 4648 §10",
    },
    vyre_spec::KatVector {
        input: b"c3VyZS4=",
        expected: b"sure.",
        source: "hand-verified canonical padding",
    },
    vyre_spec::KatVector {
        input: b"c3VyZQ==",
        expected: b"sure",
        source: "hand-verified double-padding",
    },
    vyre_spec::KatVector {
        input: b"c3Vy",
        expected: b"sur",
        source: "hand-verified no-padding",
    },
    vyre_spec::KatVector {
        input: b"c3U=",
        expected: b"su",
        source: "hand-verified single-padding",
    },
    vyre_spec::KatVector {
        input: b"cw==",
        expected: b"s",
        source: "hand-verified double-padding short input",
    },
];

/// Adversarial inputs for this op.
pub const ADVERSARIAL: &[vyre_spec::AdversarialInput] = &[
    vyre_spec::AdversarialInput {
        input: b"",
        reason: "empty input exercises the zero-length branch",
    },
    vyre_spec::AdversarialInput {
        input: b"A",
        reason: "single character without padding — not a complete base64 quartet",
    },
    vyre_spec::AdversarialInput {
        input: b"!!!!",
        reason: "non-alphabet characters must be rejected or skipped, never mapped to zero",
    },
    vyre_spec::AdversarialInput {
        input: b"====",
        reason: "all-padding input has no payload bytes",
    },
    vyre_spec::AdversarialInput {
        input: b"AAAA" as &[u8],
        reason: "all-zero nibbles produce three zero bytes — byte-count invariant check",
    },
];

/// Build the OpSpec for this decode operation.
#[inline]
pub fn vyre_op() -> OpSpec {
    let id = "decode.base64";
    OpSpec::builder(id)
        .signature(OpSignature {
            inputs: vec![DataType::Bytes],
            output: DataType::Bytes,
        })
        .cpu_fn(cpu_fn)
        .wgsl_fn(wgsl_fn)
        .category(crate::Category::A {
            composition_of: vec![id],
        })
        .laws(vec![crate::spec::law::AlgebraicLaw::Bounded {
            lo: 0,
            hi: u32::MAX,
        }])
        .strictness(crate::spec::types::Strictness::Strict)
        .version(1)
        .alt_wgsl_fns(vec![("category_a_handwritten", wgsl_fn)])
        .convention(Convention::V1)
        .boundary_values(vec![
            crate::spec::types::BoundaryValue {
                label: "empty",
                inputs: vec![0],
            },
            crate::spec::types::BoundaryValue {
                label: "single_element",
                inputs: vec![1],
            },
            crate::spec::types::BoundaryValue {
                label: "boundary",
                inputs: vec![255],
            },
            crate::spec::types::BoundaryValue {
                label: "max",
                inputs: vec![u32::MAX],
            },
        ])
        .equivalence_classes(vec![
            crate::spec::types::EquivalenceClass::specific("empty input", vec![0]),
            crate::spec::types::EquivalenceClass::specific("typical input", vec![42]),
            crate::spec::types::EquivalenceClass::specific("boundary input", vec![255]),
        ])
        .spec_table(crate::spec::tables::base64::ROWS)
        .expect("Fix: checked-in conform spec must satisfy the typestate builder")
}

/// CPU reference implementation.
#[inline]
pub fn cpu_fn(input: &[u8]) -> Vec<u8> {
    let mut output = Vec::new();
    let mut cursor = 0;
    while cursor < input.len() {
        if !is_base64_char(input[cursor]) || (cursor > 0 && is_base64_char(input[cursor - 1])) {
            cursor += 1;
            continue;
        }
        let start = cursor;
        let mut end = start;
        while end < input.len() && is_base64_char(input[end]) {
            end += 1;
        }
        let usable_len = (end - start) - ((end - start) % 4);
        if usable_len >= 4 {
            decode_run(input, start, usable_len, &mut output);
        }
        cursor = end;
    }
    output
}

fn decode_run(input: &[u8], start: usize, usable_len: usize, output: &mut Vec<u8>) {
    let mut quartet = start;
    while quartet + 4 <= start + usable_len {
        let Some(a) = base64_value(input[quartet]) else {
            break;
        };
        let Some(b) = base64_value(input[quartet + 1]) else {
            break;
        };
        let packed = (u32::from(a) << 18) | (u32::from(b) << 12);
        output.push((packed >> 16) as u8);
        match (
            base64_value(input[quartet + 2]),
            base64_value(input[quartet + 3]),
        ) {
            (Some(c), Some(d)) => {
                let packed = packed | (u32::from(c) << 6) | u32::from(d);
                output.push((packed >> 8) as u8);
                output.push(packed as u8);
            }
            (Some(c), None) => {
                output.push(((packed | (u32::from(c) << 6)) >> 8) as u8);
                break;
            }
            (None, _) => break,
        }
        quartet += 4;
    }
}

fn base64_value(value: u8) -> Option<u8> {
    match value {
        b'A'..=b'Z' => Some(value - b'A'),
        b'a'..=b'z' => Some(value - b'a' + 26),
        b'0'..=b'9' => Some(value - b'0' + 52),
        b'+' => Some(62),
        b'/' => Some(63),
        b'=' => None,
        _ => None,
    }
}

fn is_base64_char(value: u8) -> bool {
    base64_value(value).is_some() || value == b'='
}

/// WGSL shader source.
#[inline]
pub fn wgsl_fn() -> String {
    r#"
fn b64_value(value: u32) -> i32 {
    if (value >= 65u && value <= 90u) { return i32(value - 65u); }
    if (value >= 97u && value <= 122u) { return i32(value - 71u); }
    if (value >= 48u && value <= 57u) { return i32(value + 4u); }
    if (value == 43u) { return 62; }
    if (value == 47u) { return 63; }
    if (value == 61u) { return -2; }
    return -1;
}

fn vyre_op(index: u32, input_len: u32) -> u32 {
    let quartet = (index / 3u) * 4u;
    if (quartet + 3u >= input_len) { return 0u; }
    let a = max(b64_value(input.data[quartet]), 0);
    let b = max(b64_value(input.data[quartet + 1u]), 0);
    let c = max(b64_value(input.data[quartet + 2u]), 0);
    let d = max(b64_value(input.data[quartet + 3u]), 0);
    let packed = (u32(a) << 18u) | (u32(b) << 12u) | (u32(c) << 6u) | u32(d);
    let slot = index % 3u;
    if (slot == 0u) { return (packed >> 16u) & 255u; }
    if (slot == 1u) { return (packed >> 8u) & 255u; }
    return packed & 255u;
}
"#
    .to_string()
}