Skip to content

Commit a5e9dad

Browse files
authored
Merge pull request #48 from cipherstash/additional-jsonb-functions-and-fixes
Additional JSONB functions and fixes
2 parents 04fd3c2 + 9889069 commit a5e9dad

File tree

4 files changed

+498
-32
lines changed

4 files changed

+498
-32
lines changed

justfile

+12-5
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,33 @@ build:
3232

3333
# Collect all the drops
3434
# In reverse order (tac) so that we drop the constraints before the tables
35-
grep -h -E '^(DROP|ALTER DOMAIN [^ ]+ DROP CONSTRAINT)' sql/0*-*.sql | tac > release/cipherstash-encrypt-tmp-drop.sql
35+
grep -h -E '^(DROP)' sql/0*-*.sql | tac > release/cipherstash-encrypt-tmp-drop-install.sql
3636
# types are always last
37-
cat sql/666-drop_types.sql >> release/cipherstash-encrypt-tmp-drop.sql
37+
cat sql/666-drop_types.sql >> release/cipherstash-encrypt-tmp-drop-install.sql
3838

3939

4040
# Build cipherstash-encrypt.sql
4141
# drop everything first
42-
cat release/cipherstash-encrypt-tmp-drop.sql > release/cipherstash-encrypt.sql
42+
cat release/cipherstash-encrypt-tmp-drop-install.sql > release/cipherstash-encrypt.sql
4343
# cat the rest of the sql files
4444
cat sql/0*-*.sql >> release/cipherstash-encrypt.sql
4545

46+
# Collect all the drops
47+
# In reverse order (tac) so that we drop the constraints before the tables
48+
grep -h -E '^(DROP|ALTER DOMAIN [^ ]+ DROP CONSTRAINT)' sql/0*-*.sql | tac > release/cipherstash-encrypt-tmp-drop-uninstall.sql
49+
# types are always last
50+
cat sql/666-drop_types.sql >> release/cipherstash-encrypt-tmp-drop-uninstall.sql
51+
4652

4753
# Build cipherstash-encrypt-uninstall.sql
4854
# prepend the drops to the main sql file
49-
cat release/cipherstash-encrypt-tmp-drop.sql >> release/cipherstash-encrypt-uninstall.sql
55+
cat release/cipherstash-encrypt-tmp-drop-uninstall.sql >> release/cipherstash-encrypt-uninstall.sql
5056
# uninstall renames configuration table
5157
cat sql/666-rename_configuration_table.sql >> release/cipherstash-encrypt-uninstall.sql
5258

5359
# remove the drop file
54-
rm release/cipherstash-encrypt-tmp-drop.sql
60+
rm release/cipherstash-encrypt-tmp-drop-install.sql
61+
rm release/cipherstash-encrypt-tmp-drop-uninstall.sql
5562

5663

5764
reset:

sql/001-ore-cllw.sql

+188-15
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,46 @@
33
--- ORE CLLW types, functions, and operators
44
---
55

6-
-- Represents a ciphertext encrypted with the CLLW ORE scheme
6+
-- Represents a ciphertext encrypted with the CLLW ORE scheme for a fixed output size
77
-- Each output block is 8-bits
88
CREATE TYPE ore_cllw_8_v1 AS (
99
bytes bytea
1010
);
1111

12+
-- Represents a ciphertext encrypted with the CLLW ORE scheme for a variable output size
13+
-- Each output block is 8-bits
14+
CREATE TYPE ore_cllw_8_variable_v1 AS (
15+
bytes bytea
16+
);
17+
18+
DROP FUNCTION IF EXISTS __bytea_ct_eq(a bytea, b bytea);
19+
20+
-- Constant time comparison of 2 bytea values
21+
CREATE FUNCTION __bytea_ct_eq(a bytea, b bytea) RETURNS boolean AS $$
22+
DECLARE
23+
result boolean;
24+
differing bytea;
25+
BEGIN
26+
-- Check if the bytea values are the same length
27+
IF LENGTH(a) != LENGTH(b) THEN
28+
RETURN false;
29+
END IF;
30+
31+
-- Compare each byte in the bytea values
32+
result := true;
33+
FOR i IN 1..LENGTH(a) LOOP
34+
IF SUBSTRING(a FROM i FOR 1) != SUBSTRING(b FROM i FOR 1) THEN
35+
result := result AND false;
36+
END IF;
37+
END LOOP;
38+
39+
RETURN result;
40+
END;
41+
$$ LANGUAGE plpgsql;
1242

13-
DROP FUNCTION IF EXISTS __compare_inner_ore_cllw_8_v1(a ore_cllw_8_v1, b ore_cllw_8_v1);
43+
DROP FUNCTION IF EXISTS __compare_inner_ore_cllw_8_v1(a bytea, b bytea);
1444

15-
CREATE FUNCTION __compare_inner_ore_cllw_8_v1(a ore_cllw_8_v1, b ore_cllw_8_v1)
45+
CREATE FUNCTION __compare_inner_ore_cllw_8_v1(a bytea, b bytea)
1646
RETURNS int AS $$
1747
DECLARE
1848
len_a INT;
@@ -21,12 +51,12 @@ DECLARE
2151
i INT;
2252
differing RECORD;
2353
BEGIN
24-
len_a := LENGTH(a.bytes);
54+
len_a := LENGTH(a);
2555

2656
-- Iterate over each byte and compare them
2757
FOR i IN 1..len_a LOOP
28-
x := SUBSTRING(a.bytes FROM i FOR 1);
29-
y := SUBSTRING(b.bytes FROM i FOR 1);
58+
x := SUBSTRING(a FROM i FOR 1);
59+
y := SUBSTRING(b FROM i FOR 1);
3060

3161
-- Check if there's a difference
3262
IF x != y THEN
@@ -66,22 +96,24 @@ BEGIN
6696
len_b := LENGTH(b.bytes);
6797

6898
IF len_a != len_b THEN
69-
RAISE EXCEPTION 'Bytea arguments must have the same length';
99+
RAISE EXCEPTION 'Numeric ORE comparison requires bytea values of the same length';
70100
END IF;
71101

72-
RETURN __compare_inner_ore_cllw_8_v1(a, b);
102+
RETURN __compare_inner_ore_cllw_8_v1(a.bytes, b.bytes);
73103
END;
74104
$$ LANGUAGE plpgsql;
75105

76106

77-
DROP FUNCTION IF EXISTS compare_lex_ore_cllw_8_v1(a ore_cllw_8_v1, b ore_cllw_8_v1);
107+
DROP FUNCTION IF EXISTS compare_lex_ore_cllw_8_v1(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
78108

79-
CREATE FUNCTION compare_lex_ore_cllw_8_v1(a ore_cllw_8_v1, b ore_cllw_8_v1)
109+
CREATE FUNCTION compare_lex_ore_cllw_8_v1(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1)
80110
RETURNS int AS $$
81111
DECLARE
82112
len_a INT;
83113
len_b INT;
84-
cmp_result int;
114+
-- length of the common part of the two bytea values
115+
common_len INT;
116+
cmp_result INT;
85117
BEGIN
86118
-- Get the lengths of both bytea inputs
87119
len_a := LENGTH(a.bytes);
@@ -96,8 +128,18 @@ BEGIN
96128
RETURN 1;
97129
END IF;
98130

131+
-- Find the length of the shorter bytea
132+
IF len_a < len_b THEN
133+
common_len := len_a;
134+
ELSE
135+
common_len := len_b;
136+
END IF;
137+
99138
-- Use the compare_bytea function to compare byte by byte
100-
cmp_result := __compare_inner_ore_cllw_8_v1(a, b);
139+
cmp_result := __compare_inner_ore_cllw_8_v1(
140+
SUBSTRING(a.bytes FROM 1 FOR common_len),
141+
SUBSTRING(b.bytes FROM 1 FOR common_len)
142+
);
101143

102144
-- If the comparison returns 'less' or 'greater', return that result
103145
IF cmp_result = -1 THEN
@@ -122,15 +164,15 @@ DROP FUNCTION IF EXISTS ore_cllw_8_v1_eq(a ore_cllw_8_v1, b ore_cllw_8_v1);
122164

123165
CREATE FUNCTION ore_cllw_8_v1_eq(a ore_cllw_8_v1, b ore_cllw_8_v1)
124166
RETURNS boolean AS $$
125-
SELECT compare_ore_cllw_8_v1(a, b) = 0
167+
SELECT __bytea_ct_eq(a.bytes, b.bytes)
126168
$$ LANGUAGE SQL;
127169

128170

129171
DROP FUNCTION IF EXISTS ore_cllw_8_v1_neq(a ore_cllw_8_v1, b ore_cllw_8_v1);
130172

131173
CREATE FUNCTION ore_cllw_8_v1_neq(a ore_cllw_8_v1, b ore_cllw_8_v1)
132174
RETURNS boolean AS $$
133-
SELECT compare_ore_cllw_8_v1(a, b) <> 0
175+
SELECT not __bytea_ct_eq(a.bytes, b.bytes)
134176
$$ LANGUAGE SQL;
135177

136178

@@ -249,12 +291,127 @@ CREATE OPERATOR <= (
249291
MERGES
250292
);
251293

294+
-- Lexical comparison operators
295+
296+
DROP FUNCTION IF EXISTS ore_cllw_8_variable_v1_eq(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
297+
298+
CREATE OR REPLACE FUNCTION ore_cllw_8_variable_v1_eq(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1) RETURNS boolean AS $$
299+
SELECT __bytea_ct_eq(a.bytes, b.bytes)
300+
$$ LANGUAGE SQL;
301+
302+
DROP FUNCTION IF EXISTS ore_cllw_8_variable_v1_neq(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
303+
304+
CREATE OR REPLACE FUNCTION ore_cllw_8_variable_v1_neq(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1) RETURNS boolean AS $$
305+
SELECT not __bytea_ct_eq(a.bytes, b.bytes)
306+
$$ LANGUAGE SQL;
307+
308+
DROP FUNCTION IF EXISTS ore_cllw_8_v1_lt_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
309+
310+
CREATE OR REPLACE FUNCTION ore_cllw_8_v1_lt_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1) RETURNS boolean AS $$
311+
SELECT compare_lex_ore_cllw_8_v1(a, b) = -1
312+
$$ LANGUAGE SQL;
313+
314+
DROP FUNCTION IF EXISTS ore_cllw_8_v1_lte_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
315+
316+
CREATE OR REPLACE FUNCTION ore_cllw_8_v1_lte_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1) RETURNS boolean AS $$
317+
SELECT compare_lex_ore_cllw_8_v1(a, b) != 1
318+
$$ LANGUAGE SQL;
319+
320+
DROP FUNCTION IF EXISTS ore_cllw_8_v1_gt_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
321+
322+
CREATE OR REPLACE FUNCTION ore_cllw_8_v1_gt_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1) RETURNS boolean AS $$
323+
SELECT compare_lex_ore_cllw_8_v1(a, b) = 1
324+
$$ LANGUAGE SQL;
325+
326+
DROP FUNCTION IF EXISTS ore_cllw_8_v1_gte_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);
327+
328+
CREATE OR REPLACE FUNCTION ore_cllw_8_v1_gte_lex(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1) RETURNS boolean AS $$
329+
SELECT compare_lex_ore_cllw_8_v1(a, b) != -1
330+
$$ LANGUAGE SQL;
331+
332+
DROP OPERATOR IF EXISTS = (ore_cllw_8_variable_v1, ore_cllw_8_variable_v1);
333+
334+
CREATE OPERATOR = (
335+
PROCEDURE="ore_cllw_8_variable_v1_eq",
336+
LEFTARG=ore_cllw_8_variable_v1,
337+
RIGHTARG=ore_cllw_8_variable_v1,
338+
NEGATOR = <>,
339+
RESTRICT = eqsel,
340+
JOIN = eqjoinsel,
341+
HASHES,
342+
MERGES
343+
);
344+
345+
DROP OPERATOR IF EXISTS <> (ore_cllw_8_variable_v1, ore_cllw_8_variable_v1);
346+
347+
CREATE OPERATOR <> (
348+
PROCEDURE="ore_cllw_8_variable_v1_neq",
349+
LEFTARG=ore_cllw_8_variable_v1,
350+
RIGHTARG=ore_cllw_8_variable_v1,
351+
NEGATOR = =,
352+
RESTRICT = eqsel,
353+
JOIN = eqjoinsel,
354+
HASHES,
355+
MERGES
356+
);
357+
358+
DROP OPERATOR IF EXISTS > (ore_cllw_8_variable_v1, ore_cllw_8_variable_v1);
359+
360+
CREATE OPERATOR > (
361+
PROCEDURE="ore_cllw_8_v1_gt_lex",
362+
LEFTARG=ore_cllw_8_variable_v1,
363+
RIGHTARG=ore_cllw_8_variable_v1,
364+
NEGATOR = <=,
365+
RESTRICT = scalarltsel,
366+
JOIN = scalarltjoinsel,
367+
HASHES,
368+
MERGES
369+
);
370+
371+
DROP OPERATOR IF EXISTS < (ore_cllw_8_variable_v1, ore_cllw_8_variable_v1);
372+
373+
CREATE OPERATOR < (
374+
PROCEDURE="ore_cllw_8_v1_lt_lex",
375+
LEFTARG=ore_cllw_8_variable_v1,
376+
RIGHTARG=ore_cllw_8_variable_v1,
377+
NEGATOR = >=,
378+
RESTRICT = scalargtsel,
379+
JOIN = scalargtjoinsel,
380+
HASHES,
381+
MERGES
382+
);
383+
384+
DROP OPERATOR IF EXISTS >= (ore_cllw_8_variable_v1, ore_cllw_8_variable_v1);
385+
386+
CREATE OPERATOR >= (
387+
PROCEDURE="ore_cllw_8_v1_gte_lex",
388+
LEFTARG=ore_cllw_8_variable_v1,
389+
RIGHTARG=ore_cllw_8_variable_v1,
390+
NEGATOR = <,
391+
RESTRICT = scalarltsel,
392+
JOIN = scalarltjoinsel,
393+
HASHES,
394+
MERGES
395+
);
396+
397+
DROP OPERATOR IF EXISTS <= (ore_cllw_8_variable_v1, ore_cllw_8_variable_v1);
398+
399+
CREATE OPERATOR <= (
400+
PROCEDURE="ore_cllw_8_v1_lte_lex",
401+
LEFTARG=ore_cllw_8_variable_v1,
402+
RIGHTARG=ore_cllw_8_variable_v1,
403+
NEGATOR = >,
404+
RESTRICT = scalargtsel,
405+
JOIN = scalargtjoinsel,
406+
HASHES,
407+
MERGES
408+
);
409+
252410

