You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Speculative. No current user driver — filed during a 2026-05-04 audit while closing #551 (originally framed as a soundness fix; turned out to be checker-prevented).
What this would change
Today vera/types.py:132 defines NUMERIC_TYPES = frozenset({INT, NAT, FLOAT64}) — Byte is deliberately not in that set. The arithmetic check at vera/checker/expressions.py:252 (binary) and :384 (unary negation) rejects any operand whose base type isn't in NUMERIC_TYPES. Refinement-type aliases (type MyByte = { @Byte | true }) don't bypass — base_type() strips refinements before the check. So @Byte + @Byte, @Byte - @Byte, @Byte * @Byte, -@Byte, etc. all produce E140 at type-check time.
Allowing Byte arithmetic would mean:
Widen NUMERIC_TYPES to include BYTE.
Verifier obligations on Byte: underflow (lhs >= rhs for sub) AND overflow (lhs + rhs <= 255 for add, lhs * rhs <= 255 for mul). Both directions, because Byte is [0, 255] (closed range, unlike Nat which is [0, ∞)).
Spec updates: spec/04 §4.4 and spec/11 §11.2.1 need to extend the unsigned-arithmetic obligation language from Nat-only to Nat + Byte, with the upper-bound case spelled out.
Tests: parameterise the existing TestNatSubtractionObligation520 and TestNatSubtractionRuntimeGuard520 tests over both types, plus add overflow-guard tests for ADD and MUL.
Why this is speculative (no current driver)
The day-to-day Vera use cases that could need byte arithmetic — base64 / URL / hex encoding, JSON char classification, HTML escape, parser lookup tables — are already implemented in the standard library as host imports (base64_encode, url_encode, etc., written in Python/JS). User code calls those, not byte primitives. The byte_to_int → @Int arithmetic → int_to_byte round-trip handles the rare custom case verbosely but correctly.
The use cases where byte arithmetic would be idiomatic but currently is not:
Custom parsers for binary formats (network protocols, image data, file headers). Not currently in scope for Vera; agents writing parsers today reach for stdlib (CSV parsing and generation #236 CSV, JSON, etc.) or call out to host code.
Character math ('a' + 1 == 'b', ASCII case folding). Vera uses string_char_code which returns @Nat — already in Nat-arithmetic land, no Byte involvement.
Hash / checksum / XOR primitives. Cryptography is deliberately out of scope today (Cryptographic hashing (SHA-256, HMAC) #235 tracker). Even if it lands, primitives might be exposed as host imports rather than Vera-level byte ops.
Color / pixel arithmetic (RGBA blend, alpha). Niche; no Vera precedent.
Trade-offs
Pros:
LLM agents porting b1 - b2 from Rust/Go/C don't need byte_to_int noise in the translation.
Eliminates the round-trip-bug class (byte_to_int(int_to_byte(...)) patterns).
@Byte subtraction silent underflow (follow-up to #520) #551 — Closed as not-a-bug; the original "Byte underflow soundness hole" framing turned out to be checker-prevented. This issue captures the speculative feature the original was conflated with.
Speculative. No current user driver — filed during a 2026-05-04 audit while closing #551 (originally framed as a soundness fix; turned out to be checker-prevented).
What this would change
Today
vera/types.py:132definesNUMERIC_TYPES = frozenset({INT, NAT, FLOAT64})—Byteis deliberately not in that set. The arithmetic check atvera/checker/expressions.py:252(binary) and:384(unary negation) rejects any operand whose base type isn't inNUMERIC_TYPES. Refinement-type aliases (type MyByte = { @Byte | true }) don't bypass —base_type()strips refinements before the check. So@Byte + @Byte,@Byte - @Byte,@Byte * @Byte,-@Byte, etc. all produceE140at type-check time.Allowing
Bytearithmetic would mean:NUMERIC_TYPESto includeBYTE.Byte: underflow (lhs >= rhsfor sub) AND overflow (lhs + rhs <= 255for add,lhs * rhs <= 255for mul). Both directions, becauseByteis[0, 255](closed range, unlikeNatwhich is[0, ∞)).Byte: lower bound (mirrorNatunderflow guard from Nat subtraction silently underflows to negative i64 — refinement-type soundness hole #520, buti32.lt_usinceByteis unsigned i32 in WASM) AND upper bound (compare against 255 after widening to i64 to avoid intermediatei32overflow).spec/04 §4.4andspec/11 §11.2.1need to extend the unsigned-arithmetic obligation language fromNat-only toNat+Byte, with the upper-bound case spelled out.TestNatSubtractionObligation520andTestNatSubtractionRuntimeGuard520tests over both types, plus add overflow-guard tests for ADD and MUL.Why this is speculative (no current driver)
The day-to-day Vera use cases that could need byte arithmetic — base64 / URL / hex encoding, JSON char classification, HTML escape, parser lookup tables — are already implemented in the standard library as host imports (
base64_encode,url_encode, etc., written in Python/JS). User code calls those, not byte primitives. Thebyte_to_int→@Intarithmetic →int_to_byteround-trip handles the rare custom case verbosely but correctly.The use cases where byte arithmetic would be idiomatic but currently is not:
'a' + 1 == 'b', ASCII case folding). Vera usesstring_char_codewhich returns@Nat— already inNat-arithmetic land, no Byte involvement.Trade-offs
Pros:
b1 - b2from Rust/Go/C don't needbyte_to_intnoise in the translation.byte_to_int(int_to_byte(...))patterns).@Nat's unsigned arithmetic story (Nat subtraction silently underflows to negative i64 — refinement-type soundness hole #520).Cons:
requiressurface for every binary operator. Adds verifier complexity.<= 255clamp; need careful widening to i64 inside the guard.Byte + Int) still needs conversions, so it doesn't fully eliminate conversion noise.u8(where wrap is silent and well-defined).Trigger condition
Open this issue when:
byte_to_intround-trips on byte-heavy benchmarks.Until one of those signals appears, the current design (Byte excluded from arithmetic) is the right call for Vera's LLM-target audience.
Action when the time comes
@Natconvention), saturate (clamp to 0/255), or wrap (C / Rustu8style).NUMERIC_TYPESinvera/types.py:132to includeBYTE._is_unsigned_typed/_has_nat_origininvera/verifier.py(rename or parameterise)._is_static_nat_typed/_has_nat_origin_codegeninvera/wasm/operators.py.+and*:lhs + rhs <= 255,lhs * rhs <= 255.+and*in addition to-.TestNatSubtractionObligation520andTestNatSubtractionRuntimeGuard520over Nat + Byte.Related
@Natsubtraction underflow (parent — the architecture this would extend).@Natinvariant check to all binding sites. If Byte arithmetic lands, the same generalisation extends.