Skip to content

Commit 15bbbc5

Browse files
authored
Merge pull request #1242 from cipherstash/feat/stack-encrypt-order-keys
feat(stack-encrypt)!: derive every order term over its ADR-0002 order key, and order floats
2 parents 9c65e7e + 36271cb commit 15bbbc5

28 files changed

Lines changed: 698 additions & 96 deletions

‎languages/golang/CHANGELOG.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,14 @@ listed under **Breaking**. Releases are tagged `languages/golang/vX.Y.Z`.
9292
`index=ope` gets `Lt`, `Lte`, `Gt`, `Gte` and `Between`. Text orders by its
9393
folded form (ADR-0002: case and accents folded, under Unicode 16), so
9494
`Café` and `cafe` tie and `alice` orders before `Zoe`.
95+
- **Ordering methods on floats.** A `float32` or `float64` field with
96+
`index=ore` or `index=ope` gets `Lt`, `Lte`, `Gt`, `Gte` and `Between`.
97+
Floats order as PostgreSQL's `float8` does (ADR-0002): `-0.0` ties `0.0`,
98+
and every NaN is one value, above `+Inf`. A `float32` orders as the
99+
`float64` it widens to.
95100
- **stashgen notices an index no generated method queries**: an `ore` or
96-
`ope` index on bytes or a float (the engine answers the orderings over
97-
integers and text only), or the second of two order indexes on a field.
101+
`ope` index on bytes (the engine answers the orderings over integers,
102+
floats and text only), or the second of two order indexes on a field.
98103
The index is still stored; the notice is on stderr and in the file.
99104

100105
### Changed

‎languages/golang/cmd/stashgen/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ For `-type User`, the file `user_stash.go` holds:
124124
- `Fields`, with one entry for each sealed field.
125125
An opaque struct, or a struct with no sealed field outside an opaque one, gets no `Fields`: nothing in it is sealed on its own, so nothing can be queried.
126126
An entry encrypts one value, and has one query method for each operator the engine answers on the field: `Eq`, `Lt`, `Lte`, `Gt`, `Gte`, `Between` or `Matches`.
127-
stashgen asks the embedded engine which operators each field answers, and which index answers each one, so it holds no copy of those rules: an equality index answers `Eq`, a match index on a string `Matches`, and an ORE or OPE index on an integer or a string the four orderings and `Between`, through ORE when the field declares both. A string orders by its folded form: case and accents folded, under Unicode 16.
127+
stashgen asks the embedded engine which operators each field answers, and which index answers each one, so it holds no copy of those rules: an equality index answers `Eq`, a match index on a string `Matches`, and an ORE or OPE index on an integer, a float or a string the four orderings and `Between`, through ORE when the field declares both. A float orders as PostgreSQL's `float8` does (`-0.0` ties `0.0`, NaN sorts last), and a string by its folded form: case and accents folded, under Unicode 16.
128128
`encrypt_into=TextEq` answers `Eq`, which returns the type's query value, `eql.TextEqQuery`.
129129
`encrypt_into=TextMatch` answers `Matches`, which returns an `encrypt.EQLMatchQuery`: the `eql.TextMatchQuery` operand, with `Verify` and `TargetLimit`.
130130
The query of `Matches` carries `Verify` and `TargetLimit`, because its answer can hold rows that do not match; an exact operator's query carries neither.

‎languages/golang/encrypt/README.md‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,14 @@ or a type defined over one (`type Email string`):
236236
| `uint16`, `uint32`, `uint64`, `uint` | the same, unsigned | `equality`, `ore`, `ope` | the same |
237237
| `int8`, `uint8` (`byte`) | an 8-bit integer | `equality` | `Eq` |
238238
| `encrypt.Int128`, `encrypt.Uint128` | a 128-bit integer | `equality`, `ore`, `ope` | the same |
239-
| `float32`, `float64` | a float of its width | `equality`, `ore`, `ope` | `Eq` |
239+
| `float32`, `float64` | a float of its width | `equality`, `ore`, `ope` | `Eq`, `Lt`, `Lte`, `Gt`, `Gte`, `Between` |
240240
| `encrypt.Decimal` | a decimal: a 96-bit coefficient and a scale up to 28 | `equality` | `Eq` |
241241
| `encrypt.Date` | a calendar date | `equality` | `Eq` |
242242
| `time.Time` | a timestamp, to the nanosecond, in UTC | `equality` | `Eq` |
243243
244244
Each query method needs its index declared. An `ore` or `ope` index on bytes
245-
or a float stores its term, but the engine answers no ordering through it
246-
yet, so such a field has no `Lt` (see [Queries](#queries)).
245+
stores its term, but the engine answers no ordering through it, so such a
246+
field has no `Lt` (see [Queries](#queries)).
247247
248248
`encrypt.Date`, `Int128`, `Uint128` and `Decimal` are vitaminc's `vcvalue`
249249
types; build them with `encrypt.DateOf`, `ParseInt128`, `ParseUint128` and
@@ -261,8 +261,8 @@ a few known rows resolve to the values, as a `bool`'s would say which rows
261261
are true. Equality follows vitaminc's normalisation: an
262262
integer equals itself at every width, decimals compare at any scale
263263
(`1.50 = 1.5`), and a timestamp compares to the microsecond. An order index on
264-
a decimal, date or timestamp is refused for now: those order terms wait for
265-
new cllw-ore and ore-rs releases (#1236).
264+
a decimal, date or timestamp is refused for now: the engine derives no
265+
order term for those kinds yet.
266266
267267
A `match` index stores text with no token (an empty string, separator-only
268268
text, or text shorter than the n-gram length of 3 characters) as the empty
@@ -320,7 +320,12 @@ range matches nothing. So `Between("b", "A")` matches nothing, since `A`
320320
folds to `a`, below `b`. Text holding a code point Unicode 16 does not assign has no
321321
fold, and its query or write is refused with `encrypt.ErrTerm`.
322322
323-
An order index on bytes or a float stores its term but answers no ordering
323+
Floats order as PostgreSQL's `float8` does (ADR-0002): `-0.0` and `0.0` are
324+
one value, and every NaN is one value, above `+Inf`, so `Between(math.NaN(),
325+
math.Inf(1))` matches nothing. A `float32` orders as the `float64` it
326+
widens to.
327+
328+
An order index on bytes stores its term but answers no ordering
324329
operator, so such a field has no `Lt`; nor does the `ope` index of a field
325330
that declares `ore` too, since `ore` answers the orderings. stashgen prints a notice for each such index, on stderr and in
326331
the generated file: the terms are stored, and only your own code can compare

‎languages/golang/encrypt/doc.go‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,10 @@
154154
// Eq returns an [EqualityTerm] (or, for a field with encrypt_into, the EQL
155155
// type's query value), an ordering an [OreTerm] or [OpeTerm], and Between a
156156
// [Range] of two. Their answers are exact. The orderings are answered on
157-
// integers and on text, which orders by its folded form (case and accents
158-
// folded, under Unicode 16), so Café and cafe tie and alice orders before
159-
// Zoe. Matches returns a [MatchQuery],
157+
// integers, on floats, which order as PostgreSQL's float8 does (-0.0 ties
158+
// 0.0, NaN sorts last), and on text, which orders by its folded form (case
159+
// and accents folded, under Unicode 16), so Café and cafe tie and alice
160+
// orders before Zoe. Matches returns a [MatchQuery],
160161
// whose answer can hold rows that do not match: size the fetch with
161162
// [MatchQuery.TargetLimit], then decrypt the rows and keep those
162163
// [MatchQuery.Verify] reports true, one call into the engine for the page.

‎languages/golang/encrypt/internal/testusers/kinds_stash.go‎

Lines changed: 25 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎languages/golang/encrypt/internal/testusers/probe_stash.go‎

Lines changed: 132 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)