253411
DROP OPERATOR FAMILY IF EXISTS ore_cllw_8_v1_btree_ops USING btree;
254412

255413
CREATE OPERATOR FAMILY ore_cllw_8_v1_btree_ops USING btree;
256414

257-
258415
DROP OPERATOR CLASS IF EXISTS ore_cllw_8_v1_btree_ops USING btree;
259416

260417
CREATE OPERATOR CLASS ore_cllw_8_v1_btree_ops DEFAULT FOR TYPE ore_cllw_8_v1 USING btree FAMILY ore_cllw_8_v1_btree_ops AS
@@ -264,3 +421,19 @@ CREATE OPERATOR CLASS ore_cllw_8_v1_btree_ops DEFAULT FOR TYPE ore_cllw_8_v1 USI
264421
OPERATOR 4 >=,
265422
OPERATOR 5 >,
266423
FUNCTION 1 compare_ore_cllw_8_v1(a ore_cllw_8_v1, b ore_cllw_8_v1);
424+
425+
-- Lexical comparison operator class
426+
427+
DROP OPERATOR FAMILY IF EXISTS ore_cllw_8_v1_variable_btree_ops USING btree;
428+
429+
CREATE OPERATOR FAMILY ore_cllw_8_v1_variable_btree_ops USING btree;
430+
431+
DROP OPERATOR CLASS IF EXISTS ore_cllw_8_v1_variable_btree_ops USING btree;
432+
433+
CREATE OPERATOR CLASS ore_cllw_8_v1_variable_btree_ops DEFAULT FOR TYPE ore_cllw_8_variable_v1 USING btree FAMILY ore_cllw_8_v1_variable_btree_ops AS
434+
OPERATOR 1 <,
435+
OPERATOR 2 <=,
436+
OPERATOR 3 =,
437+
OPERATOR 4 >=,
438+
OPERATOR 5 >,
439+
FUNCTION 1 compare_lex_ore_cllw_8_v1(a ore_cllw_8_variable_v1, b ore_cllw_8_variable_v1);

0 commit comments

Comments
 (0)