Skip to content

Commit e274bb1

Browse files
committed
Add cs_ste_vec_value_v1, cs_ste_vec_term_v1, and cs_ste_vec_terms_v1 to 002-ste-vec.sql
Also add in the SteVec side of variable length ORE fixes.
1 parent df12fc9 commit e274bb1

File tree

1 file changed

+296
-12
lines changed

1 file changed

+296
-12
lines changed

sql/002-ste-vec.sql

Lines changed: 296 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,304 @@
22
---
33
--- SteVec types, functions, and operators
44
---
5-
CREATE TYPE ste_vec_v1_entry AS (
5+
6+
CREATE TYPE cs_ste_vec_encrypted_term_v1 AS (
7+
bytes bytea
8+
);
9+
10+
DROP FUNCTION IF EXISTS compare_ste_vec_encrypted_term_v1(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
11+
12+
CREATE FUNCTION compare_ste_vec_encrypted_term_v1(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1)
13+
RETURNS INT AS $$
14+
DECLARE
15+
header_a INT;
16+
header_b INT;
17+
body_a BYTEA;
18+
body_b BYTEA;
19+
BEGIN
20+
-- `get_byte` is 0-indexed
21+
header_a := get_byte(a.bytes, 0);
22+
header_b := get_byte(b.bytes, 0);
23+
24+
IF header_a != header_b THEN
25+
RAISE EXCEPTION 'compare_ste_vec_encrypted_term_v1: expected equal header bytes';
26+
END IF;
27+
28+
-- `substr` is 1-indexed (yes, `subtr` starts at 1 and `get_byte` starts at 0).
29+
body_a := substr(a.bytes, 2);
30+
body_b := substr(b.bytes, 2);
31+
32+
CASE header_a
33+
WHEN 0 THEN
34+
RAISE EXCEPTION 'compare_ste_vec_encrypted_term_v1: can not compare MAC terms';
35+
WHEN 1 THEN
36+
RETURN compare_ore_cllw_8_v1(ROW(body_a)::ore_cllw_8_v1, ROW(body_b)::ore_cllw_8_v1);
37+
WHEN 2 THEN
38+
RETURN compare_lex_ore_cllw_8_v1(ROW(body_a)::ore_cllw_8_variable_v1, ROW(body_b)::ore_cllw_8_variable_v1);
39+
ELSE
40+
RAISE EXCEPTION 'compare_ste_vec_encrypted_term_v1: invalid header for cs_ste_vec_encrypted_term_v1: header "%", body "%', header_a, body_a;
41+
END CASE;
42+
END;
43+
$$ LANGUAGE plpgsql;
44+
45+
DROP FUNCTION IF EXISTS cs_ste_vec_encrypted_term_eq(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
46+
47+
CREATE FUNCTION cs_ste_vec_encrypted_term_eq(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1) RETURNS boolean AS $$
48+
SELECT __bytea_ct_eq(a.bytes, b.bytes)
49+
$$ LANGUAGE SQL;
50+
51+
DROP FUNCTION IF EXISTS cs_ste_vec_encrypted_term_neq(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
52+
53+
CREATE FUNCTION cs_ste_vec_encrypted_term_neq(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1) RETURNS boolean AS $$
54+
SELECT not __bytea_ct_eq(a.bytes, b.bytes)
55+
$$ LANGUAGE SQL;
56+
57+
DROP FUNCTION IF EXISTS cs_ste_vec_encrypted_term_lt(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
58+
59+
CREATE FUNCTION cs_ste_vec_encrypted_term_lt(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1) RETURNS boolean AS $$
60+
SELECT compare_ste_vec_encrypted_term_v1(a, b) = -1
61+
$$ LANGUAGE SQL;
62+
63+
DROP FUNCTION IF EXISTS cs_ste_vec_encrypted_term_lte(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
64+
65+
CREATE FUNCTION cs_ste_vec_encrypted_term_lte(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1) RETURNS boolean AS $$
66+
SELECT compare_ste_vec_encrypted_term_v1(a, b) != 1
67+
$$ LANGUAGE SQL;
68+
69+
DROP FUNCTION IF EXISTS cs_ste_vec_encrypted_term_gt(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
70+
71+
CREATE FUNCTION cs_ste_vec_encrypted_term_gt(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1) RETURNS boolean AS $$
72+
SELECT compare_ste_vec_encrypted_term_v1(a, b) = 1
73+
$$ LANGUAGE SQL;
74+
75+
DROP FUNCTION IF EXISTS cs_ste_vec_encrypted_term_gte(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
76+
77+
CREATE FUNCTION cs_ste_vec_encrypted_term_gte(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1) RETURNS boolean AS $$
78+
SELECT compare_ste_vec_encrypted_term_v1(a, b) != -1
79+
$$ LANGUAGE SQL;
80+
81+
DROP OPERATOR IF EXISTS = (cs_ste_vec_encrypted_term_v1, cs_ste_vec_encrypted_term_v1);
82+
83+
CREATE OPERATOR = (
84+
PROCEDURE="cs_ste_vec_encrypted_term_eq",
85+
LEFTARG=cs_ste_vec_encrypted_term_v1,
86+
RIGHTARG=cs_ste_vec_encrypted_term_v1,
87+
NEGATOR = <>,
88+
RESTRICT = eqsel,
89+
JOIN = eqjoinsel,
90+
HASHES,
91+
MERGES
92+
);
93+
94+
DROP OPERATOR IF EXISTS <> (cs_ste_vec_encrypted_term_v1, cs_ste_vec_encrypted_term_v1);
95+
96+
CREATE OPERATOR <> (
97+
PROCEDURE="cs_ste_vec_encrypted_term_neq",
98+
LEFTARG=cs_ste_vec_encrypted_term_v1,
99+
RIGHTARG=cs_ste_vec_encrypted_term_v1,
100+
NEGATOR = =,
101+
RESTRICT = eqsel,
102+
JOIN = eqjoinsel,
103+
HASHES,
104+
MERGES
105+
);
106+
107+
DROP OPERATOR IF EXISTS > (cs_ste_vec_encrypted_term_v1, cs_ste_vec_encrypted_term_v1);
108+
109+
CREATE OPERATOR > (
110+
PROCEDURE="cs_ste_vec_encrypted_term_gt",
111+
LEFTARG=cs_ste_vec_encrypted_term_v1,
112+
RIGHTARG=cs_ste_vec_encrypted_term_v1,
113+
NEGATOR = <=,
114+
RESTRICT = scalarltsel,
115+
JOIN = scalarltjoinsel,
116+
HASHES,
117+
MERGES
118+
);
119+
120+
DROP OPERATOR IF EXISTS < (cs_ste_vec_encrypted_term_v1, cs_ste_vec_encrypted_term_v1);
121+
122+
CREATE OPERATOR < (
123+
PROCEDURE="cs_ste_vec_encrypted_term_lt",
124+
LEFTARG=cs_ste_vec_encrypted_term_v1,
125+
RIGHTARG=cs_ste_vec_encrypted_term_v1,
126+
NEGATOR = >=,
127+
RESTRICT = scalargtsel,
128+
JOIN = scalargtjoinsel,
129+
HASHES,
130+
MERGES
131+
);
132+
133+
DROP OPERATOR IF EXISTS >= (cs_ste_vec_encrypted_term_v1, cs_ste_vec_encrypted_term_v1);
134+
135+
CREATE OPERATOR >= (
136+
PROCEDURE="cs_ste_vec_encrypted_term_gte",
137+
LEFTARG=cs_ste_vec_encrypted_term_v1,
138+
RIGHTARG=cs_ste_vec_encrypted_term_v1,
139+
NEGATOR = <,
140+
RESTRICT = scalarltsel,
141+
JOIN = scalarltjoinsel,
142+
HASHES,
143+
MERGES
144+
);
145+
146+
DROP OPERATOR IF EXISTS <= (cs_ste_vec_encrypted_term_v1, cs_ste_vec_encrypted_term_v1);
147+
148+
CREATE OPERATOR <= (
149+
PROCEDURE="cs_ste_vec_encrypted_term_lte",
150+
LEFTARG=cs_ste_vec_encrypted_term_v1,
151+
RIGHTARG=cs_ste_vec_encrypted_term_v1,
152+
NEGATOR = >,
153+
RESTRICT = scalargtsel,
154+
JOIN = scalargtjoinsel,
155+
HASHES,
156+
MERGES
157+
);
158+
159+
DROP OPERATOR FAMILY IF EXISTS cs_ste_vec_encrypted_term_v1_btree_ops USING btree;
160+
161+
CREATE OPERATOR FAMILY cs_ste_vec_encrypted_term_v1_btree_ops USING btree;
162+
163+
DROP OPERATOR CLASS IF EXISTS cs_ste_vec_encrypted_term_v1_btree_ops USING btree;
164+
165+
CREATE OPERATOR CLASS cs_ste_vec_encrypted_term_v1_btree_ops DEFAULT FOR TYPE cs_ste_vec_encrypted_term_v1 USING btree FAMILY cs_ste_vec_encrypted_term_v1_btree_ops AS
166+
OPERATOR 1 <,
167+
OPERATOR 2 <=,
168+
OPERATOR 3 =,
169+
OPERATOR 4 >=,
170+
OPERATOR 5 >,
171+
FUNCTION 1 compare_ste_vec_encrypted_term_v1(a cs_ste_vec_encrypted_term_v1, b cs_ste_vec_encrypted_term_v1);
172+
173+
CREATE TYPE cs_ste_vec_v1_entry AS (
6174
tokenized_selector text,
7-
term ore_cllw_8_v1,
175+
term cs_ste_vec_encrypted_term_v1,
8176
ciphertext text
9177
);
10178

11179
CREATE TYPE cs_ste_vec_index_v1 AS (
12-
entries ste_vec_v1_entry[]
180+
entries cs_ste_vec_v1_entry[]
13181
);
14182

183+
DROP FUNCTION IF EXISTS cs_ste_vec_value_v1(col jsonb, selector jsonb);
184+
185+
-- col: already encrypted payload
186+
-- selector: already encrypted payload
187+
-- returns a value in the format of our custom jsonb schema that will be decrypted
188+
CREATE FUNCTION cs_ste_vec_value_v1(col jsonb, selector jsonb)
189+
RETURNS jsonb AS $$
190+
DECLARE
191+
ste_vec_index cs_ste_vec_index_v1;
192+
target_selector text;
193+
found text;
194+
ignored text;
195+
i integer;
196+
BEGIN
197+
ste_vec_index := cs_ste_vec_v1(col);
198+
target_selector := selector->>'svs';
199+
200+
FOR i IN 1..array_length(ste_vec_index.entries, 1) LOOP
201+
-- The ELSE part is to help ensure constant time operation.
202+
-- The result is thrown away.
203+
IF ste_vec_index.entries[i].tokenized_selector = target_selector THEN
204+
found := ste_vec_index.entries[i].ciphertext;
205+
ELSE
206+
ignored := ste_vec_index.entries[i].ciphertext;
207+
END IF;
208+
END LOOP;
209+
210+
IF found IS NOT NULL THEN
211+
RETURN jsonb_build_object(
212+
'k', 'ct',
213+
'c', found,
214+
'o', NULL,
215+
'm', NULL,
216+
'u', NULL,
217+
'i', col->'i',
218+
'v', 1
219+
);
220+
ELSE
221+
RETURN NULL;
222+
END IF;
223+
END;
224+
$$ LANGUAGE plpgsql;
225+
226+
DROP FUNCTION IF EXISTS cs_ste_vec_terms_v1(col jsonb, selector jsonb);
227+
228+
CREATE FUNCTION cs_ste_vec_terms_v1(col jsonb, selector jsonb)
229+
RETURNS cs_ste_vec_encrypted_term_v1[] AS $$
230+
DECLARE
231+
ste_vec_index cs_ste_vec_index_v1;
232+
target_selector text;
233+
found cs_ste_vec_encrypted_term_v1;
234+
ignored cs_ste_vec_encrypted_term_v1;
235+
i integer;
236+
term_array cs_ste_vec_encrypted_term_v1[];
237+
BEGIN
238+
ste_vec_index := cs_ste_vec_v1(col);
239+
target_selector := selector->>'svs';
240+
241+
FOR i IN 1..array_length(ste_vec_index.entries, 1) LOOP
242+
-- The ELSE part is to help ensure constant time operation.
243+
-- The result is thrown away.
244+
IF ste_vec_index.entries[i].tokenized_selector = target_selector THEN
245+
found := ste_vec_index.entries[i].term;
246+
term_array := array_append(term_array, found);
247+
ELSE
248+
ignored := ste_vec_index.entries[i].term;
249+
END IF;
250+
END LOOP;
251+
252+
RETURN term_array;
253+
END;
254+
$$ LANGUAGE plpgsql;
255+
256+
DROP FUNCTION IF EXISTS cs_ste_vec_term_v1(col jsonb, selector jsonb);
257+
258+
-- col: already encrypted payload
259+
-- selector: already encrypted payload
260+
-- returns a value that can be used for comparison operations
261+
CREATE OR REPLACE FUNCTION cs_ste_vec_term_v1(col jsonb, selector jsonb)
262+
RETURNS cs_ste_vec_encrypted_term_v1 AS $$
263+
DECLARE
264+
ste_vec_index cs_ste_vec_index_v1;
265+
target_selector text;
266+
found cs_ste_vec_encrypted_term_v1;
267+
ignored cs_ste_vec_encrypted_term_v1;
268+
i integer;
269+
BEGIN
270+
ste_vec_index := cs_ste_vec_v1(col);
271+
target_selector := selector->>'svs';
272+
273+
FOR i IN 1..array_length(ste_vec_index.entries, 1) LOOP
274+
-- The ELSE part is to help ensure constant time operation.
275+
-- The result is thrown away.
276+
IF ste_vec_index.entries[i].tokenized_selector = target_selector THEN
277+
found := ste_vec_index.entries[i].term;
278+
ELSE
279+
ignored := ste_vec_index.entries[i].term;
280+
END IF;
281+
END LOOP;
282+
283+
RETURN found;
284+
END;
285+
$$ LANGUAGE plpgsql;
286+
287+
DROP FUNCTION IF EXISTS cs_ste_vec_term_v1(col jsonb);
288+
289+
CREATE FUNCTION cs_ste_vec_term_v1(col jsonb)
290+
RETURNS cs_ste_vec_encrypted_term_v1 AS $$
291+
DECLARE
292+
ste_vec_index cs_ste_vec_index_v1;
293+
BEGIN
294+
ste_vec_index := cs_ste_vec_v1(col);
295+
RETURN ste_vec_index.entries[1].term;
296+
END;
297+
$$ LANGUAGE plpgsql;
298+
15299
-- Determine if a == b (ignoring ciphertext values)
16-
DROP FUNCTION IF EXISTS ste_vec_v1_entry_eq(a ste_vec_v1_entry, b ste_vec_v1_entry);
300+
DROP FUNCTION IF EXISTS cs_ste_vec_v1_entry_eq(a cs_ste_vec_v1_entry, b cs_ste_vec_v1_entry);
17301

18-
CREATE FUNCTION ste_vec_v1_entry_eq(a ste_vec_v1_entry, b ste_vec_v1_entry)
302+
CREATE FUNCTION cs_ste_vec_v1_entry_eq(a cs_ste_vec_v1_entry, b cs_ste_vec_v1_entry)
19303
RETURNS boolean AS $$
20304
DECLARE
21305
sel_cmp int;
@@ -50,17 +334,17 @@ BEGIN
50334
RETURN result;
51335
END IF;
52336
FOR i IN 1..array_length(b.entries, 1) LOOP
53-
intermediate_result := ste_vec_v1_entry_array_contains_entry(a.entries, b.entries[i]);
337+
intermediate_result := cs_ste_vec_v1_entry_array_contains_entry(a.entries, b.entries[i]);
54338
result := result AND intermediate_result;
55339
END LOOP;
56340
RETURN result;
57341
END;
58342
$$ LANGUAGE plpgsql;
59343

60344
-- Determine if a contains b (ignoring ciphertext values)
61-
DROP FUNCTION IF EXISTS ste_vec_v1_entry_array_contains_entry(a ste_vec_v1_entry[], b ste_vec_v1_entry);
345+
DROP FUNCTION IF EXISTS cs_ste_vec_v1_entry_array_contains_entry(a cs_ste_vec_v1_entry[], b cs_ste_vec_v1_entry);
62346

63-
CREATE FUNCTION ste_vec_v1_entry_array_contains_entry(a ste_vec_v1_entry[], b ste_vec_v1_entry)
347+
CREATE FUNCTION cs_ste_vec_v1_entry_array_contains_entry(a cs_ste_vec_v1_entry[], b cs_ste_vec_v1_entry)
64348
RETURNS boolean AS $$
65349
DECLARE
66350
result boolean;
@@ -95,8 +379,8 @@ DROP FUNCTION IF EXISTS jsonb_to_cs_ste_vec_index_v1(input jsonb);
95379
CREATE FUNCTION jsonb_to_cs_ste_vec_index_v1(input jsonb)
96380
RETURNS cs_ste_vec_index_v1 AS $$
97381
DECLARE
98-
vec_entry ste_vec_v1_entry;
99-
entry_array ste_vec_v1_entry[];
382+
vec_entry cs_ste_vec_v1_entry;
383+
entry_array cs_ste_vec_v1_entry[];
100384
entry_json jsonb;
101385
entry_json_array jsonb[];
102386
entry_array_length int;
@@ -106,9 +390,9 @@ BEGIN
106390
LOOP
107391
vec_entry := ROW(
108392
entry_json->>0,
109-
ROW((entry_json->>1)::bytea)::ore_cllw_8_v1,
393+
ROW(decode(entry_json->>1, 'hex'))::cs_ste_vec_encrypted_term_v1,
110394
entry_json->>2
111-
)::ste_vec_v1_entry;
395+
)::cs_ste_vec_v1_entry;
112396
entry_array := array_append(entry_array, vec_entry);
113397
END LOOP;
114398

0 commit comments

Comments
 (0)