Skip to content

Stack Encrypt cannot order floats, dates, timestamps or decimals, and its integer order keys predate ADR-0002: derive every order term over vitaminc-ore #1236

Closed

Description

@coderdan

Background

Stack Encrypt is CipherStash's Rust encryption engine, also used by the Go SDK and data plans. Next to a ciphertext it can store order terms, which let the database answer <, >, BETWEEN and ORDER BY without decrypting. There are two schemes: ORE (order-revealing encryption) and OPE (order-preserving encryption, compared as plain bytes). ADR-0002 (accepted) says how each kind of value is turned into an order key before it is encrypted, and vitaminc 0.6 ships those encodings in vitaminc-ore.

Problem

  1. Floats, dates, timestamps and decimals cannot be ordered. The ordering operators (Lt, Lte, Gt, Gte, Between) are answered only on integers, plus text once Stack Encrypt cannot order text: answer Lt, Gt and Between on text over ADR-0002's folded order key #1234 lands. That holds on the typed path (op::Ordered, packages/stack-encrypt/src/op/mod.rs:381) and on the data-plan path (ordered(kind), packages/stack-encrypt/src/dynamic/query.rs:193). A float64 field with an order index stores terms nothing can query.
  2. Integer order terms don't follow ADR-0002. They come from cllw-ore's own integer encoding (OreTerm<T: CllwOreEncrypt>, packages/stack-encrypt/src/sem/mod.rs:1113), not vitaminc-ore's. ADR-0002 notes the two differ, and wants an integer column's key at the column's declared width so values from every language land in one domain.

Impact: about 13 EQL v4 types (the *Ord and *OrdOpe types of the integer, bigint, real, double, date, timestamp and numeric families) stay unproducible. That is because the engine cannot derive their order terms the way ADR-0002 says, and not because the encryption scheme is missing.

Proposal

Unblocked for CLLW ORE and OPE (2026-10-18). The ORE crates own how each type is encoded for ordering. cllw-ore 0.5.2-rc.1, a pre-release, implements vitaminc-ore 0.6's OrderScheme behind its vitaminc feature and uses its encodings internally: the integer at its declared width, the canonical float (-0.0 as +0.0, one NaN above +Infinity), and text's fold. Stack Encrypt passes each value through and names its type's target. Block ORE still waits on an ore-rs release (#1132).

With the crate available:

  1. Take cllw-ore 0.5.2-rc.1 with the vitaminc feature, and pass every value straight to its scheme. Integer order terms change bytes; none are deployed (ADR-0002).
  2. Answer the ordering operators on floats: op::Ordered for f64, and the data path's float32 and float64 fields. An f32 is ordered as the f64 it widens to: its target is F64, which vitaminc widens exactly. Between's inverted-range refusal compares the bounds in the crate's order. Dates, timestamps and decimals follow once those kinds exist (Go SDK: int16 is widened to Int32, and there's no way to encrypt a date, timestamp, decimal or 128-bit integer #1144, stashgen refuses every number, date and boolean EQL type — produce them in EQL v4 using ADR-0002's encodings #1130).
  3. Pin the term bytes per kind in fixtures that the typed and data-plan paths both match, and prove the order across kinds: -0.0 == 0.0, and NaN sorting last.

#1242 implements this. It was reworked on 2026-10-18 on top of #1235 to pass values straight through cllw-ore's vitaminc schemes; its first draft encoded vitaminc-ore keys in Stack Encrypt in front of cllw-ore 0.5. Its tests (float order, the cross-path fixture, the Go property tests) carried over.

Relationship to other work

Activity

  1. added
    enhancementNew feature or request
    rustPull requests that update Rust code
    on Oct 17, 2026
  2. coderdan commented on Oct 18, 2026

    @coderdan
    ContributorAuthor

    #1242 covers part of this issue: floats now order over vitaminc-ore (f32/f64 at cllw-ore's F64 target, ordered as PostgreSQL's float8 does), and #1235 moved every integer and text order term onto cllw-ore's vitaminc schemes. #1242 no longer closes this issue.

    Still open here:

    • ordering dates;
    • ordering timestamps;
    • ordering decimals.
  3. added 3 commits that reference this issue on Oct 19, 2026
    2d97f21
    ea26f9d
    c634933
  4. added
    StagedDone in the next branch; closes when next merges into main
    on Oct 19, 2026
  5. self-assigned this
    on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

SDKStagedDone in the next branch; closes when next merges into mainenhancementNew feature or requestrustPull requests that update Rust code

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions