Skip to content

stack-encrypt refactor: remove transitional traits and redundant execution APIs #1488

Open

Description

@coderdan

Background

Stack Encrypt (packages/stack-encrypt) is the Rust engine that every CipherStash language SDK runs on. It has two Rust APIs side by side on next:

  • The new API. Owned conversions through EncryptTarget and DecryptSource, and paired entry points such as keyset.encrypt(..) and keyset.encrypt_with_context(..) (feat(stack-encrypt): add owned scalar ciphertext API #1404).
  • The old API. EncryptFrom, DecryptInto, encrypt_as, the helpers in target::legacy, and the plan chain in plan/chain.rs, with its .context(..), .extend(..), and .keyset(..) steps.

The Stack Encrypt API plan, merged in pull request #1365, keeps the new API and removes the old one.

Problem

Two APIs for the same job make the right one hard to find. The chain also causes real defects. A context part added late in a chain can replace an earlier one (#1120). Rust then builds a different context from Go, and a query finds nothing.

Proposal

The plan items "One context argument, and paired entry points" and "Remove the structural API" describe the work.

  1. Add Planned::new(&plan, value), with encrypt, encrypt_with_context, decrypt, and decrypt_with_context. It replaces the chain in plan/chain.rs and every chain state.
  2. Pass context as one argument, built from Scope and Bind values. The type fixes the order: scopes, then bindings.
  3. Choose the keyset first. It is the receiver of the scalar entry points, and the argument of every other verb, as in encrypt(&keyset). There is no using method.
  4. Check a stored context part passed on decrypt against the row before any key is fetched. ExpectedContext does this today. It stops being a public type.
  5. Replace the CipherScope trait and the dynamic::Scope enum with one borrowed value, CipherRef<'c, K>. Both reduce to a connection and an optional keyset ID. Build it with From<&Cipher> and From<&Keyset>. Entry points take impl Into<CipherRef>. A Keyset reference refuses a leaf from another keyset with ForeignKeyset. A Cipher reference opens leaves from any keyset the client can use.
  6. Remove EncryptFrom, DecryptInto, encrypt_as, and target::legacy.
  7. Remove the old context path type Label and IntoLabel. A plan's context is its declared Scope parts, and the guest sends parts, not a path.
  8. Rename the plan builder's output method from build() to target.
  9. Move EQL, the Go guest, and every example to the new API in the same change.

encrypt_tree and decrypt_tree stay, as explicit structural operations.

Acceptance

Do not add aliases only to keep the unpublished prototype names. Account for any contract a customer already depends on.

Relationship to other work

Plans: the Stack Encrypt API plan and the conformance roadmap.

Activity

  1. self-assigned this
    on Nov 1, 2026
  2. coderdan commented on Nov 9, 2026

    @coderdan
    ContributorAuthor

    Pull request #1597 is the first part of this issue: Planned is now the one lowering of a data plan (compose and opening in dynamic::planned), and the plan builder is out of the dynamic path. It closes #1120, whose fix had already landed. Still to do here, in the pull requests that follow: remove the plan chain and builder (plan/chain.rs, plan/build.rs, plan/value.rs, plan/field_ref.rs, pick!), EncryptFrom, DecryptInto, encrypt_as and target::legacy; replace CipherScope and dynamic::Scope with CipherRef; make ExpectedContext private; remove Label and IntoLabel; and move EQL, the Go guest and the examples to the new API. The field markers (#1595) are the typed query those removals need; #1596 lists the operator methods they still lack, which must land before the chain goes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions