Background
An equality term is a keyed hash (a PRF, pseudorandom function) of a
value. The database compares hashes to answer = without decrypting.
vitaminc-prf defines the byte input for each type, with a domain label so
that different types never hash the same input.
Problem
Date, Timestamp, Decimal, the new integer widths, floats and Bool
have no equality domain. Stack Encrypt refuses equality for floats
(packages/stack-encrypt/src/dynamic/term.rs:390-397).
- The kind-to-type dispatch lives in Stack Encrypt (
Scalar), not here.
- The existing writer, cipherstash-client, hashes a timestamp's milliseconds
but orders by nanoseconds, and hashes a decimal with its scale while
ordering ignores it. So equality and ordering disagree about which values
are equal.
Proposal
- Hash each kind's canonical form, which is also the input to its order term:
Timestamp: truncated to microseconds.
Decimal: scale normalised. NaN and ±Infinity are refused (rust_decimal
can't represent them).
- Floats:
-0.0 folded into +0.0, every NaN replaced by one positive
NaN.
- Text: NFC, pinned to a Unicode version that is part of the domain label
(for example text-nfc/unicode-16/v1). Strings with unassigned code
points are refused.
- No equality domain for
Bool. A hash over two values splits the rows into
two groups and hides nothing.
- Derive equality terms from
&Value, with one exhaustive match that keeps
leaves inside Protected. An unsupported kind returns a typed error.
- Known-answer tests for every domain.
Gate: using the canonical order bytes as the PRF input needs written
sign-off before this merges.
Needs #372. Decided in ADR-0002 (cipherstash/stack#1139). Predecessor: #275.
Background
An equality term is a keyed hash (a PRF, pseudorandom function) of a
value. The database compares hashes to answer
=without decrypting.vitaminc-prfdefines the byte input for each type, with a domain label sothat different types never hash the same input.
Problem
Date,Timestamp,Decimal, the new integer widths, floats andBoolhave no equality domain. Stack Encrypt refuses equality for floats
(
packages/stack-encrypt/src/dynamic/term.rs:390-397).Scalar), not here.but orders by nanoseconds, and hashes a decimal with its scale while
ordering ignores it. So equality and ordering disagree about which values
are equal.
Proposal
Timestamp: truncated to microseconds.Decimal: scale normalised. NaN and ±Infinity are refused (rust_decimalcan't represent them).
-0.0folded into+0.0, every NaN replaced by one positiveNaN.
(for example
text-nfc/unicode-16/v1). Strings with unassigned codepoints are refused.
Bool. A hash over two values splits the rows intotwo groups and hides nothing.
&Value, with one exhaustive match that keepsleaves inside
Protected. An unsupported kind returns a typed error.Gate: using the canonical order bytes as the PRF input needs written
sign-off before this merges.
Needs #372. Decided in ADR-0002 (cipherstash/stack#1139). Predecessor: #275.