From c1568d48e4d05dcf153e3eb3ec6d35cd44866de6 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Thu, 29 Jun 2023 18:09:41 +0200 Subject: [PATCH 01/19] spec: support for `reject if` --- SPECIFICATIONS.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 9d0a672..b27f12b 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -291,23 +291,27 @@ To validate an operation, all of a token's checks must succeed. One block can contain one or more checks. -Their text representation is `check if` or `check all` followed by the body of the query. +Their text representation is `check if`, `check all` or `reject if` followed by the body of the query. There can be multiple queries inside of a check, it will succeed if any of them -succeeds. They are separated by a `or` token. +succeeds (in the case of `reject if`, the check will fail if any query matches). They are separated by a `or` token. - a `check if` query succeeds if it finds one set of facts that matches the body and expressions - a `check all` query succeeds if all the sets of facts that match the body also succeed the expression. -`check all` can only be used starting from block version 4 +- a `reject if` query succeeds if no set of facts matches the body and expressions + +`check all` can only be used starting from block version 4. +`reject if` can only be used starting from block version 5. Here are some examples of writing checks: #### Basic token This first token defines a list of authority facts giving `read` and `write` -rights on `file1`, `read` on `file2`. The first caveat checks that the operation +rights on `file1`, `read` on `file2`. The first check ensures that the operation is `read` (and will not allow any other `operation` fact), and then that we have -the `read` right over the resource. -The second caveat checks that the resource is `file1`. +the `read` right over the resource. +The second check ensures that the resource is either `file1` or `file2`. +The third check ensures that the resource is not `file1`. ``` authority: @@ -323,20 +327,24 @@ check if ---------- Block 2: check if - resource("file1") // restrict to file1 resource + resource("file1") + or resource("file2") // restrict to file1 or file2 +---------- +Block 3: +reject if + resource("file1") // forbid using the token on file1 ``` The verifier side provides the `resource` and `operation` facts with information from the request. -If the verifier provided the facts `resource("file2")` and +If the verifier provided the facts `resource("file1")` and `operation("read")`, the rule application of the first check would see -`resource("file2"), operation("read"), right("file2", "read")` -with `X = "file2"`, so it would succeed, but the second check would fail -because it expects `resource("file1")`. +`resource("file1"), operation("read"), right("file1", "read")` +with `X = "file1"`, so it would succeed, the second check would also succeed because it expects `resource("file1")` or `resource("file2")`. The third check would then fail because it would match on `resource("file1")`. -If the verifier provided the facts `resource("file1")` and -`operation("read")`, both checks would succeed. +If the verifier provided the facts `resource("file2")` and +`operation("read")`, all checks would succeed. #### Broad authority rules @@ -661,7 +669,7 @@ each block must carry its own version. when possible, especially for biscuit versions that are only additive in terms of features. - The lowest supported biscuit version is `3`; -- The highest supported biscuit version is `4`; +- The highest supported biscuit version is `5`; # Version 2 From 7e6e347f8f51437dba2281402e02109d7c873a0a Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sun, 12 May 2024 19:15:09 +0200 Subject: [PATCH 02/19] Reject if samples (#161) * add samples for reject if * missing change --- samples/current/README.md | 92 ++++++++++++++++++++++++- samples/current/samples.json | 92 ++++++++++++++++++++++++- samples/current/test017_expressions.bc | Bin 1725 -> 1799 bytes samples/current/test029_reject_if.bc | Bin 0 -> 182 bytes 4 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 samples/current/test029_reject_if.bc diff --git a/samples/current/README.md b/samples/current/README.md index e123c7c..bec8ced 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -1214,7 +1214,7 @@ result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedB ### token authority: -symbols: ["hello world", "hello", "world", "aaabde", "a*c?.e", "abd", "aaa", "b", "de", "abcD12", "abc", "def"] +symbols: ["hello world", "hello", "world", "aaabde", "a*c?.e", "abd", "aaa", "b", "de", "abcD12", "é", "abc", "def"] public keys: [] @@ -1239,6 +1239,8 @@ check if "aaabde".matches("a*c?.e"); check if "aaabde".contains("abd"); check if "aaabde" == "aaa" + "b" + "de"; check if "abcD12" == "abcD12"; +check if "abcD12".length() == 6; +check if "é".length() == 2; check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z; check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z; @@ -1268,7 +1270,7 @@ allow if true; ``` revocation ids: -- `f61b4cb4fc58777fec6c8d39fe62259dc3c78511868236c391e9f67ffd03a3a8b8e3042d4bacce0d5756d053f5afccd4c5e4df0597af44b36bdfab492e5fe50e` +- `3d5b23b502b3dd920bfb68b9039164d1563bb8927210166fa5c17f41b76b31bb957bc2ed3318452958f658baa2d398fe4cf25c58a27e6c8bc42c9702c8aa1b0c` authorizer world: ``` @@ -1287,7 +1289,9 @@ World { "check if \"aaabde\".contains(\"abd\")", "check if \"aaabde\".matches(\"a*c?.e\")", "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12\".length() == 6", "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")", + "check if \"é\".length() == 2", "check if (true || false) && true", "check if 1 + 2 * 3 - 4 / 2 == 5", "check if 1 < 2", @@ -2357,3 +2361,87 @@ World { result: `Ok(0)` + +------------------------------ + +## test reject if: test029_reject_if.bc +### token + +authority: +symbols: ["test"] + +public keys: [] + +``` +reject if test($test), $test; +``` + +### validation + +authorizer code: +``` +test(false); + +allow if true; +``` + +revocation ids: +- `2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07` + +authorizer world: +``` +World { + facts: { + ( + "test(false)", + { + None, + }, + ), +} + rules: {} + checks: { + "reject if test($test), $test", +} + policies: { + "allow if true", +} +} +``` + +result: `Ok(0)` +### validation for "rejection" + +authorizer code: +``` +test(true); + +allow if true; +``` + +revocation ids: +- `2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07` + +authorizer world: +``` +World { + facts: { + ( + "test(true)", + { + None, + }, + ), +} + rules: {} + checks: { + "reject if test($test), $test", +} + policies: { + "allow if true", +} +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))` + diff --git a/samples/current/samples.json b/samples/current/samples.json index 432c45d..28730f3 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -1239,12 +1239,13 @@ "b", "de", "abcD12", + "é", "abc", "def" ], "public_keys": [], "external_key": null, - "code": "check if true;\ncheck if !false;\ncheck if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if true == true;\ncheck if false == false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 == 3;\ncheck if 1 + 2 * 3 - 4 / 2 == 5;\ncheck if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" == \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" == \"abcD12\";\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z;\ncheck if hex:12ab == hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] == [1, 2];\ncheck if [1, 2].intersection([2, 3]) == [2];\ncheck if [1, 2].union([2, 3]) == [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() == 2;\n" + "code": "check if true;\ncheck if !false;\ncheck if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if true == true;\ncheck if false == false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 == 3;\ncheck if 1 + 2 * 3 - 4 / 2 == 5;\ncheck if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" == \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12\".length() == 6;\ncheck if \"é\".length() == 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z;\ncheck if hex:12ab == hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] == [1, 2];\ncheck if [1, 2].intersection([2, 3]) == [2];\ncheck if [1, 2].union([2, 3]) == [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() == 2;\n" } ], "validations": { @@ -1262,7 +1263,9 @@ "check if \"aaabde\".contains(\"abd\")", "check if \"aaabde\".matches(\"a*c?.e\")", "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12\".length() == 6", "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")", + "check if \"é\".length() == 2", "check if (true || false) && true", "check if 1 + 2 * 3 - 4 / 2 == 5", "check if 1 < 2", @@ -1307,7 +1310,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "f61b4cb4fc58777fec6c8d39fe62259dc3c78511868236c391e9f67ffd03a3a8b8e3042d4bacce0d5756d053f5afccd4c5e4df0597af44b36bdfab492e5fe50e" + "3d5b23b502b3dd920bfb68b9039164d1563bb8927210166fa5c17f41b76b31bb957bc2ed3318452958f658baa2d398fe4cf25c58a27e6c8bc42c9702c8aa1b0c" ] } } @@ -2174,6 +2177,91 @@ ] } } + }, + { + "title": "test reject if", + "filename": "test029_reject_if.bc", + "token": [ + { + "symbols": [ + "test" + ], + "public_keys": [], + "external_key": null, + "code": "reject if test($test), $test;\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + [ + "test(false)", + [ + null + ] + ] + ], + "rules": [], + "checks": [ + "reject if test($test), $test" + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "test(false);\n\nallow if true;\n", + "revocation_ids": [ + "2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07" + ] + }, + "rejection": { + "world": { + "facts": [ + [ + "test(true)", + [ + null + ] + ] + ], + "rules": [], + "checks": [ + "reject if test($test), $test" + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "reject if test($test), $test" + } + } + ] + } + } + } + }, + "authorizer_code": "test(true);\n\nallow if true;\n", + "revocation_ids": [ + "2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07" + ] + } + } } ] } diff --git a/samples/current/test017_expressions.bc b/samples/current/test017_expressions.bc index 10f50241d96621a4a6d9b28f9e7386e98f21d91a..1f3234c07694321afef884cd0b547baa27d64096 100644 GIT binary patch delta 178 zcmdnX+s?--^njP^>qJ&JW~Rd{H+pSkvRCAi=VIcJmXhRRmKxm1*V^WcTSpL$3^^V)K4R=qiKJ?aD!c{ZkTg0wKmuLL*`4khes4l1bh|YAT6RV_o JCeLJ30RV53IiC62nq!X0~m_4_ynr~K=vC< zwES3if9!0HIsRfLox{h45r%>`!;$IsfBgfasJP<de*gdg diff --git a/samples/current/test029_reject_if.bc b/samples/current/test029_reject_if.bc new file mode 100644 index 0000000000000000000000000000000000000000..9d6c4d360c6d4231eef5e1dd89e0851cb5561823 GIT binary patch literal 182 zcmV;n07?H6j{yoL3Iudzb95L5G8+mP3IYfl5(o%@2oeJbfCw4~3Iz%S2!IF>0um$$ z01_Y&RmV`Vp-@>juN61OCb}|XnOrlbM_8(_u_s#t65@m!Kp4*RqlF+uhRNT?M7FW~0`rL|yBLSoUZetC9l2O=U0 kAercU4v|<>9`3aR{}m=~DIQVI&ef5&!@I literal 0 HcmV?d00001 From 5cddb2ea3d1cf1c8e70a803d223e847b4a01b03b Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 23 May 2024 14:25:30 +0200 Subject: [PATCH 03/19] Add support for the null type (#166) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Delafargue --- SPECIFICATIONS.md | 9 +- samples/current/README.md | 419 +++++++++++++++++++++++++-------- samples/current/samples.json | 259 +++++++++++++++++++- samples/current/test30_null.bc | Bin 0 -> 248 bytes 4 files changed, 571 insertions(+), 116 deletions(-) create mode 100644 samples/current/test30_null.bc diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index bfe4ad1..c0d5861 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -75,6 +75,7 @@ _predicates_ over the following types: - _byte array_ - _date_ - _boolean_ +- _null_ - _set_ a deduplicated list of values of any type, except _variable_ or _set_ While a Biscuit token does not use a textual representation for storage, we @@ -117,6 +118,7 @@ We will represent the various types as follows: - byte array: `hex:01A2` - date in RFC 3339 format: `1985-04-12T23:20:50.52Z` - boolean: `true` or `false` +- null: `null`, supported since block version 5 - set: `[ "a", "b", "c"]` As an example, assuming we have the following facts: `parent("a", "b")`, @@ -154,6 +156,8 @@ not equal, set inclusion. A _boolean_ is `true` or `false`. It supports the following operations: `==`, `!=`, `||`, `&&`, set inclusion. +A _null_ is a default type indicating the absence of value. It supports the operations `==` and `!=` with any other type. _null_ is always equal to itself, and not equal to any other type + A _set_ is a deduplicated list of terms of the same type. It cannot contain variables or other sets. It supports equal, not equal, , intersection, union, set inclusion. @@ -184,13 +188,14 @@ The logic language is described by the following EBNF grammar: ::= "(" ? (? "," ? )* ? ")" ::= | - ::= | | | ("hex:" ) | | - ::= | | | | + ::= | | | ("hex:" ) | | | + ::= | | | | | ::= "-"? [0-9]+ ::= ([a-z] | [0-9])+ ::= "true" | "false" + ::= "null" ::= [0-9]* "-" [0-9] [0-9] "-" [0-9] [0-9] "T" [0-9] [0-9] ":" [0-9] [0-9] ":" [0-9] [0-9] ( "Z" | ( ("+" | "-") [0-9] [0-9] ":" [0-9] [0-9] )) ::= "[" ? ( ( ? "," ? )* ? )? "]" diff --git a/samples/current/README.md b/samples/current/README.md index bec8ced..e7a0ae1 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -45,7 +45,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -53,7 +53,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -68,7 +68,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -296,7 +296,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -305,7 +305,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -316,7 +316,7 @@ World { "user_id(\"alice\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -328,7 +328,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -338,7 +338,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -407,7 +407,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -416,7 +416,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -426,7 +426,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -439,7 +439,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -499,7 +499,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -512,7 +512,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -574,7 +574,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -583,7 +583,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -593,7 +593,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -606,7 +606,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -657,7 +657,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -666,7 +666,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -679,7 +679,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -728,7 +728,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -740,7 +740,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -773,7 +773,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -785,7 +785,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -847,7 +847,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -856,7 +856,7 @@ World { "time(2020-12-21T09:23:12Z)", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -867,7 +867,7 @@ World { "valid_date(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -880,7 +880,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -891,7 +891,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -925,7 +925,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -934,7 +934,7 @@ World { "time(2020-12-21T09:23:12Z)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -947,7 +947,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -958,7 +958,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1006,7 +1006,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1017,7 +1017,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1049,7 +1049,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1060,7 +1060,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1108,7 +1108,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1121,7 +1121,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1177,7 +1177,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1190,7 +1190,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1278,7 +1278,7 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1404,7 +1404,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1412,7 +1412,7 @@ World { "operation(\"write\")", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -1425,7 +1425,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -1435,7 +1435,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1496,7 +1496,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1505,7 +1505,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1520,7 +1520,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1568,7 +1568,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1581,7 +1581,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1656,7 +1656,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1696,7 +1696,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1763,7 +1763,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1773,7 +1773,7 @@ World { "authority_fact(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1786,7 +1786,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -1847,7 +1847,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1857,7 +1857,7 @@ World { "right(\"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1870,7 +1870,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1878,7 +1878,7 @@ World { "check if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1928,7 +1928,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1937,7 +1937,7 @@ World { "operation(\"B\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1950,7 +1950,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1983,7 +1983,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1992,7 +1992,7 @@ World { "operation(\"invalid\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -2005,7 +2005,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2112,7 +2112,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -2122,7 +2122,7 @@ World { "query(0)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2132,7 +2132,7 @@ World { "query(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2145,7 +2145,7 @@ World { "query(1, 2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -2155,7 +2155,7 @@ World { "query(2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 3, @@ -2165,7 +2165,7 @@ World { "query(3)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 4, @@ -2177,7 +2177,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -2187,7 +2187,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2195,7 +2195,7 @@ World { "check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -2204,7 +2204,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -2213,7 +2213,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 3, ), @@ -2222,7 +2222,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 4, ), @@ -2231,7 +2231,7 @@ World { "check if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -2284,7 +2284,7 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2339,7 +2339,7 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2391,21 +2391,30 @@ revocation ids: authorizer world: ``` World { - facts: { - ( - "test(false)", - { + facts: [ + Facts { + origin: { None, }, - ), -} - rules: {} - checks: { - "reject if test($test), $test", -} - policies: { + facts: [ + "test(false)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "reject if test($test), $test", + ], + }, +] + policies: [ "allow if true", -} +] } ``` @@ -2425,23 +2434,225 @@ revocation ids: authorizer world: ``` World { - facts: { - ( - "test(true)", - { + facts: [ + Facts { + origin: { None, }, - ), + facts: [ + "test(true)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "reject if test($test), $test", + ], + }, +] + policies: [ + "allow if true", +] } - rules: {} - checks: { - "reject if test($test), $test", +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))` + + +------------------------------ + +## test null: test30_null.bc +### token + +authority: +symbols: ["fact", "value"] + +public keys: [] + +``` +check if fact(null, $value), $value == null; +reject if fact(null, $value), $value != null; +``` + +### validation + +authorizer code: +``` +fact(null, null); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, null)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] } - policies: { +``` + +result: `Ok(0)` +### validation for "rejection1" + +authorizer code: +``` +fact(null, 1); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, 1)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ "allow if true", +] } +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` +### validation for "rejection2" + +authorizer code: +``` +fact(null, true); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, true)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] } ``` -result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))` +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` +### validation for "rejection3" + +authorizer code: +``` +fact(null, "abcd"); + +allow if true; +``` + +revocation ids: +- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, \"abcd\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` diff --git a/samples/current/samples.json b/samples/current/samples.json index 28730f3..4af6b9c 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -2195,16 +2195,23 @@ "": { "world": { "facts": [ - [ - "test(false)", - [ + { + "origin": [ null + ], + "facts": [ + "test(false)" ] - ] + } ], "rules": [], "checks": [ - "reject if test($test), $test" + { + "origin": 0, + "checks": [ + "reject if test($test), $test" + ] + } ], "policies": [ "allow if true" @@ -2221,16 +2228,23 @@ "rejection": { "world": { "facts": [ - [ - "test(true)", - [ + { + "origin": [ null + ], + "facts": [ + "test(true)" ] - ] + } ], "rules": [], "checks": [ - "reject if test($test), $test" + { + "origin": 0, + "checks": [ + "reject if test($test), $test" + ] + } ], "policies": [ "allow if true" @@ -2262,6 +2276,231 @@ ] } } + }, + { + "title": "test null", + "filename": "test30_null.bc", + "token": [ + { + "symbols": [ + "fact", + "value" + ], + "public_keys": [], + "external_key": null, + "code": "check if fact(null, $value), $value == null;\nreject if fact(null, $value), $value != null;\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, null)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "fact(null, null);\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + }, + "rejection1": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, 1)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, 1);\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + }, + "rejection2": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, true)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, true);\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + }, + "rejection3": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, \"abcd\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, \"abcd\");\n\nallow if true;\n", + "revocation_ids": [ + "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + ] + } + } } ] } diff --git a/samples/current/test30_null.bc b/samples/current/test30_null.bc new file mode 100644 index 0000000000000000000000000000000000000000..2337a1114ef4e0530bb0283a7e36ff07aa920989 GIT binary patch literal 248 zcmWf-$jFt>#gdkoT*Ad#mY7qTD#2=`$)(Q4#33!j!_mMY#N@;v#LUsiAtlVk$^~L@ zv2X#!xLBl^I9QCdiB&2hz$B!?!62j{5PCddPP$2UNR<`+DIN%IdD0A-g5zynHfbpoUMiR^0))% znoDzSVrjhE<0dI#*E#)giF@0N2h2)JTnaN^RP#-Y2$p-dmHEG@TAsG@p+y1J!aZ}P M<+Zj%+}BM60M+S53jhEB literal 0 HcmV?d00001 From 1514dd5efa07ee201362a789c6c88b03e7f6ab7a Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Thu, 24 Oct 2024 17:59:37 +0200 Subject: [PATCH 04/19] update samples and schema based on the latest v5 branch in biscuit-rust --- samples/current/README.md | 452 +++++++++++++++--- samples/current/samples.json | 366 ++++++++++++-- samples/current/test017_expressions.bc | Bin 1799 -> 1687 bytes samples/current/test024_third_party.bc | Bin 458 -> 458 bytes .../current/test026_public_keys_interning.bc | Bin 1316 -> 1547 bytes samples/current/test027_integer_wraparound.bc | Bin 329 -> 293 bytes samples/current/test029_reject_if.bc | Bin 182 -> 182 bytes samples/current/test030_null.bc | Bin 0 -> 248 bytes .../current/test031_heterogeneous_equal.bc | Bin 0 -> 253 bytes samples/current/test032_laziness_closures.bc | Bin 0 -> 758 bytes samples/current/test033_typeof.bc | Bin 0 -> 882 bytes schema.proto | 17 +- 12 files changed, 715 insertions(+), 120 deletions(-) create mode 100644 samples/current/test030_null.bc create mode 100644 samples/current/test031_heterogeneous_equal.bc create mode 100644 samples/current/test032_laziness_closures.bc create mode 100644 samples/current/test033_typeof.bc diff --git a/samples/current/README.md b/samples/current/README.md index e7a0ae1..7ff9275 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -1221,45 +1221,42 @@ public keys: [] ``` check if true; check if !false; -check if !false && true; -check if false || true; -check if (true || false) && true; -check if true == true; -check if false == false; +check if true === true; +check if false === false; check if 1 < 2; check if 2 > 1; check if 1 <= 2; check if 1 <= 1; check if 2 >= 1; check if 2 >= 2; -check if 3 == 3; -check if 1 + 2 * 3 - 4 / 2 == 5; -check if "hello world".starts_with("hello") && "hello world".ends_with("world"); +check if 3 === 3; +check if 1 + 2 * 3 - 4 / 2 === 5; +check if "hello world".starts_with("hello"), "hello world".ends_with("world"); check if "aaabde".matches("a*c?.e"); check if "aaabde".contains("abd"); -check if "aaabde" == "aaa" + "b" + "de"; -check if "abcD12" == "abcD12"; -check if "abcD12".length() == 6; -check if "é".length() == 2; +check if "aaabde" === "aaa" + "b" + "de"; +check if "abcD12" === "abcD12"; +check if "abcD12".length() === 6; +check if "é".length() === 2; check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z; check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z; -check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z; -check if hex:12ab == hex:12ab; +check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z; +check if hex:12ab === hex:12ab; check if [1, 2].contains(2); check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z); check if [false, true].contains(true); check if ["abc", "def"].contains("abc"); check if [hex:12ab, hex:34de].contains(hex:34de); check if [1, 2].contains([2]); -check if [1, 2] == [1, 2]; -check if [1, 2].intersection([2, 3]) == [2]; -check if [1, 2].union([2, 3]) == [1, 2, 3]; +check if [1, 2] === [1, 2]; +check if [1, 2].intersection([2, 3]) === [2]; +check if [1, 2].union([2, 3]) === [1, 2, 3]; check if [1, 2, 3].intersection([1, 2]).contains(1); -check if [1, 2, 3].intersection([1, 2]).length() == 2; +check if [1, 2, 3].intersection([1, 2]).length() === 2; ``` ### validation @@ -1270,7 +1267,7 @@ allow if true; ``` revocation ids: -- `3d5b23b502b3dd920bfb68b9039164d1563bb8927210166fa5c17f41b76b31bb957bc2ed3318452958f658baa2d398fe4cf25c58a27e6c8bc42c9702c8aa1b0c` +- `d0420227266e3583a42dfaa0e38550d99f681d150dd18856f3af9a697bc9c5c8bf06b4b0fe5b9df0377d1b963574e2fd210a0a76a8b0756a65f640c602bebd07` authorizer world: ``` @@ -1284,16 +1281,14 @@ World { ), checks: [ "check if !false", - "check if !false && true", - "check if \"aaabde\" == \"aaa\" + \"b\" + \"de\"", + "check if \"aaabde\" === \"aaa\" + \"b\" + \"de\"", "check if \"aaabde\".contains(\"abd\")", "check if \"aaabde\".matches(\"a*c?.e\")", - "check if \"abcD12\" == \"abcD12\"", - "check if \"abcD12\".length() == 6", - "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")", - "check if \"é\".length() == 2", - "check if (true || false) && true", - "check if 1 + 2 * 3 - 4 / 2 == 5", + "check if \"abcD12\" === \"abcD12\"", + "check if \"abcD12\".length() === 6", + "check if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\")", + "check if \"é\".length() === 2", + "check if 1 + 2 * 3 - 4 / 2 === 5", "check if 1 < 2", "check if 1 <= 1", "check if 1 <= 2", @@ -1302,28 +1297,27 @@ World { "check if 2 >= 2", "check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z", "check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z", - "check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z", + "check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", - "check if 3 == 3", + "check if 3 === 3", "check if [\"abc\", \"def\"].contains(\"abc\")", "check if [1, 2, 3].intersection([1, 2]).contains(1)", - "check if [1, 2, 3].intersection([1, 2]).length() == 2", - "check if [1, 2] == [1, 2]", + "check if [1, 2, 3].intersection([1, 2]).length() === 2", + "check if [1, 2] === [1, 2]", "check if [1, 2].contains(2)", "check if [1, 2].contains([2])", - "check if [1, 2].intersection([2, 3]) == [2]", - "check if [1, 2].union([2, 3]) == [1, 2, 3]", + "check if [1, 2].intersection([2, 3]) === [2]", + "check if [1, 2].union([2, 3]) === [1, 2, 3]", "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)", "check if [false, true].contains(true)", "check if [hex:12ab, hex:34de].contains(hex:34de)", - "check if false == false", - "check if false || true", - "check if hex:12ab == hex:12ab", + "check if false === false", + "check if hex:12ab === hex:12ab", "check if true", - "check if true == true", + "check if true === true", ], }, ] @@ -1841,7 +1835,7 @@ allow if true; revocation ids: - `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03` -- `93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405` +- `342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03` authorizer world: ``` @@ -2041,7 +2035,7 @@ check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755 1: symbols: [] -public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" @@ -2055,7 +2049,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 2: symbols: [] -public keys: [] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" @@ -2068,7 +2062,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 3: symbols: [] -public keys: [] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" @@ -2081,7 +2075,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 4: symbols: [] -public keys: ["ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] ``` query(4); @@ -2103,10 +2097,10 @@ allow if true; revocation ids: - `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04` -- `45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400` -- `179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703` -- `edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d` -- `6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07` +- `6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d` +- `5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04` +- `c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09` +- `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900` authorizer world: ``` @@ -2263,9 +2257,9 @@ symbols: [] public keys: [] ``` -check if true || 10000000000 * 10000000000 != 0; -check if true || 9223372036854775807 + 1 != 0; -check if true || -9223372036854775808 - 1 != 0; +check if 10000000000 * 10000000000 != 0; +check if 9223372036854775807 + 1 != 0; +check if -9223372036854775808 - 1 != 0; ``` ### validation @@ -2276,7 +2270,7 @@ allow if true; ``` revocation ids: -- `3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05` +- `31f01031b8d9cc312c346674625a2218b19a126e931318dc02d8d53aec2775faecd3f848f60c1446573c37ea0664fefc768f35ba5ce4365b83ff06f0c0409b0e` authorizer world: ``` @@ -2289,9 +2283,9 @@ World { 0, ), checks: [ - "check if true || -9223372036854775808 - 1 != 0", - "check if true || 10000000000 * 10000000000 != 0", - "check if true || 9223372036854775807 + 1 != 0", + "check if -9223372036854775808 - 1 != 0", + "check if 10000000000 * 10000000000 != 0", + "check if 9223372036854775807 + 1 != 0", ], }, ] @@ -2315,12 +2309,12 @@ symbols: ["abcD12x", "abcD12"] public keys: [] ``` -check if 1 != 3; -check if 1 | 2 ^ 3 == 0; -check if "abcD12x" != "abcD12"; -check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z; -check if hex:12abcd != hex:12ab; -check if [1, 4] != [1, 2]; +check if 1 !== 3; +check if 1 | 2 ^ 3 === 0; +check if "abcD12x" !== "abcD12"; +check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z; +check if hex:12abcd !== hex:12ab; +check if [1, 4] !== [1, 2]; ``` ### validation @@ -2344,12 +2338,12 @@ World { 0, ), checks: [ - "check if \"abcD12x\" != \"abcD12\"", - "check if 1 != 3", - "check if 1 | 2 ^ 3 == 0", - "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", - "check if [1, 4] != [1, 2]", - "check if hex:12abcd != hex:12ab", + "check if \"abcD12x\" !== \"abcD12\"", + "check if 1 !== 3", + "check if 1 | 2 ^ 3 === 0", + "check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z", + "check if [1, 4] !== [1, 2]", + "check if hex:12abcd !== hex:12ab", ], }, ] @@ -2386,7 +2380,7 @@ allow if true; ``` revocation ids: -- `2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07` +- `2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b` authorizer world: ``` @@ -2429,7 +2423,7 @@ allow if true; ``` revocation ids: -- `2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07` +- `2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b` authorizer world: ``` @@ -2466,7 +2460,7 @@ result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedB ------------------------------ -## test null: test30_null.bc +## test null: test030_null.bc ### token authority: @@ -2489,7 +2483,7 @@ allow if true; ``` revocation ids: -- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` authorizer world: ``` @@ -2533,7 +2527,7 @@ allow if true; ``` revocation ids: -- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` authorizer world: ``` @@ -2577,7 +2571,7 @@ allow if true; ``` revocation ids: -- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` authorizer world: ``` @@ -2621,7 +2615,7 @@ allow if true; ``` revocation ids: -- `bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003` +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` authorizer world: ``` @@ -2656,3 +2650,317 @@ World { result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` + +------------------------------ + +## test heterogeneous equal: test031_heterogeneous_equal.bc +### token + +authority: +symbols: ["fact", "value", "fact2"] + +public keys: [] + +``` +check if fact(1, $value), 1 == $value; +check if fact2(1, $value), 1 != $value; +``` + +### validation for "authorized same type" + +authorizer code: +``` +fact(1, 1); +fact2(1, 2); + +allow if true; +``` + +revocation ids: +- `d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(1, 1)", + "fact2(1, 2)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "unauthorized failed logic different type" + +authorizer code: +``` +fact(1, true); +fact2(1, false); + +allow if true; +``` + +revocation ids: +- `d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(1, true)", + "fact2(1, false)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(1, $value), 1 == $value" })] }))` + + +------------------------------ + +## test laziness and closures: test032_laziness_closures.bc +### token + +authority: +symbols: ["x", "p", "q"] + +public keys: [] + +``` +check if !false && true; +check if false || true; +check if (true || false) && true; +check if !(false && "x".intersection("x")); +check if true || "x".intersection("x"); +check if [1, 2, 3].all($p -> $p > 0); +check if ![1, 2, 3].all($p -> $p == 2); +check if [1, 2, 3].any($p -> $p > 2); +check if ![1, 2, 3].any($p -> $p > 3); +check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q)); +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if ![1, 2, 3].all($p -> $p == 2)", + "check if ![1, 2, 3].any($p -> $p > 3)", + "check if !false && true", + "check if (true || false) && true", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if false || true", + "check if true || \"x\".intersection(\"x\")", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "shadowing" + +authorizer code: +``` +allow if [true].any($p -> [true].all($p -> $p)); +``` + +revocation ids: +- `ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if ![1, 2, 3].all($p -> $p == 2)", + "check if ![1, 2, 3].any($p -> $p > 3)", + "check if !false && true", + "check if (true || false) && true", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if false || true", + "check if true || \"x\".intersection(\"x\")", + ], + }, +] + policies: [ + "allow if [true].any($p -> [true].all($p -> $p))", +] +} +``` + +result: `Err(Execution(ShadowedVariable))` + + +------------------------------ + +## test .type(): test033_typeof.bc +### token + +authority: +symbols: ["integer", "string", "test", "date", "bytes", "bool", "set", "null", "t"] + +public keys: [] + +``` +integer(1); +string("test"); +date(2023-12-28T00:00:00Z); +bytes(hex:aa); +bool(true); +set([false, true]); +null(null); +check if 1.type() == "integer"; +check if integer($t), $t.type() == "integer"; +check if "test".type() == "string"; +check if string($t), $t.type() == "string"; +check if (2023-12-28T00:00:00Z).type() == "date"; +check if date($t), $t.type() == "date"; +check if hex:aa.type() == "bytes"; +check if bytes($t), $t.type() == "bytes"; +check if true.type() == "bool"; +check if bool($t), $t.type() == "bool"; +check if [false, true].type() == "set"; +check if set($t), $t.type() == "set"; +check if null.type() == "null"; +check if null($t), $t.type() == "null"; +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `be401996253dce45ac3d8b2f4b289af1f2cc2a4447a8265a1a2ca879c43377978ffc5ac6633053cd7c30e7c33cf258a37767226834bc80b005c48eb0229c4502` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + Some( + 0, + ), + }, + facts: [ + "bool(true)", + "bytes(hex:aa)", + "date(2023-12-28T00:00:00Z)", + "integer(1)", + "null(null)", + "set([false, true])", + "string(\"test\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if \"test\".type() == \"string\"", + "check if (2023-12-28T00:00:00Z).type() == \"date\"", + "check if 1.type() == \"integer\"", + "check if [false, true].type() == \"set\"", + "check if bool($t), $t.type() == \"bool\"", + "check if bytes($t), $t.type() == \"bytes\"", + "check if date($t), $t.type() == \"date\"", + "check if hex:aa.type() == \"bytes\"", + "check if integer($t), $t.type() == \"integer\"", + "check if null($t), $t.type() == \"null\"", + "check if null.type() == \"null\"", + "check if set($t), $t.type() == \"set\"", + "check if string($t), $t.type() == \"string\"", + "check if true.type() == \"bool\"", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + diff --git a/samples/current/samples.json b/samples/current/samples.json index 4af6b9c..a68baa6 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -1245,7 +1245,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if true;\ncheck if !false;\ncheck if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if true == true;\ncheck if false == false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 == 3;\ncheck if 1 + 2 * 3 - 4 / 2 == 5;\ncheck if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" == \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12\".length() == 6;\ncheck if \"é\".length() == 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z;\ncheck if hex:12ab == hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] == [1, 2];\ncheck if [1, 2].intersection([2, 3]) == [2];\ncheck if [1, 2].union([2, 3]) == [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() == 2;\n" + "code": "check if true;\ncheck if !false;\ncheck if true === true;\ncheck if false === false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 === 3;\ncheck if 1 + 2 * 3 - 4 / 2 === 5;\ncheck if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" === \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" === \"abcD12\";\ncheck if \"abcD12\".length() === 6;\ncheck if \"é\".length() === 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z;\ncheck if hex:12ab === hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] === [1, 2];\ncheck if [1, 2].intersection([2, 3]) === [2];\ncheck if [1, 2].union([2, 3]) === [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() === 2;\n" } ], "validations": { @@ -1258,16 +1258,14 @@ "origin": 0, "checks": [ "check if !false", - "check if !false && true", - "check if \"aaabde\" == \"aaa\" + \"b\" + \"de\"", + "check if \"aaabde\" === \"aaa\" + \"b\" + \"de\"", "check if \"aaabde\".contains(\"abd\")", "check if \"aaabde\".matches(\"a*c?.e\")", - "check if \"abcD12\" == \"abcD12\"", - "check if \"abcD12\".length() == 6", - "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")", - "check if \"é\".length() == 2", - "check if (true || false) && true", - "check if 1 + 2 * 3 - 4 / 2 == 5", + "check if \"abcD12\" === \"abcD12\"", + "check if \"abcD12\".length() === 6", + "check if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\")", + "check if \"é\".length() === 2", + "check if 1 + 2 * 3 - 4 / 2 === 5", "check if 1 < 2", "check if 1 <= 1", "check if 1 <= 2", @@ -1276,28 +1274,27 @@ "check if 2 >= 2", "check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z", "check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z", - "check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z", + "check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", - "check if 3 == 3", + "check if 3 === 3", "check if [\"abc\", \"def\"].contains(\"abc\")", "check if [1, 2, 3].intersection([1, 2]).contains(1)", - "check if [1, 2, 3].intersection([1, 2]).length() == 2", - "check if [1, 2] == [1, 2]", + "check if [1, 2, 3].intersection([1, 2]).length() === 2", + "check if [1, 2] === [1, 2]", "check if [1, 2].contains(2)", "check if [1, 2].contains([2])", - "check if [1, 2].intersection([2, 3]) == [2]", - "check if [1, 2].union([2, 3]) == [1, 2, 3]", + "check if [1, 2].intersection([2, 3]) === [2]", + "check if [1, 2].union([2, 3]) === [1, 2, 3]", "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)", "check if [false, true].contains(true)", "check if [hex:12ab, hex:34de].contains(hex:34de)", - "check if false == false", - "check if false || true", - "check if hex:12ab == hex:12ab", + "check if false === false", + "check if hex:12ab === hex:12ab", "check if true", - "check if true == true" + "check if true === true" ] } ], @@ -1310,7 +1307,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "3d5b23b502b3dd920bfb68b9039164d1563bb8927210166fa5c17f41b76b31bb957bc2ed3318452958f658baa2d398fe4cf25c58a27e6c8bc42c9702c8aa1b0c" + "d0420227266e3583a42dfaa0e38550d99f681d150dd18856f3af9a697bc9c5c8bf06b4b0fe5b9df0377d1b963574e2fd210a0a76a8b0756a65f640c602bebd07" ] } } @@ -1798,7 +1795,7 @@ "authorizer_code": "allow if true;\n", "revocation_ids": [ "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03", - "93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405" + "342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03" ] } } @@ -1939,26 +1936,34 @@ { "symbols": [], "public_keys": [ - "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" ], "external_key": "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", "code": "query(1);\nquery(1, 2) <- query(1), query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], - "public_keys": [], + "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" + ], "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "code": "query(2);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], - "public_keys": [], + "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" + ], "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "code": "query(3);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136" ], "external_key": null, @@ -2082,10 +2087,10 @@ "authorizer_code": "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\nallow if true;\n", "revocation_ids": [ "3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04", - "45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400", - "179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703", - "edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d", - "6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07" + "6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d", + "5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04", + "c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09", + "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900" ] } } @@ -2098,7 +2103,7 @@ "symbols": [], "public_keys": [], "external_key": null, - "code": "check if true || 10000000000 * 10000000000 != 0;\ncheck if true || 9223372036854775807 + 1 != 0;\ncheck if true || -9223372036854775808 - 1 != 0;\n" + "code": "check if 10000000000 * 10000000000 != 0;\ncheck if 9223372036854775807 + 1 != 0;\ncheck if -9223372036854775808 - 1 != 0;\n" } ], "validations": { @@ -2110,9 +2115,9 @@ { "origin": 0, "checks": [ - "check if true || -9223372036854775808 - 1 != 0", - "check if true || 10000000000 * 10000000000 != 0", - "check if true || 9223372036854775807 + 1 != 0" + "check if -9223372036854775808 - 1 != 0", + "check if 10000000000 * 10000000000 != 0", + "check if 9223372036854775807 + 1 != 0" ] } ], @@ -2127,7 +2132,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05" + "31f01031b8d9cc312c346674625a2218b19a126e931318dc02d8d53aec2775faecd3f848f60c1446573c37ea0664fefc768f35ba5ce4365b83ff06f0c0409b0e" ] } } @@ -2143,7 +2148,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if 1 != 3;\ncheck if 1 | 2 ^ 3 == 0;\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if hex:12abcd != hex:12ab;\ncheck if [1, 4] != [1, 2];\n" + "code": "check if 1 !== 3;\ncheck if 1 | 2 ^ 3 === 0;\ncheck if \"abcD12x\" !== \"abcD12\";\ncheck if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z;\ncheck if hex:12abcd !== hex:12ab;\ncheck if [1, 4] !== [1, 2];\n" } ], "validations": { @@ -2155,12 +2160,12 @@ { "origin": 0, "checks": [ - "check if \"abcD12x\" != \"abcD12\"", - "check if 1 != 3", - "check if 1 | 2 ^ 3 == 0", - "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", - "check if [1, 4] != [1, 2]", - "check if hex:12abcd != hex:12ab" + "check if \"abcD12x\" !== \"abcD12\"", + "check if 1 !== 3", + "check if 1 | 2 ^ 3 === 0", + "check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z", + "check if [1, 4] !== [1, 2]", + "check if hex:12abcd !== hex:12ab" ] } ], @@ -2222,7 +2227,7 @@ }, "authorizer_code": "test(false);\n\nallow if true;\n", "revocation_ids": [ - "2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07" + "2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b" ] }, "rejection": { @@ -2272,14 +2277,14 @@ }, "authorizer_code": "test(true);\n\nallow if true;\n", "revocation_ids": [ - "2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07" + "2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b" ] } } }, { "title": "test null", - "filename": "test30_null.bc", + "filename": "test030_null.bc", "token": [ { "symbols": [ @@ -2323,7 +2328,7 @@ }, "authorizer_code": "fact(null, null);\n\nallow if true;\n", "revocation_ids": [ - "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" ] }, "rejection1": { @@ -2381,7 +2386,7 @@ }, "authorizer_code": "fact(null, 1);\n\nallow if true;\n", "revocation_ids": [ - "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" ] }, "rejection2": { @@ -2439,7 +2444,7 @@ }, "authorizer_code": "fact(null, true);\n\nallow if true;\n", "revocation_ids": [ - "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" ] }, "rejection3": { @@ -2497,7 +2502,274 @@ }, "authorizer_code": "fact(null, \"abcd\");\n\nallow if true;\n", "revocation_ids": [ - "bbf3ad51a70e935126b334f37be2bf66e90162353c19c524c0d3579ee71034996872b8433b132e6e0b519d371b0ab20481d58c4619183e8997c3744786e8e003" + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" + ] + } + } + }, + { + "title": "test heterogeneous equal", + "filename": "test031_heterogeneous_equal.bc", + "token": [ + { + "symbols": [ + "fact", + "value", + "fact2" + ], + "public_keys": [], + "external_key": null, + "code": "check if fact(1, $value), 1 == $value;\ncheck if fact2(1, $value), 1 != $value;\n" + } + ], + "validations": { + "authorized same type": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(1, 1)", + "fact2(1, 2)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "fact(1, 1);\nfact2(1, 2);\n\nallow if true;\n", + "revocation_ids": [ + "d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d" + ] + }, + "unauthorized failed logic different type": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(1, true)", + "fact2(1, false)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(1, $value), 1 == $value" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(1, true);\nfact2(1, false);\n\nallow if true;\n", + "revocation_ids": [ + "d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d" + ] + } + } + }, + { + "title": "test laziness and closures", + "filename": "test032_laziness_closures.bc", + "token": [ + { + "symbols": [ + "x", + "p", + "q" + ], + "public_keys": [], + "external_key": null, + "code": "check if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if !(false && \"x\".intersection(\"x\"));\ncheck if true || \"x\".intersection(\"x\");\ncheck if [1, 2, 3].all($p -> $p > 0);\ncheck if ![1, 2, 3].all($p -> $p == 2);\ncheck if [1, 2, 3].any($p -> $p > 2);\ncheck if ![1, 2, 3].any($p -> $p > 3);\ncheck if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q));\n" + } + ], + "validations": { + "": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if ![1, 2, 3].all($p -> $p == 2)", + "check if ![1, 2, 3].any($p -> $p > 3)", + "check if !false && true", + "check if (true || false) && true", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if false || true", + "check if true || \"x\".intersection(\"x\")" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08" + ] + }, + "shadowing": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if ![1, 2, 3].all($p -> $p == 2)", + "check if ![1, 2, 3].any($p -> $p > 3)", + "check if !false && true", + "check if (true || false) && true", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if false || true", + "check if true || \"x\".intersection(\"x\")" + ] + } + ], + "policies": [ + "allow if [true].any($p -> [true].all($p -> $p))" + ] + }, + "result": { + "Err": { + "Execution": "ShadowedVariable" + } + }, + "authorizer_code": "allow if [true].any($p -> [true].all($p -> $p));\n", + "revocation_ids": [ + "ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08" + ] + } + } + }, + { + "title": "test .type()", + "filename": "test033_typeof.bc", + "token": [ + { + "symbols": [ + "integer", + "string", + "test", + "date", + "bytes", + "bool", + "set", + "null", + "t" + ], + "public_keys": [], + "external_key": null, + "code": "integer(1);\nstring(\"test\");\ndate(2023-12-28T00:00:00Z);\nbytes(hex:aa);\nbool(true);\nset([false, true]);\nnull(null);\ncheck if 1.type() == \"integer\";\ncheck if integer($t), $t.type() == \"integer\";\ncheck if \"test\".type() == \"string\";\ncheck if string($t), $t.type() == \"string\";\ncheck if (2023-12-28T00:00:00Z).type() == \"date\";\ncheck if date($t), $t.type() == \"date\";\ncheck if hex:aa.type() == \"bytes\";\ncheck if bytes($t), $t.type() == \"bytes\";\ncheck if true.type() == \"bool\";\ncheck if bool($t), $t.type() == \"bool\";\ncheck if [false, true].type() == \"set\";\ncheck if set($t), $t.type() == \"set\";\ncheck if null.type() == \"null\";\ncheck if null($t), $t.type() == \"null\";\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + 0 + ], + "facts": [ + "bool(true)", + "bytes(hex:aa)", + "date(2023-12-28T00:00:00Z)", + "integer(1)", + "null(null)", + "set([false, true])", + "string(\"test\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if \"test\".type() == \"string\"", + "check if (2023-12-28T00:00:00Z).type() == \"date\"", + "check if 1.type() == \"integer\"", + "check if [false, true].type() == \"set\"", + "check if bool($t), $t.type() == \"bool\"", + "check if bytes($t), $t.type() == \"bytes\"", + "check if date($t), $t.type() == \"date\"", + "check if hex:aa.type() == \"bytes\"", + "check if integer($t), $t.type() == \"integer\"", + "check if null($t), $t.type() == \"null\"", + "check if null.type() == \"null\"", + "check if set($t), $t.type() == \"set\"", + "check if string($t), $t.type() == \"string\"", + "check if true.type() == \"bool\"" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "be401996253dce45ac3d8b2f4b289af1f2cc2a4447a8265a1a2ca879c43377978ffc5ac6633053cd7c30e7c33cf258a37767226834bc80b005c48eb0229c4502" ] } } diff --git a/samples/current/test017_expressions.bc b/samples/current/test017_expressions.bc index 1f3234c07694321afef884cd0b547baa27d64096..7be7a4fda92f3feecff08e8c3a68d1c53bea2100 100644 GIT binary patch delta 143 zcmZqYo6gHB^nr(~bs}rc#qOR?Yy~bkE+!6XDG4qXE+zv8E*2ps4j>6+Gjg#=F>&x3NpVSl zRS3aUz~%Uibhxy@aw;$#5Ho=K_`oIs&48=s-PqvCXl}-30@k6&#mdDj(ZB(w8acpr zu_22!LB!Z0uGsvC(VWG>Hd=Wr)8@OAxPNEtWS*FEG0b|$q#^;a{G|u$9k*v2?w(qG o=&iAYt7gQvh+T^=&-mx_DJEi3T~7BAo#{*`R!Q?rE@o2!0FwDK%K!iX diff --git a/samples/current/test024_third_party.bc b/samples/current/test024_third_party.bc index 7bca415c6f4aeff3f27628adbaa6211f6e263493..d2aef52815e08c1d47cfaaec9ad0b8eaa1bc13e4 100644 GIT binary patch delta 149 zcmV;G0BZlr1Ih!Cxd8={xziGHPFJ%uTceGU^8b6lYjwA DDLF|c delta 149 zcmV;G0BZlr1Ih!Cxd8-`xLCT|;|b}> z%G?Sj#b8epkq@pvEYN@lR@=B?SrtgW zV^p2!&o#v7y*c4|mM^o6M_}!R0WSsp4EnTt{TxTWP@!Q)c>ZFTKI$ z8n(0|HCj$n>(PnFTYn$(eskd3wC?9C`-3g2zTN!0+_K<;QLR;6FRO^E-&dZ=ZyD9u z?=o?90DUl7ib<6y*GDla)yIZa{>$9|+`CfJ$W-*@n_Y7mowUXFO?KQ`-|=kfrrq4v zr)5_NFkagEfbW^a-$Rxs^TZ$PY_9xhFLZ5hwY2+M7LevNg^q|dI*wSk9{@1e4uW`9LOEWUq&z0OaNh!U&xp~*jxgR%7;$Shkx2+&oW>*eJEYL2uEZV%?HJ;TmrpS(M60sXpR+HJ76($$4_&M08$L5&%u{p$gWSnGq!f)GnSewIkVnpr^kt?UYznX2? or7*YYqqNVqTbkAhn|KqI{@C$xyx_5reb@Zrnb^rhX delta 627 zcmeC?S;9482m4JXt`!i(pVw?y=j>@H<1lCqRuKyZm zx7lC0`pk4ehw5a_H3<^?w=gJWa5>~GogeS{`oZscj-T88wbcqbJDWVEK2Da(nfB?( z!Um0>$7J+w+<2ZQt?+*?H`|J6TiHL4ANH&Z-L}(0k4@$>V-$M6HWDn8 z9hp>dxcNAfM!ooaR)3ptHMiAE84V-XNopO@4@->rId*bK^$NOEbZ^Y``YL;!8RXtO+4Z{HS(@K`tV(tIo%CEFT;`tNLCeRj z_9{`%VQXUZ7(WJT@A~xPi}hiV&)e7k+{dz&(eG~m+%H>BXR)VJaPUHA zTn<)e(WrmBI;3K5TG-_Lvlk<Yvmj!{b%zx^MV}AuXE_}v-rPzZbvU_)Vo-caIWN|(ROF64_;!C z4~jSceCyWN)xYe4_sJQj)zSr59cr7QzyGw8+V5>Mf=k#I)OyyifgQ{$b%c>CYVv;; ztI6@K9u8Sa1{sDgZ@;jsHoiS=d&KeDYZE5(>*}^YvfL!Faf(l9)BfB#>3=Jp|I|2C fum7J<@6m&`N8|(_9A5q6`p)cm_t+;tXH@|Jec${W diff --git a/samples/current/test027_integer_wraparound.bc b/samples/current/test027_integer_wraparound.bc index 50aa63b93cca6a963d474c44f4ea66bf90aba4b0..a3a2f712bbe52d427d020ea7d4d4aee910bd6c11 100644 GIT binary patch delta 130 zcmX@fw3JCm=pQ53WJU=#BRwu1E+!6XDYc0bs@!5o+z=2~pGy}kt3Gjp8l%|6y&4XN z9|R0{+&p8bW0F>q6s07wah6ctWMPRrOgFAty-_dy_2%*qk8eC8Zs9iOuh>%l{VD4= X-4*l1EV}tW+lK=Vv-u{gGO7Rorf4d- delta 166 zcmZ3=bdpIzXb}_Fc18&nBP%WoE+!6XDI+cxE+zxUi9)L4B3vv|OdNa|QcegdYc5N$ zE@P;!A~klXu8A`>9E{x-X|3bhfAIfOwGaAb0WZ0Jaz1@3Ib(vFi(JLoL$2HZ3Z*ii lztdr86o0^({q34*RqlF+uhRNT?M7FW~0`rL|yBLSoUZetC9l2a%E_N?jpT diff --git a/samples/current/test030_null.bc b/samples/current/test030_null.bc new file mode 100644 index 0000000000000000000000000000000000000000..8adc4fabf6c5c26ae9874a0392be6add374dcc11 GIT binary patch literal 248 zcmWf-$jFt>#gdkoT*Ad#mY7qTD#2!?$)(Q4#33!j!_mMY#N@;v#LUsiAtlVk$^~L@ zv2X#!xLBl^I7E%KiB&2lz$B!?!62j{5PCddv@WUpvZ=0LBolt%0ww9OUdj6GSpDX;F9ljfu zNWJ4>@0ec7r(Td5dA+ri?~~Vg0e&SVE`^yds`(~H1k1hK%KTqcEl*qd(4v59;hwqD M@>*LW?&~H30P875G5`Po literal 0 HcmV?d00001 diff --git a/samples/current/test031_heterogeneous_equal.bc b/samples/current/test031_heterogeneous_equal.bc new file mode 100644 index 0000000000000000000000000000000000000000..feb38732a79185bad7ddf3f375abfa33d4795d5e GIT binary patch literal 253 zcmWf-#>kb!#gdkoT*Ad#mY7qT%Eb!e7)h`hX>zG^F>y!>@o+S72r&sT3Ndpua!3ht zv2X!7T&!FmE*Faw6Nf00(kA>$#e`Hi7=#oALXQV*To@2(zFyS)nA$F*35~%`Eh&Matn?wAGu}Nf|FTqMC1FM6leut<3*L)$+8J4=oC) Q7VeoVEw8mD;=XPo0G*jkQ~&?~ literal 0 HcmV?d00001 diff --git a/samples/current/test032_laziness_closures.bc b/samples/current/test032_laziness_closures.bc new file mode 100644 index 0000000000000000000000000000000000000000..dfd0c5b2c838bb524adcb281c55d47a593e1c955 GIT binary patch literal 758 zcmWeS&&u_Lg^RI*i?M)=GT|};%jiqK72YQjI6jUz^aY71i1LDc(|AZ7=f4xh?%)0 zl*Bk1!S;bDpq~X8gg~}J+$d?}z-0&4YeAG=Ca_*nu!|)jVM(Ix5ECG_OOa?hGm^`t zpthHDm4e-$kH!6=O2KG;XM~s_WU6E=1Pd!>V3>fyg;hvWNt~kz9#+7Z0`WkBB?=~` zz@#|X^HM@891KDV0-?tPHZBZ^G+!@jeoSqbQS!_f<7Ms{u8?8>gDcZU|d(pctGtG^QZGHtt zRy|$6Z*SM)*nJ#IN?ZyvUsUr=j0l!{x0U(7s9K)3@}Wfm)xte<3;6N8Z=mpm5}hqRO=7Yi5A zd@dFtCJtsURxW0V1`aM3DJBk4BONX+kP;ydkQV0_~;7_J({rA`b;2DW1w z2uv-w41}o`QsH0_QV<9|9Tc z>}lA*dZcfI(i~SNC19k@d{NCeF(O#*-B#xRqH1~C%7+#OR15dam6q4q5^-NQ5diyo Bim(6x literal 0 HcmV?d00001 diff --git a/schema.proto b/schema.proto index bc6cb29..e2dfda2 100644 --- a/schema.proto +++ b/schema.proto @@ -80,6 +80,7 @@ message CheckV2 { enum Kind { One = 0; All = 1; + Reject = 2; } } @@ -97,6 +98,7 @@ message TermV2 { bytes bytes = 5; bool bool = 6; TermSet set = 7; + Empty null = 8; } } @@ -113,6 +115,7 @@ message Op { TermV2 value = 1; OpUnary unary = 2; OpBinary Binary = 3; + OpClosure closure = 4; } } @@ -121,6 +124,7 @@ message OpUnary { Negate = 0; Parens = 1; Length = 2; + TypeOf = 3; } required Kind kind = 1; @@ -149,11 +153,22 @@ message OpBinary { BitwiseOr = 18; BitwiseXor = 19; NotEqual = 20; + HeterogeneousEqual = 21; + HeterogeneousNotEqual = 22; + LazyAnd = 23; + LazyOr = 24; + All = 25; + Any = 26; } required Kind kind = 1; } +message OpClosure { + repeated uint32 params = 1; + repeated Op ops = 2; +} + message Policy { enum Kind { Allow = 0; @@ -228,4 +243,4 @@ message SnapshotBlock { repeated CheckV2 checks_v2 = 5; repeated Scope scope = 6; optional PublicKey externalKey = 7; -} \ No newline at end of file +} From 79e1b696722336582151022b24ed961eeaa9a486 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Thu, 24 Oct 2024 18:13:31 +0200 Subject: [PATCH 05/19] Document lenient (heterogeneous) equality --- SPECIFICATIONS.md | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index c0d5861..bdb89f4 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -138,29 +138,29 @@ rules application does not generate any new facts, we can stop. #### Data types An _integer_ is a signed 64 bits integer. It supports the following operations: -lower than, greater than, lower than or equal, greater than or equal, equal, -not equal, set inclusion, addition, subtraction, mutiplication, division, -bitwise and, bitwise or, bitwise xor. +lower than, greater than, lower than or equal, greater than or equal, strict equal, +strict not equal, set inclusion, addition, subtraction, mutiplication, division, +bitwise and, bitwise or, bitwise xor, lenient equal, lenient not equal. A _string_ is a suite of UTF-8 characters. It supports the following -operations: prefix, suffix, equal, not equal, set inclusion, regular -expression, concatenation (with `+`), substring test (with `.contains()`). +operations: prefix, suffix, strict equal, strict not equal, set inclusion, regular +expression, concatenation (with `+`), substring test (with `.contains()`), lenient equal, lenient not equal. A _byte array_ is a suite of bytes. It supports the following -operations: equal, not equal, set inclusion. +operations: strict equal, strict not equal, set inclusion, lenient equal, lenient not equal. A _date_ is a 64 bit unsigned integer representing a UTC unix timestamp (number of seconds since 1970-01-01T00:00:00Z). It supports -the following operations: `<`, `<=` (before), `>`, `>=` (after), equal, -not equal, set inclusion. +the following operations: `<`, `<=` (before), `>`, `>=` (after), strict equal, +strict not equal, set inclusion, lenient equal, lenient not equal. A _boolean_ is `true` or `false`. It supports the following operations: -`==`, `!=`, `||`, `&&`, set inclusion. +`===` (strict equal), `!==` (strict not equal), `||`, `&&`, set inclusion, `==` (lenient equal), `!=` (lenient not equal). -A _null_ is a default type indicating the absence of value. It supports the operations `==` and `!=` with any other type. _null_ is always equal to itself, and not equal to any other type +A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal). `null` is always equal to itself. A _set_ is a deduplicated list of terms of the same type. It cannot contain -variables or other sets. It supports equal, not equal, , intersection, union, -set inclusion. +variables or other sets. It supports strict equal, strict not equal, intersection, union, +set inclusion, lenient equal, lenient not equal. #### Grammar @@ -206,7 +206,7 @@ The logic language is described by the following EBNF grammar: ::= ([a-z] | [A-Z] ) ([a-z] | [A-Z] | [0-9] | "_" )* ::= | ("(" ? ? ")") - ::= "<" | ">" | "<=" | ">=" | "==" | "!=" | "&&" | "||" | "+" | "-" | "*" | "/" | "&" | "|" | "^" + ::= "<" | ">" | "<=" | ">=" | "===" | "!==" | "&&" | "||" | "+" | "-" | "*" | "/" | "&" | "|" | "^" | "==" | "!==" ::= (" " | "\t" | "\n")+ ``` @@ -454,8 +454,8 @@ Here are the currently defined binary operations: - _greater than_, defined on integers and dates, returns a boolean - _less or equal_, defined on integers and dates, returns a boolean - _greater or equal_, defined on integers and dates, returns a boolean -- _equal_, defined on integers, strings, byte arrays, dates, set, returns a boolean -- _not equal_, defined on integers, strings, byte arrays, dates, set, returns a boolean (v4 only) +- _strict equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean +- _strict not equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean (v4 only) - _contains_ takes a set and another value as argument, returns a boolean. Between two sets, indicates if the first set is a superset of the second one. between two strings, indicates a substring test. - _prefix_, defined on strings, returns a boolean @@ -472,10 +472,16 @@ Here are the currently defined binary operations: - _bitwiseAnd_, defined on integers, returns an integer (v4 only) - _bitwiseOr_, defined on integers, returns an integer (v4 only) - _bitwiseXor_, defined on integers, returns an integer (v4 only) +- _lenient equal_, defined on all types, returns a boolean (v6 only) +- _lenient not equal_, defined on all types, returns a boolean (v6 only) Integer operations must have overflow checks. If it overflows, the expression fails. +Strict equality fails with a type error when trying to compare different types. + +Lenient equality returns false when trying to compare different types. + #### Example The expression `1 + 2 < 4` will translate to the following opcodes: 1, 2, +, 4, < From e46fbbba961ce2820116c3e254312167eadef1f8 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Thu, 24 Oct 2024 18:30:39 +0200 Subject: [PATCH 06/19] Document the `.type()` operation --- SPECIFICATIONS.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index bdb89f4..7431192 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -140,27 +140,27 @@ rules application does not generate any new facts, we can stop. An _integer_ is a signed 64 bits integer. It supports the following operations: lower than, greater than, lower than or equal, greater than or equal, strict equal, strict not equal, set inclusion, addition, subtraction, mutiplication, division, -bitwise and, bitwise or, bitwise xor, lenient equal, lenient not equal. +bitwise and, bitwise or, bitwise xor, lenient equal, lenient not equal, typeof. A _string_ is a suite of UTF-8 characters. It supports the following operations: prefix, suffix, strict equal, strict not equal, set inclusion, regular -expression, concatenation (with `+`), substring test (with `.contains()`), lenient equal, lenient not equal. +expression, concatenation (with `+`), substring test (with `.contains()`), lenient equal, lenient not equal, typeof. A _byte array_ is a suite of bytes. It supports the following -operations: strict equal, strict not equal, set inclusion, lenient equal, lenient not equal. +operations: strict equal, strict not equal, set inclusion, lenient equal, lenient not equal, typeof. A _date_ is a 64 bit unsigned integer representing a UTC unix timestamp (number of seconds since 1970-01-01T00:00:00Z). It supports the following operations: `<`, `<=` (before), `>`, `>=` (after), strict equal, -strict not equal, set inclusion, lenient equal, lenient not equal. +strict not equal, set inclusion, lenient equal, lenient not equal, typeof. A _boolean_ is `true` or `false`. It supports the following operations: -`===` (strict equal), `!==` (strict not equal), `||`, `&&`, set inclusion, `==` (lenient equal), `!=` (lenient not equal). +`===` (strict equal), `!==` (strict not equal), `||`, `&&`, set inclusion, `==` (lenient equal), `!=` (lenient not equal), typeof. -A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal). `null` is always equal to itself. +A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal). `null` is always equal to itself, typeof. A _set_ is a deduplicated list of terms of the same type. It cannot contain variables or other sets. It supports strict equal, strict not equal, intersection, union, -set inclusion, lenient equal, lenient not equal. +set inclusion, lenient equal, lenient not equal, any, all, typeof. #### Grammar @@ -447,6 +447,14 @@ Here are the currently defined unary operations: - _parens_: returns its argument without modification (this is used when printing the expression, to avoid precedence errors) - _length_: defined on strings, byte arrays and sets (for strings, _length_ is defined as the number of bytes in the UTF-8 encoded string; the alternative of counting grapheme clusters would be inconsistent between languages) +- _type_, defined on all types, returns a string (v6 only) + - `integer` + - `string` + - `date` + - `bytes` + - `bool` + - `set` + - `null` Here are the currently defined binary operations: From 27ec12a66988f15e3f7343a7608e583b67bfda5e Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Thu, 24 Oct 2024 18:59:39 +0200 Subject: [PATCH 07/19] Document closures, any/all, eager/short-circuit boolean operators --- SPECIFICATIONS.md | 74 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 7431192..3c3a959 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -154,7 +154,7 @@ the following operations: `<`, `<=` (before), `>`, `>=` (after), strict equal, strict not equal, set inclusion, lenient equal, lenient not equal, typeof. A _boolean_ is `true` or `false`. It supports the following operations: -`===` (strict equal), `!==` (strict not equal), `||`, `&&`, set inclusion, `==` (lenient equal), `!=` (lenient not equal), typeof. +`===` (strict equal), `!==` (strict not equal), eager or, eager and, set inclusion, `==` (lenient equal), `!=` (lenient not equal), typeof, short-circuiting or, short-circuiting and. A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal). `null` is always equal to itself, typeof. @@ -429,7 +429,7 @@ rule. #### Execution Expressions are internally represented as a series of opcodes for a stack based -virtual machine. There are three kinds of opcodes: +virtual machine. There are four kinds of opcodes: - _value_: a raw value of any type. If it is a variable, the variable must also appear in a predicate, so the variable gets a real value for execution. When @@ -438,9 +438,22 @@ virtual machine. There are three kinds of opcodes: it pops a value from the stack, applies the operation, then pushes the result - _binary operation_: an operation that applies on two arguments. When executed, it pops two values from the stack, applies the operation, then pushes the result +- _closure_: a function definition containing the name of parameters and the body of the function expressed as a list of opcodes. Closures can be nested. After executing, the stack must contain only one value, of the boolean type. +##### Closures + +Closures are evaluated recursively. When executing a closure, a new empty stack is created, and the closure opcodes are evaluated. After evaluation, the stack must contain only one value, of any type, which is then pushed on the parent stack. + +The closure arguments are treated the same way as datalog variables and are replaced by their value when the corresponding opcode is evaluated. + +Shadowing (defining a parameter with the same name as a variable already in scope) is not allowed and should be rejected before starting the evaluation. + +Short-circuiting boolean operators (`&&` and `||`) are implemented using closures: the right-hand side is defined in a closure (taking zero arguments) and is only evaluated as needed. + +##### Operations + Here are the currently defined unary operations: - _negate_: boolean negation @@ -473,8 +486,8 @@ Here are the currently defined binary operations: - _sub_, defined on integers, returns an integer - _mul_, defined on integers, returns an integer - _div_, defined on integers, returns an integer -- _and_, defined on booleans, returns a boolean -- _or_, defined on booleans, returns a boolean +- _eager and_, defined on booleans, returns a boolean +- _eager or_, defined on booleans, returns a boolean - _intersection_, defined on sets, return a set that is the intersection of both arguments - _union_, defined on sets, return a set that is the union of both arguments - _bitwiseAnd_, defined on integers, returns an integer (v4 only) @@ -482,6 +495,10 @@ Here are the currently defined binary operations: - _bitwiseXor_, defined on integers, returns an integer (v4 only) - _lenient equal_, defined on all types, returns a boolean (v6 only) - _lenient not equal_, defined on all types, returns a boolean (v6 only) +- _any_, defined on sets, takes a closure term -> boolean, returns a boolean (v6 only) +- _all_, defined on sets, takes a closure term -> boolean, returns a boolean (v6 only) +- _short circuiting and_, defined on booleans, takes a closure () -> boolean, returns a boolean (v6 only) +- _short circuiting or_, defined on booleans, takes a closure () -> boolean, returns a boolean (v6 only) Integer operations must have overflow checks. If it overflows, the expression fails. @@ -492,14 +509,15 @@ Lenient equality returns false when trying to compare different types. #### Example -The expression `1 + 2 < 4` will translate to the following opcodes: 1, 2, +, 4, < +The expression `$a + 2 < 4` will translate to the following opcodes: $a, 2, +, 4, < -Here is how it would be executed: +Here is how it would be executed, given $a is bound to the value 1: ``` +Context: a ~> 1 Op | stack | [ ] -1 | [ 1 ] +$a | [ 1 ] 2 | [ 2, 1 ] + | [ 3 ] 4 | [ 4, 3 ] @@ -508,6 +526,48 @@ Op | stack The stack contains only one value, and it is `true`: the expression succeeds. +##### Closures + +The expression `[1,2].any($x -> $x == $a)` will translate to the following opcodes: [1,2], x->[$x, $a, ==], any. + +Here is how it would be executed, given $a is bound to the value 2: + +``` +Context: a ~> 2 +Op | stack + | [ ] +[1,2] | [ [1,2] ] +x->[$x,$a,==] | [ x->[$x,$a,==],[1,2] ] +any | … starting recursive evaluation … + + +Beginning new evaluation +Context: a ~> 2, x ~> 1 +Op | stack + | [] +$x | [ 1 ] +$a | [ 2, 1 ] +== | [ false ] + +The stack contains one value, false. So the evaluation must continue with the next set element. + +Beggining new evaluation +Context: a ~> 2, x ~> 2 +Op | stack + | [] +$x | [ 2 ] +$a | [ 2, 2 ] +== | [ true ] + +The stack contains one value, true. The evaluation can stop here, the evaluation of any can return true. + +Resuming parent stack +Context: a ~> 2 +Op | stack +any | true +``` +The stack contains only one value, and it is `true`: the expression succeeds. + ### Datalog fact generation Datalog fact generation works by repeatedly extending a Datalog _world_ until no new facts are generated. From 92d1c6767be25158a54212453ace560834239026 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 4 Nov 2024 14:06:48 +0100 Subject: [PATCH 08/19] add spec and samples for map and array types --- SPECIFICATIONS.md | 19 +- samples/current/README.md | 210 +++++++++++---- samples/current/samples.json | 245 +++++++++++------- .../current/test031_heterogeneous_equal.bc | Bin 253 -> 748 bytes samples/current/test033_typeof.bc | Bin 882 -> 1034 bytes samples/current/test034_array_map.bc | Bin 0 -> 1951 bytes 6 files changed, 322 insertions(+), 152 deletions(-) create mode 100644 samples/current/test034_array_map.bc diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 3c3a959..2197233 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -77,6 +77,8 @@ _predicates_ over the following types: - _boolean_ - _null_ - _set_ a deduplicated list of values of any type, except _variable_ or _set_ +- _array_ an array of values of any type, expect _variable_ (nested arrays are allowed) +- _map_ a map of key/value pairs. keys must be either strings or integers, values can be of any type, except _variable_ (nested maps are allowed) While a Biscuit token does not use a textual representation for storage, we use one for parsing and pretty printing of Datalog elements. @@ -118,8 +120,10 @@ We will represent the various types as follows: - byte array: `hex:01A2` - date in RFC 3339 format: `1985-04-12T23:20:50.52Z` - boolean: `true` or `false` -- null: `null`, supported since block version 5 -- set: `[ "a", "b", "c"]` +- null: `null`, supported since block version 6 +- set: `{ "a", "b", "c"}` +- array: `[ "a", true, null]`, supported since block version 6 +- map: `{ "a": true, 12: "a" }`, supported since block version 6 As an example, assuming we have the following facts: `parent("a", "b")`, `parent("b", "c")`, `parent("c", "d")`. If we apply the rule @@ -162,6 +166,10 @@ A _set_ is a deduplicated list of terms of the same type. It cannot contain variables or other sets. It supports strict equal, strict not equal, intersection, union, set inclusion, lenient equal, lenient not equal, any, all, typeof. +An _array_ is an ordered list of terms, not necessarily of the same type. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal), contains, prefix, suffix, get, typeof. + +A _map_ is an unordered collection of key/value pairs, with unique keys. Keys are either strings or integers, values can be any term. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal), contains, get, typeof. + #### Grammar The logic language is described by the following EBNF grammar: @@ -197,7 +205,10 @@ The logic language is described by the following EBNF grammar: ::= "true" | "false" ::= "null" ::= [0-9]* "-" [0-9] [0-9] "-" [0-9] [0-9] "T" [0-9] [0-9] ":" [0-9] [0-9] ":" [0-9] [0-9] ( "Z" | ( ("+" | "-") [0-9] [0-9] ":" [0-9] [0-9] )) - ::= "[" ? ( ( ? "," ? )* ? )? "]" + ::= "{" ? ( ( ? "," ? )* ? )? "}" + ::= "[" ? ( ( ? "," ? )* ? )? "]" + ::= ( | ) ? ":" ? + ::= "{" ? ( ( ? "," ? )* ? )? "}" ::= (? ? )* ::= | ( ? ) @@ -305,7 +316,7 @@ succeeds (in the case of `reject if`, the check will fail if any query matches). - a `reject if` query succeeds if no set of facts matches the body and expressions `check all` can only be used starting from block version 4. -`reject if` can only be used starting from block version 5. +`reject if` can only be used starting from block version 6. Here are some examples of writing checks: diff --git a/samples/current/README.md b/samples/current/README.md index 7ff9275..06b48e3 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -825,7 +825,7 @@ public keys: [] ``` valid_date("file1") <- time($0), resource("file1"), $0 <= 2030-12-31T12:59:59Z; -valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !["file1"].contains($1); +valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{"file1"}.contains($1); check if valid_date($0), resource($0); ``` @@ -886,7 +886,7 @@ World { ), rules: [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)", + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)", ], }, ] @@ -953,7 +953,7 @@ World { ), rules: [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)", + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)", ], }, ] @@ -1246,17 +1246,17 @@ check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z; check if hex:12ab === hex:12ab; -check if [1, 2].contains(2); -check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z); -check if [false, true].contains(true); -check if ["abc", "def"].contains("abc"); -check if [hex:12ab, hex:34de].contains(hex:34de); -check if [1, 2].contains([2]); -check if [1, 2] === [1, 2]; -check if [1, 2].intersection([2, 3]) === [2]; -check if [1, 2].union([2, 3]) === [1, 2, 3]; -check if [1, 2, 3].intersection([1, 2]).contains(1); -check if [1, 2, 3].intersection([1, 2]).length() === 2; +check if {1, 2}.contains(2); +check if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z); +check if {false, true}.contains(true); +check if {"abc", "def"}.contains("abc"); +check if {hex:12ab, hex:34de}.contains(hex:34de); +check if {1, 2}.contains({2}); +check if {1, 2} === {1, 2}; +check if {1, 2}.intersection({2, 3}) === {2}; +check if {1, 2}.union({2, 3}) === {1, 2, 3}; +check if {1, 2, 3}.intersection({1, 2}).contains(1); +check if {1, 2, 3}.intersection({1, 2}).length() === 2; ``` ### validation @@ -1303,21 +1303,21 @@ World { "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 3 === 3", - "check if [\"abc\", \"def\"].contains(\"abc\")", - "check if [1, 2, 3].intersection([1, 2]).contains(1)", - "check if [1, 2, 3].intersection([1, 2]).length() === 2", - "check if [1, 2] === [1, 2]", - "check if [1, 2].contains(2)", - "check if [1, 2].contains([2])", - "check if [1, 2].intersection([2, 3]) === [2]", - "check if [1, 2].union([2, 3]) === [1, 2, 3]", - "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)", - "check if [false, true].contains(true)", - "check if [hex:12ab, hex:34de].contains(hex:34de)", "check if false === false", "check if hex:12ab === hex:12ab", "check if true", "check if true === true", + "check if {\"abc\", \"def\"}.contains(\"abc\")", + "check if {1, 2, 3}.intersection({1, 2}).contains(1)", + "check if {1, 2, 3}.intersection({1, 2}).length() === 2", + "check if {1, 2} === {1, 2}", + "check if {1, 2}.contains(2)", + "check if {1, 2}.contains({2})", + "check if {1, 2}.intersection({2, 3}) === {2}", + "check if {1, 2}.union({2, 3}) === {1, 2, 3}", + "check if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z)", + "check if {false, true}.contains(true)", + "check if {hex:12ab, hex:34de}.contains(hex:34de)", ], }, ] @@ -1901,7 +1901,7 @@ symbols: ["allowed_operations", "A", "B", "op", "allowed"] public keys: [] ``` -allowed_operations(["A", "B"]); +allowed_operations({"A", "B"}); check all operation($op), allowed_operations($allowed), $allowed.contains($op); ``` @@ -1938,7 +1938,7 @@ World { ), }, facts: [ - "allowed_operations([\"A\", \"B\"])", + "allowed_operations({\"A\", \"B\"})", ], }, ] @@ -1993,7 +1993,7 @@ World { ), }, facts: [ - "allowed_operations([\"A\", \"B\"])", + "allowed_operations({\"A\", \"B\"})", ], }, ] @@ -2314,7 +2314,7 @@ check if 1 | 2 ^ 3 === 0; check if "abcD12x" !== "abcD12"; check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z; check if hex:12abcd !== hex:12ab; -check if [1, 4] !== [1, 2]; +check if {1, 4} !== {1, 2}; ``` ### validation @@ -2342,8 +2342,8 @@ World { "check if 1 !== 3", "check if 1 | 2 ^ 3 === 0", "check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z", - "check if [1, 4] !== [1, 2]", "check if hex:12abcd !== hex:12ab", + "check if {1, 4} !== {1, 2}", ], }, ] @@ -2776,11 +2776,11 @@ check if false || true; check if (true || false) && true; check if !(false && "x".intersection("x")); check if true || "x".intersection("x"); -check if [1, 2, 3].all($p -> $p > 0); -check if ![1, 2, 3].all($p -> $p == 2); -check if [1, 2, 3].any($p -> $p > 2); -check if ![1, 2, 3].any($p -> $p > 3); -check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q)); +check if {1, 2, 3}.all($p -> $p > 0); +check if !{1, 2, 3}.all($p -> $p == 2); +check if {1, 2, 3}.any($p -> $p > 2); +check if !{1, 2, 3}.any($p -> $p > 3); +check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q)); ``` ### validation @@ -2805,15 +2805,15 @@ World { ), checks: [ "check if !(false && \"x\".intersection(\"x\"))", - "check if ![1, 2, 3].all($p -> $p == 2)", - "check if ![1, 2, 3].any($p -> $p > 3)", "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", "check if (true || false) && true", - "check if [1, 2, 3].all($p -> $p > 0)", - "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", - "check if [1, 2, 3].any($p -> $p > 2)", "check if false || true", "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)", ], }, ] @@ -2846,15 +2846,15 @@ World { ), checks: [ "check if !(false && \"x\".intersection(\"x\"))", - "check if ![1, 2, 3].all($p -> $p == 2)", - "check if ![1, 2, 3].any($p -> $p > 3)", "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", "check if (true || false) && true", - "check if [1, 2, 3].all($p -> $p > 0)", - "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", - "check if [1, 2, 3].any($p -> $p > 2)", "check if false || true", "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)", ], }, ] @@ -2873,7 +2873,7 @@ result: `Err(Execution(ShadowedVariable))` ### token authority: -symbols: ["integer", "string", "test", "date", "bytes", "bool", "set", "null", "t"] +symbols: ["integer", "string", "test", "date", "bytes", "bool", "set", "null", "array", "map", "a", "t"] public keys: [] @@ -2883,8 +2883,10 @@ string("test"); date(2023-12-28T00:00:00Z); bytes(hex:aa); bool(true); -set([false, true]); +set({false, true}); null(null); +array([1, 2, 3]); +map({"a": true}); check if 1.type() == "integer"; check if integer($t), $t.type() == "integer"; check if "test".type() == "string"; @@ -2895,10 +2897,12 @@ check if hex:aa.type() == "bytes"; check if bytes($t), $t.type() == "bytes"; check if true.type() == "bool"; check if bool($t), $t.type() == "bool"; -check if [false, true].type() == "set"; +check if {false, true}.type() == "set"; check if set($t), $t.type() == "set"; check if null.type() == "null"; check if null($t), $t.type() == "null"; +check if array($t), $t.type() == "array"; +check if map($t), $t.type() == "map"; ``` ### validation @@ -2909,7 +2913,7 @@ allow if true; ``` revocation ids: -- `be401996253dce45ac3d8b2f4b289af1f2cc2a4447a8265a1a2ca879c43377978ffc5ac6633053cd7c30e7c33cf258a37767226834bc80b005c48eb0229c4502` +- `c8f7ff152b40a3e8f3ab19a435ccd16c41288762864022895b99d2abb6330c794b3f1378a4651b31d249f4c35b69246d88124d40e05e634a0eb9ca9e54b1ca0a` authorizer world: ``` @@ -2922,12 +2926,14 @@ World { ), }, facts: [ + "array([1, 2, 3])", "bool(true)", "bytes(hex:aa)", "date(2023-12-28T00:00:00Z)", "integer(1)", + "map({\"a\": true})", "null(null)", - "set([false, true])", + "set({false, true})", "string(\"test\")", ], }, @@ -2942,17 +2948,119 @@ World { "check if \"test\".type() == \"string\"", "check if (2023-12-28T00:00:00Z).type() == \"date\"", "check if 1.type() == \"integer\"", - "check if [false, true].type() == \"set\"", + "check if array($t), $t.type() == \"array\"", "check if bool($t), $t.type() == \"bool\"", "check if bytes($t), $t.type() == \"bytes\"", "check if date($t), $t.type() == \"date\"", "check if hex:aa.type() == \"bytes\"", "check if integer($t), $t.type() == \"integer\"", + "check if map($t), $t.type() == \"map\"", "check if null($t), $t.type() == \"null\"", "check if null.type() == \"null\"", "check if set($t), $t.type() == \"set\"", "check if string($t), $t.type() == \"string\"", "check if true.type() == \"bool\"", + "check if {false, true}.type() == \"set\"", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + + +------------------------------ + +## test array and map operations (v5 blocks): test034_array_map.bc +### token + +authority: +symbols: ["a", "b", "c", "p", "d", "A", "kv", "id", "roles"] + +public keys: [] + +``` +check if [1, 2, 1].length() == 3; +check if ["a", "b"] != true; +check if ["a", "b"] != [1, 2, 3]; +check if ["a", "b"] == ["a", "b"]; +check if ["a", "b"] === ["a", "b"]; +check if ["a", "b"] !== ["a", "c"]; +check if ["a", "b", "c"].contains("c"); +check if [1, 2, 3].starts_with([1, 2]); +check if [4, 5, 6].ends_with([6]); +check if [1, 2, "a"].get(2) == "a"; +check if [1, 2].get(3) == null; +check if [1, 2, 3].all($p -> $p > 0); +check if [1, 2, 3].any($p -> $p > 2); +check if {"a": 1, "b": 2, "c": 3, "d": 4}.length() == 4; +check if {1: "a", 2: "b"} != true; +check if {1: "a", 2: "b"} != {"a": 1, "b": 2}; +check if {1: "a", 2: "b"} == {1: "a", 2: "b"}; +check if {1: "a", 2: "b"} !== {"a": 1, "b": 2}; +check if {1: "a", 2: "b"} === {1: "a", 2: "b"}; +check if {"a": 1, "b": 2, "c": 3, "d": 4}.contains("d"); +check if {1: "A", "a": 1, "b": 2}.get("a") == 1; +check if {1: "A", "a": 1, "b": 2}.get(1) == "A"; +check if {1: "A", "a": 1, "b": 2}.get("c") == null; +check if {1: "A", "a": 1, "b": 2}.get(2) == null; +check if {"a": 1, "b": 2}.all($kv -> $kv.get(0) != "c" && $kv.get(1) < 3); +check if {1: "A", "a": 1, "b": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == "A"); +check if {"user": {"id": 1, "roles": ["admin"]}}.get("user").get("roles").contains("admin"); +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `8041144f92616477f1cd00b81e8be79581202a3853b08b3d477797b0d91f30c02fd7c01ca91a00f8a222d6be4794cc287baa361a1a00d5941518c1917967ec03` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if [\"a\", \"b\", \"c\"].contains(\"c\")", + "check if [\"a\", \"b\"] != [1, 2, 3]", + "check if [\"a\", \"b\"] != true", + "check if [\"a\", \"b\"] !== [\"a\", \"c\"]", + "check if [\"a\", \"b\"] == [\"a\", \"b\"]", + "check if [\"a\", \"b\"] === [\"a\", \"b\"]", + "check if [1, 2, \"a\"].get(2) == \"a\"", + "check if [1, 2, 1].length() == 3", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if [1, 2, 3].starts_with([1, 2])", + "check if [1, 2].get(3) == null", + "check if [4, 5, 6].ends_with([6])", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.contains(\"d\")", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.length() == 4", + "check if {\"a\": 1, \"b\": 2}.all($kv -> $kv.get(0) != \"c\" && $kv.get(1) < 3)", + "check if {\"user\": {\"id\": 1, \"roles\": [\"admin\"]}}.get(\"user\").get(\"roles\").contains(\"admin\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == \"A\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"a\") == 1", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"c\") == null", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(1) == \"A\"", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(2) == null", + "check if {1: \"a\", 2: \"b\"} != true", + "check if {1: \"a\", 2: \"b\"} != {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} !== {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} == {1: \"a\", 2: \"b\"}", + "check if {1: \"a\", 2: \"b\"} === {1: \"a\", 2: \"b\"}", ], }, ] diff --git a/samples/current/samples.json b/samples/current/samples.json index a68baa6..140d3d7 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -862,7 +862,7 @@ ], "public_keys": [], "external_key": null, - "code": "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z;\nvalid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1);\ncheck if valid_date($0), resource($0);\n" + "code": "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z;\nvalid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1);\ncheck if valid_date($0), resource($0);\n" } ], "validations": { @@ -902,7 +902,7 @@ "origin": 1, "rules": [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)" + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)" ] } ], @@ -954,7 +954,7 @@ "origin": 1, "rules": [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)" + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)" ] } ], @@ -1245,7 +1245,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if true;\ncheck if !false;\ncheck if true === true;\ncheck if false === false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 === 3;\ncheck if 1 + 2 * 3 - 4 / 2 === 5;\ncheck if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" === \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" === \"abcD12\";\ncheck if \"abcD12\".length() === 6;\ncheck if \"é\".length() === 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z;\ncheck if hex:12ab === hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] === [1, 2];\ncheck if [1, 2].intersection([2, 3]) === [2];\ncheck if [1, 2].union([2, 3]) === [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() === 2;\n" + "code": "check if true;\ncheck if !false;\ncheck if true === true;\ncheck if false === false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 === 3;\ncheck if 1 + 2 * 3 - 4 / 2 === 5;\ncheck if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" === \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" === \"abcD12\";\ncheck if \"abcD12\".length() === 6;\ncheck if \"é\".length() === 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z;\ncheck if hex:12ab === hex:12ab;\ncheck if {1, 2}.contains(2);\ncheck if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z);\ncheck if {false, true}.contains(true);\ncheck if {\"abc\", \"def\"}.contains(\"abc\");\ncheck if {hex:12ab, hex:34de}.contains(hex:34de);\ncheck if {1, 2}.contains({2});\ncheck if {1, 2} === {1, 2};\ncheck if {1, 2}.intersection({2, 3}) === {2};\ncheck if {1, 2}.union({2, 3}) === {1, 2, 3};\ncheck if {1, 2, 3}.intersection({1, 2}).contains(1);\ncheck if {1, 2, 3}.intersection({1, 2}).length() === 2;\n" } ], "validations": { @@ -1280,21 +1280,21 @@ "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 3 === 3", - "check if [\"abc\", \"def\"].contains(\"abc\")", - "check if [1, 2, 3].intersection([1, 2]).contains(1)", - "check if [1, 2, 3].intersection([1, 2]).length() === 2", - "check if [1, 2] === [1, 2]", - "check if [1, 2].contains(2)", - "check if [1, 2].contains([2])", - "check if [1, 2].intersection([2, 3]) === [2]", - "check if [1, 2].union([2, 3]) === [1, 2, 3]", - "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)", - "check if [false, true].contains(true)", - "check if [hex:12ab, hex:34de].contains(hex:34de)", "check if false === false", "check if hex:12ab === hex:12ab", "check if true", - "check if true === true" + "check if true === true", + "check if {\"abc\", \"def\"}.contains(\"abc\")", + "check if {1, 2, 3}.intersection({1, 2}).contains(1)", + "check if {1, 2, 3}.intersection({1, 2}).length() === 2", + "check if {1, 2} === {1, 2}", + "check if {1, 2}.contains(2)", + "check if {1, 2}.contains({2})", + "check if {1, 2}.intersection({2, 3}) === {2}", + "check if {1, 2}.union({2, 3}) === {1, 2, 3}", + "check if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z)", + "check if {false, true}.contains(true)", + "check if {hex:12ab, hex:34de}.contains(hex:34de)" ] } ], @@ -1814,7 +1814,7 @@ ], "public_keys": [], "external_key": null, - "code": "allowed_operations([\"A\", \"B\"]);\ncheck all operation($op), allowed_operations($allowed), $allowed.contains($op);\n" + "code": "allowed_operations({\"A\", \"B\"});\ncheck all operation($op), allowed_operations($allowed), $allowed.contains($op);\n" } ], "validations": { @@ -1835,7 +1835,7 @@ 0 ], "facts": [ - "allowed_operations([\"A\", \"B\"])" + "allowed_operations({\"A\", \"B\"})" ] } ], @@ -1877,7 +1877,7 @@ 0 ], "facts": [ - "allowed_operations([\"A\", \"B\"])" + "allowed_operations({\"A\", \"B\"})" ] } ], @@ -2148,7 +2148,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if 1 !== 3;\ncheck if 1 | 2 ^ 3 === 0;\ncheck if \"abcD12x\" !== \"abcD12\";\ncheck if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z;\ncheck if hex:12abcd !== hex:12ab;\ncheck if [1, 4] !== [1, 2];\n" + "code": "check if 1 !== 3;\ncheck if 1 | 2 ^ 3 === 0;\ncheck if \"abcD12x\" !== \"abcD12\";\ncheck if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z;\ncheck if hex:12abcd !== hex:12ab;\ncheck if {1, 4} !== {1, 2};\n" } ], "validations": { @@ -2164,8 +2164,8 @@ "check if 1 !== 3", "check if 1 | 2 ^ 3 === 0", "check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z", - "check if [1, 4] !== [1, 2]", - "check if hex:12abcd !== hex:12ab" + "check if hex:12abcd !== hex:12ab", + "check if {1, 4} !== {1, 2}" ] } ], @@ -2513,71 +2513,41 @@ "token": [ { "symbols": [ - "fact", - "value", - "fact2" + "abcD12", + "abcD12x" ], "public_keys": [], "external_key": null, - "code": "check if fact(1, $value), 1 == $value;\ncheck if fact2(1, $value), 1 != $value;\n" + "code": "check if true == true;\ncheck if false != false;\ncheck if 1 != true;\ncheck if 1 == 1;\ncheck if 1 != 3;\ncheck if 1 != true;\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if \"abcD12x\" != true;\ncheck if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != true;\ncheck if hex:12abcd == hex:12abcd;\ncheck if hex:12abcd != hex:12ab;\ncheck if hex:12abcd != true;\ncheck if {1, 2} == {1, 2};\ncheck if {1, 4} != {1, 2};\ncheck if {1, 4} != true;\n" } ], "validations": { - "authorized same type": { - "world": { - "facts": [ - { - "origin": [ - null - ], - "facts": [ - "fact(1, 1)", - "fact2(1, 2)" - ] - } - ], - "rules": [], - "checks": [ - { - "origin": 0, - "checks": [ - "check if fact(1, $value), 1 == $value", - "check if fact2(1, $value), 1 != $value" - ] - } - ], - "policies": [ - "allow if true" - ] - }, - "result": { - "Ok": 0 - }, - "authorizer_code": "fact(1, 1);\nfact2(1, 2);\n\nallow if true;\n", - "revocation_ids": [ - "d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d" - ] - }, - "unauthorized failed logic different type": { + "": { "world": { - "facts": [ - { - "origin": [ - null - ], - "facts": [ - "fact(1, true)", - "fact2(1, false)" - ] - } - ], + "facts": [], "rules": [], "checks": [ { "origin": 0, "checks": [ - "check if fact(1, $value), 1 == $value", - "check if fact2(1, $value), 1 != $value" + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if false != false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}" ] } ], @@ -2596,8 +2566,8 @@ { "Block": { "block_id": 0, - "check_id": 0, - "rule": "check if fact(1, $value), 1 == $value" + "check_id": 1, + "rule": "check if false != false" } } ] @@ -2605,9 +2575,9 @@ } } }, - "authorizer_code": "fact(1, true);\nfact2(1, false);\n\nallow if true;\n", + "authorizer_code": "allow if true;\n", "revocation_ids": [ - "d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d" + "4af245a2504ec00809bd0cd8d20ceaaac35f8ec5aaa8c7d3fd6652b126d2bf246d64fec8f0e65c409b196d4a60c9723dd4fbb3328988790e97fc4e08e9528208" ] } } @@ -2624,7 +2594,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if !(false && \"x\".intersection(\"x\"));\ncheck if true || \"x\".intersection(\"x\");\ncheck if [1, 2, 3].all($p -> $p > 0);\ncheck if ![1, 2, 3].all($p -> $p == 2);\ncheck if [1, 2, 3].any($p -> $p > 2);\ncheck if ![1, 2, 3].any($p -> $p > 3);\ncheck if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q));\n" + "code": "check if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if !(false && \"x\".intersection(\"x\"));\ncheck if true || \"x\".intersection(\"x\");\ncheck if {1, 2, 3}.all($p -> $p > 0);\ncheck if !{1, 2, 3}.all($p -> $p == 2);\ncheck if {1, 2, 3}.any($p -> $p > 2);\ncheck if !{1, 2, 3}.any($p -> $p > 3);\ncheck if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q));\n" } ], "validations": { @@ -2637,15 +2607,15 @@ "origin": 0, "checks": [ "check if !(false && \"x\".intersection(\"x\"))", - "check if ![1, 2, 3].all($p -> $p == 2)", - "check if ![1, 2, 3].any($p -> $p > 3)", "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", "check if (true || false) && true", - "check if [1, 2, 3].all($p -> $p > 0)", - "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", - "check if [1, 2, 3].any($p -> $p > 2)", "check if false || true", - "check if true || \"x\".intersection(\"x\")" + "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)" ] } ], @@ -2670,15 +2640,15 @@ "origin": 0, "checks": [ "check if !(false && \"x\".intersection(\"x\"))", - "check if ![1, 2, 3].all($p -> $p == 2)", - "check if ![1, 2, 3].any($p -> $p > 3)", "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", "check if (true || false) && true", - "check if [1, 2, 3].all($p -> $p > 0)", - "check if [1, 2, 3].any($p -> $p > 1 && [3, 4, 5].any($q -> $p == $q))", - "check if [1, 2, 3].any($p -> $p > 2)", "check if false || true", - "check if true || \"x\".intersection(\"x\")" + "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)" ] } ], @@ -2712,11 +2682,14 @@ "bool", "set", "null", + "array", + "map", + "a", "t" ], "public_keys": [], "external_key": null, - "code": "integer(1);\nstring(\"test\");\ndate(2023-12-28T00:00:00Z);\nbytes(hex:aa);\nbool(true);\nset([false, true]);\nnull(null);\ncheck if 1.type() == \"integer\";\ncheck if integer($t), $t.type() == \"integer\";\ncheck if \"test\".type() == \"string\";\ncheck if string($t), $t.type() == \"string\";\ncheck if (2023-12-28T00:00:00Z).type() == \"date\";\ncheck if date($t), $t.type() == \"date\";\ncheck if hex:aa.type() == \"bytes\";\ncheck if bytes($t), $t.type() == \"bytes\";\ncheck if true.type() == \"bool\";\ncheck if bool($t), $t.type() == \"bool\";\ncheck if [false, true].type() == \"set\";\ncheck if set($t), $t.type() == \"set\";\ncheck if null.type() == \"null\";\ncheck if null($t), $t.type() == \"null\";\n" + "code": "integer(1);\nstring(\"test\");\ndate(2023-12-28T00:00:00Z);\nbytes(hex:aa);\nbool(true);\nset({false, true});\nnull(null);\narray([1, 2, 3]);\nmap({\"a\": true});\ncheck if 1.type() == \"integer\";\ncheck if integer($t), $t.type() == \"integer\";\ncheck if \"test\".type() == \"string\";\ncheck if string($t), $t.type() == \"string\";\ncheck if (2023-12-28T00:00:00Z).type() == \"date\";\ncheck if date($t), $t.type() == \"date\";\ncheck if hex:aa.type() == \"bytes\";\ncheck if bytes($t), $t.type() == \"bytes\";\ncheck if true.type() == \"bool\";\ncheck if bool($t), $t.type() == \"bool\";\ncheck if {false, true}.type() == \"set\";\ncheck if set($t), $t.type() == \"set\";\ncheck if null.type() == \"null\";\ncheck if null($t), $t.type() == \"null\";\ncheck if array($t), $t.type() == \"array\";\ncheck if map($t), $t.type() == \"map\";\n" } ], "validations": { @@ -2728,12 +2701,14 @@ 0 ], "facts": [ + "array([1, 2, 3])", "bool(true)", "bytes(hex:aa)", "date(2023-12-28T00:00:00Z)", "integer(1)", + "map({\"a\": true})", "null(null)", - "set([false, true])", + "set({false, true})", "string(\"test\")" ] } @@ -2746,17 +2721,93 @@ "check if \"test\".type() == \"string\"", "check if (2023-12-28T00:00:00Z).type() == \"date\"", "check if 1.type() == \"integer\"", - "check if [false, true].type() == \"set\"", + "check if array($t), $t.type() == \"array\"", "check if bool($t), $t.type() == \"bool\"", "check if bytes($t), $t.type() == \"bytes\"", "check if date($t), $t.type() == \"date\"", "check if hex:aa.type() == \"bytes\"", "check if integer($t), $t.type() == \"integer\"", + "check if map($t), $t.type() == \"map\"", "check if null($t), $t.type() == \"null\"", "check if null.type() == \"null\"", "check if set($t), $t.type() == \"set\"", "check if string($t), $t.type() == \"string\"", - "check if true.type() == \"bool\"" + "check if true.type() == \"bool\"", + "check if {false, true}.type() == \"set\"" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "c8f7ff152b40a3e8f3ab19a435ccd16c41288762864022895b99d2abb6330c794b3f1378a4651b31d249f4c35b69246d88124d40e05e634a0eb9ca9e54b1ca0a" + ] + } + } + }, + { + "title": "test array and map operations (v5 blocks)", + "filename": "test034_array_map.bc", + "token": [ + { + "symbols": [ + "a", + "b", + "c", + "p", + "d", + "A", + "kv", + "id", + "roles" + ], + "public_keys": [], + "external_key": null, + "code": "check if [1, 2, 1].length() == 3;\ncheck if [\"a\", \"b\"] != true;\ncheck if [\"a\", \"b\"] != [1, 2, 3];\ncheck if [\"a\", \"b\"] == [\"a\", \"b\"];\ncheck if [\"a\", \"b\"] === [\"a\", \"b\"];\ncheck if [\"a\", \"b\"] !== [\"a\", \"c\"];\ncheck if [\"a\", \"b\", \"c\"].contains(\"c\");\ncheck if [1, 2, 3].starts_with([1, 2]);\ncheck if [4, 5, 6].ends_with([6]);\ncheck if [1, 2, \"a\"].get(2) == \"a\";\ncheck if [1, 2].get(3) == null;\ncheck if [1, 2, 3].all($p -> $p > 0);\ncheck if [1, 2, 3].any($p -> $p > 2);\ncheck if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.length() == 4;\ncheck if {1: \"a\", 2: \"b\"} != true;\ncheck if {1: \"a\", 2: \"b\"} != {\"a\": 1, \"b\": 2};\ncheck if {1: \"a\", 2: \"b\"} == {1: \"a\", 2: \"b\"};\ncheck if {1: \"a\", 2: \"b\"} !== {\"a\": 1, \"b\": 2};\ncheck if {1: \"a\", 2: \"b\"} === {1: \"a\", 2: \"b\"};\ncheck if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.contains(\"d\");\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"a\") == 1;\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(1) == \"A\";\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"c\") == null;\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(2) == null;\ncheck if {\"a\": 1, \"b\": 2}.all($kv -> $kv.get(0) != \"c\" && $kv.get(1) < 3);\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == \"A\");\ncheck if {\"user\": {\"id\": 1, \"roles\": [\"admin\"]}}.get(\"user\").get(\"roles\").contains(\"admin\");\n" + } + ], + "validations": { + "": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if [\"a\", \"b\", \"c\"].contains(\"c\")", + "check if [\"a\", \"b\"] != [1, 2, 3]", + "check if [\"a\", \"b\"] != true", + "check if [\"a\", \"b\"] !== [\"a\", \"c\"]", + "check if [\"a\", \"b\"] == [\"a\", \"b\"]", + "check if [\"a\", \"b\"] === [\"a\", \"b\"]", + "check if [1, 2, \"a\"].get(2) == \"a\"", + "check if [1, 2, 1].length() == 3", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if [1, 2, 3].starts_with([1, 2])", + "check if [1, 2].get(3) == null", + "check if [4, 5, 6].ends_with([6])", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.contains(\"d\")", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.length() == 4", + "check if {\"a\": 1, \"b\": 2}.all($kv -> $kv.get(0) != \"c\" && $kv.get(1) < 3)", + "check if {\"user\": {\"id\": 1, \"roles\": [\"admin\"]}}.get(\"user\").get(\"roles\").contains(\"admin\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == \"A\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"a\") == 1", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"c\") == null", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(1) == \"A\"", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(2) == null", + "check if {1: \"a\", 2: \"b\"} != true", + "check if {1: \"a\", 2: \"b\"} != {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} !== {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} == {1: \"a\", 2: \"b\"}", + "check if {1: \"a\", 2: \"b\"} === {1: \"a\", 2: \"b\"}" ] } ], @@ -2769,7 +2820,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "be401996253dce45ac3d8b2f4b289af1f2cc2a4447a8265a1a2ca879c43377978ffc5ac6633053cd7c30e7c33cf258a37767226834bc80b005c48eb0229c4502" + "8041144f92616477f1cd00b81e8be79581202a3853b08b3d477797b0d91f30c02fd7c01ca91a00f8a222d6be4794cc287baa361a1a00d5941518c1917967ec03" ] } } diff --git a/samples/current/test031_heterogeneous_equal.bc b/samples/current/test031_heterogeneous_equal.bc index feb38732a79185bad7ddf3f375abfa33d4795d5e..8ca4ff20e3684c29cf2d6117eba3d745751c1f10 100644 GIT binary patch literal 748 zcmWeS%F1<%g^MjQDcQx)h>IOUS4glKNpVSVF>y#s330J-F&QwzNGT=`Q8YOQupE#C z%88-M2_WmkDhE=5X(mLU05cJ0%5X`6-6_Jw%Ec_vzyYHmrlQI=qR5IFNpnep^$LSE z0cD|H1$#t^O93n?#l^wJrqFnE;~X|57Q}d*YPwhaV}&|ij!On?ju^6TNRWc5*H5_ zmlX#W6EJw01enlx5WBFeWx=9W%n0FoWOG@NLs3YDgF#3^AoO^^#)Scq=IcexkE!i4 zN}d^Gyv#jf)%uO<(ab`RTBIDjKDjOm@H@c4xtHh0C7xHS4#)Q$UA5x)<-ch`8`UoD zSIJHJcjCjd7>C)Cxn2n;i)^p_-fYy_QOP&`j~~a&pe7C_pj&3XsOFm(5iIv^EAxL* YwLER*LyH2cg?r{o%WG|kxUZWC07XD~kpKVy delta 205 zcmaFE`j@d@=o%we4i`&WVsZ%=YguAWX(|^hh+`zdW~9lb&c(zbEyTmoz#+sWz$nDb z(a0es%*Db5 zWe7P=`1-oNqAPBPOy}Z1%>^eHzcN!dJQ|j;Y4e0rNd?cke(mH)+N-_0p=;UJ@SN#U S&x==1TIB3AnRoIDCKUi^s5!3y diff --git a/samples/current/test033_typeof.bc b/samples/current/test033_typeof.bc index 5b0b4c6250b82f0b05dda663d7144c21d2284d82..649e2544ed9f588cce8f9cefd18d6fb7b0f59fd8 100644 GIT binary patch delta 371 zcmeyw*2Tdl^q8IN2irt8Gd|YDqN2n~F6P|C0xrhHiPj0aN}^oC9331&d|o_UOahER z%ml>DN+MiB9Gx6Oyg}StoLtNTT^vG828LYm zWkiv^&ghOTtHI=t%xz?HuSXcn!NnrP#K8=*MWP+Zkz(QyHPYeI;$q^E7UBT87HB)% z8OW+TFjWIRflGBKRJD)_2ZPY$*G$R|C%*p|)pl6?;`3_BC8lRC<~VA!C$%{!bwYaj|kSb977=Ve~-erZEO0a}T1*3NyJQ z%cd~-b0du6m^^_=WU>Ym@8tVTswm|TF>5&NbC8^-YJ1LgjcvESx5liGpU!Bx zxUW!)lG0gGdBnJUdjFrOW61`=XKM_eAGY}vvA8^4DZ^w>!v@wPeH)bKxH3(C#;gJW D$E-a0 diff --git a/samples/current/test034_array_map.bc b/samples/current/test034_array_map.bc new file mode 100644 index 0000000000000000000000000000000000000000..2fb439447caa4f08f750f19699f6349ff85e4de0 GIT binary patch literal 1951 zcmb_dPe>GD6yKTI-M${Wt)I>|&Wf(1ZL)19Uy%}28s^3zDJzmu7t@F+Dh#rc!2b!> z!7#!@hdcy%QK29@gmtJ(9V)FV1>=O8yfcuSmdAs?Xs~=p#pDR5hee9D^1L)CfDEDp{G9W{i=f*_uo5R6A3v zVn-;E^Nu7tRynI7!IYbflri*wkI!nEHh4P8X=QNHPS4>@xK3s2OZQ_gjgLF6Y+Oww z-efE_kzqNcxRz+dLcG$cps7t^GS@N!z01Yx9y9M+E3QcoAqy^FGSDG>AjB=U32q`J5L$>>!{s0*i_PX zue-PZ*L%L~yD%=m3aFYT&&J=;D|eCJ`fBKEZF%kJ(!Fm=@i literal 0 HcmV?d00001 From d815877795f6026631ff30c770b751fd4e0f8fc5 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 4 Nov 2024 14:09:51 +0100 Subject: [PATCH 09/19] fix: reword supported operations on `null` --- SPECIFICATIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 2197233..91db0dc 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -160,7 +160,7 @@ strict not equal, set inclusion, lenient equal, lenient not equal, typeof. A _boolean_ is `true` or `false`. It supports the following operations: `===` (strict equal), `!==` (strict not equal), eager or, eager and, set inclusion, `==` (lenient equal), `!=` (lenient not equal), typeof, short-circuiting or, short-circuiting and. -A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal). `null` is always equal to itself, typeof. +A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal), typeof. `null` is always equal to itself. A _set_ is a deduplicated list of terms of the same type. It cannot contain variables or other sets. It supports strict equal, strict not equal, intersection, union, From 05a49da9e6aead9ae91250c58e0c60b9f04c2fd1 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Fri, 8 Nov 2024 15:30:21 +0100 Subject: [PATCH 10/19] Update schema.proto with maps and arrays Also explictly document the `Get` binary operation --- SPECIFICATIONS.md | 3 +++ schema.proto | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 91db0dc..bce683f 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -510,6 +510,9 @@ Here are the currently defined binary operations: - _all_, defined on sets, takes a closure term -> boolean, returns a boolean (v6 only) - _short circuiting and_, defined on booleans, takes a closure () -> boolean, returns a boolean (v6 only) - _short circuiting or_, defined on booleans, takes a closure () -> boolean, returns a boolean (v6 only) +- _get_, defined on arrays and maps (v6 only) + on arrays, takes an integer and returns the corresponding element (or `null`, if out of bounds) + on maps, takes either an integer or a string and returns the corresponding element (or `null`, if out of bounds) Integer operations must have overflow checks. If it overflows, the expression fails. diff --git a/schema.proto b/schema.proto index e2dfda2..8e716f6 100644 --- a/schema.proto +++ b/schema.proto @@ -99,6 +99,8 @@ message TermV2 { bool bool = 6; TermSet set = 7; Empty null = 8; + Array array = 9; + Map map = 10; } } @@ -106,6 +108,26 @@ message TermSet { repeated TermV2 set = 1; } +message Array { + repeated TermV2 array = 1; +} + +message Map { + repeated MapEntry entries = 1; +} + +message MapEntry { + required MapKey key = 1; + required TermV2 value = 2; +} + +message MapKey { + oneof Content { + int64 integer = 1; + uint64 string = 2; + } +} + message ExpressionV2 { repeated Op ops = 1; } @@ -159,6 +181,7 @@ message OpBinary { LazyOr = 24; All = 25; Any = 26; + Get = 27; } required Kind kind = 1; From 90fbea9b811cbc22bffe3a013b9a4ef8c1d0f5e5 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Fri, 8 Nov 2024 15:44:21 +0100 Subject: [PATCH 11/19] specifcy FFI operations --- SPECIFICATIONS.md | 6 +++++- schema.proto | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index bce683f..821ac76 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -214,7 +214,7 @@ The logic language is described by the following EBNF grammar: ::= | ( ? ) ::= "!" ? ::= "." "(" ? ( ( ? "," ? )* )? ? ")" - ::= ([a-z] | [A-Z] ) ([a-z] | [A-Z] | [0-9] | "_" )* + ::= (extern::)?([a-z] | [A-Z] ) ([a-z] | [A-Z] | [0-9] | "_" )* ::= | ("(" ? ? ")") ::= "<" | ">" | "<=" | ">=" | "===" | "!==" | "&&" | "||" | "+" | "-" | "*" | "/" | "&" | "|" | "^" | "==" | "!==" @@ -479,6 +479,7 @@ Here are the currently defined unary operations: - `bool` - `set` - `null` +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language Here are the currently defined binary operations: @@ -513,6 +514,7 @@ Here are the currently defined binary operations: - _get_, defined on arrays and maps (v6 only) on arrays, takes an integer and returns the corresponding element (or `null`, if out of bounds) on maps, takes either an integer or a string and returns the corresponding element (or `null`, if out of bounds) +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language Integer operations must have overflow checks. If it overflows, the expression fails. @@ -521,6 +523,8 @@ Strict equality fails with a type error when trying to compare different types. Lenient equality returns false when trying to compare different types. +External calls are implementation defined. External calls carry a function name, which can be used to call a user-defined function provided to the biscuit library. + #### Example The expression `$a + 2 < 4` will translate to the following opcodes: $a, 2, +, 4, < diff --git a/schema.proto b/schema.proto index 8e716f6..5524582 100644 --- a/schema.proto +++ b/schema.proto @@ -147,9 +147,11 @@ message OpUnary { Parens = 1; Length = 2; TypeOf = 3; + Ffi = 4; } required Kind kind = 1; + optional string ffiName = 2; } message OpBinary { @@ -182,9 +184,11 @@ message OpBinary { All = 25; Any = 26; Get = 27; + Ffi = 28; } required Kind kind = 1; + optional string ffiName = 2; } message OpClosure { From 7e601cb1a1057d6accf763fcf2c31b326aaaeae8 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Tue, 19 Nov 2024 11:24:59 +0100 Subject: [PATCH 12/19] Signature payload format v1 (#175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces a new way to construct the payload for block signatures and external signatures: - prefixes are used to recognize each type of signature: `BLOCK` or `EXTERNAL` - prefixes are used to separate each part of the payload - external signature payloads contain the signature of the previous block instead of the current block's public key - block signatures now contain the signature of the previous block too - the previous payload format for block signatures. is deprecated Still supported, but will be removed in a future major version - the previous payload format for external signatures is not supported anymore Co-authored-by: Clément Delafargue --- SPECIFICATIONS.md | 103 ++++++++++++--- samples/current/README.md | 117 +++++++----------- samples/current/samples.json | 8 +- samples/current/test024_third_party.bc | Bin 458 -> 460 bytes .../current/test026_public_keys_interning.bc | Bin 1547 -> 1553 bytes samples/current/test30_null.bc | Bin 248 -> 0 bytes schema.proto | 3 + 7 files changed, 141 insertions(+), 90 deletions(-) delete mode 100644 samples/current/test30_null.bc diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 821ac76..8f18953 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -699,6 +699,7 @@ message SignedBlock { required PublicKey nextKey = 2; required bytes signature = 3; optional ExternalSignature externalSignature = 4; + optional uint32 version = 5; } message ExternalSignature { @@ -729,7 +730,8 @@ for signature verification. Each block contains a serialized byte array of the Datalog data (`block`), the next public key (`nextKey`) and the signature of that block and key -by the previous key. +by the previous key. The `version` field indicates the version of the signature +payload format. The `proof` field contains either the private key corresponding to the public key in the last block (attenuable tokens) or a signature of the last @@ -787,13 +789,88 @@ corresponding to the last public key, to sign a new block and attenuate the token, or a signature of the last block by the last private key, to seal the token. +#### Signed payload generation + +The data covered by the signature algorithm depends on the `version` field of +the `SignedBlock` message. If the field is absent, it defaults to version 0. + +##### Version 0 (deprecated) + +This defines the block signature payload v0. + +The authority block signature payload v0 is the concatenation of: +- `data_0`: the serialized Datalog +- `pk_1`: the next public key +- `alg_1`: the little endian representation of the signature algorithm for `pk_1` + +To sign the block at index `n+1`, the signed payload format is the concatenation of: +- `data_n+1`: the serialized Datalog +- `pk_n+2`: the next public key +- `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` + +if `external_sig_n+1` is present, the signed payload format is instead the concatenation of: +- `data_n+1`: the serialized Datalog +- `external_sig_n+1`: the optional external signature of the block +- `pk_n+2`: the next public key +- `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` + +This format is deprecated and will be replaced by version 1 in the future. + +the signed payload format for external signatures, thereafter referred as "external signature payload v0", is the concatenation of: +- `data_n+1`: the serialized Datalog +- `pk_n+1`: the public key for the next block +- `alg_n+1`: the little endian representation of the signature algorithm for `pk_n+1` + +This format is not supported anymore and should be replaced by version 1. + +##### Version 1 + +This defines the block signature payload v1. + +The authority block signature payload v1 is the concatenation of: +- the binary representation of the ASCII string "\0BLOCK\0" +- the binary representation of the ASCII string "\0VERSION\0" +- the little endian representation of the version of the signature payload format +- the binary representation of the ASCII string "\0PAYLOAD\0" +- `data_0`: the serialized Datalog +- the binary representation of the ASCII string "\0ALGORITHM\0" +- `alg_1`: the little endian representation of the signature algorithm for `pk_1` +- the binary representation of the ASCII string "\0NEXTKEY\0" +- `pk_1`: the next public key + +To sign the block at index `n+1`, the signed payload format is the concatenation of: +- the binary representation of the ASCII string "\0BLOCK\0" +- the binary representation of the ASCII string "\0VERSION\0" +- the little endian representation of the version of the signature payload format +- the binary representation of the ASCII string "\0PAYLOAD\0" +- `data_n+1`: the serialized Datalog +- the binary representation of the ASCII string "\0ALGORITHM\0" +- `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` +- the binary representation of the ASCII string "\0NEXTKEY\0" +- `pk_n+2`: the next public key +- the binary representation of the ASCII string "\0PREVSIG\0" +- `sig_n`: the signature of the previous block +- if `external_sig_n+1` is present: + - the binary representation of the ASCII string "\0EXTERNALSIG\0" + - `external_sig_n+1`: the optional external signature of the block + +the signed payload format for external signatures, thereafter referred as "external signature payload v1", is the concatenation of: +- the binary representation of the ASCII string "\0EXTERNAL\0" +- the binary representation of the ASCII string "\0VERSION\0" +- the little endian representation of the version of the signature payload format +- the binary representation of the ASCII string "\0PAYLOAD\0" +- `data_n+1`: the serialized Datalog +- the binary representation of the ASCII string "\0PREVSIG\0" +- `sig_n`: the signature of the previous block + #### Signature (one block) - `(pk_0, sk_0)` the root public and private Ed25519 keys - `data_0` the serialized Datalog - `(pk_1, sk_1)` the next key pair, generated at random - `alg_1` the little endian representation of the signature algorithm fr `pk1, sk1` (see protobuf schema) -- `sig_0 = sign(sk_0, data_0 + alg_1 + pk_1)` +- the signed block version indicates the version of the signature payload format, either "block signature payload v0" or "block signature payload v1" +- `sig_0` is the signature of the payload by `sk_0` The token will contain: @@ -826,7 +903,9 @@ The token also contains `sk_n+1`. The new block can optionally be signed by an external keypair `(epk, esk)` and carry an external signature `esig`. -We generate at random `(pk_n+2, sk_n+2)` and the signature `sig_n+1 = sign(sk_n+1, data_n+1 + esig? + alg_n+2 + pk_n+2)`. If the block is not signed by an external keypair, then `esig` is not part of the signed payload. +the signed block version indicates the version of the signature payload format, either "block signature payload v0" or "block signature payload v1". + +We generate at random `(pk_n+2, sk_n+2)` and the signature `sig_n+1` is the signature of the payload by `sk_n+1`. The token will contain: @@ -852,12 +931,8 @@ Token { Blocks generated by a trusted third party can carry an *extra* signature to provide a proof of their origin. Same as regular signatures, they rely on Ed25519. -The external signature for block `n+1`, with `(external_pk, external_sk)` is `external_sig_n+1 = sign(external_sk, data_n+1 + alg_n+1 + pk_n+1)`. -It's quite similar to the regular signature, with a crucial difference: the public key appended to the block payload is the one _carried_ by block `n` (and which is used to verify block `n+1`). -This means that the authority block can't carry an external signature (that would be useless, since -the root key is not ephemeral and can be trusted directly). - -This is necessary to make sure an external signature can't be used for any other token. +The external signature for block `n+1`, with `(external_pk, external_sk)` is `external_sig_n+1`, the signature of the payload in format "external signature payload v1" by `external_sk`. +The authority block can't carry an external signature. This is necessary to make sure an external signature can't be used for any other token. The presence of an external signature affects the regular signature: the external signature is part of the payload signed by the regular signature. @@ -881,12 +956,11 @@ Token { } ``` - #### Verifying For each block i from 0 to n: - -- verify(pk_i, sig_i, data_i + alg_i+1 + pk_i+1) +- `payload_i`: the signature payload for block i +- `verify(pk_i, sig_i, payload_i)` If all signatures are verified, extract pk_n+1 from the last block and sk_n+1 from the proof field, and check that they are from the same @@ -895,8 +969,8 @@ key pair. ##### Verifying external signatures For each block i from 1 to n, _where an external signature is present_: - -- verify(external_pk_i, external_sig_i, data_i + alg_i + pk_i) +- `external_payload_i`: the external signature payload for block i +- `verify(external_pk_i, external_sig_i, external_payload_i)` #### Signature (sealing) @@ -1062,6 +1136,7 @@ To support this use-case, the protobuf schema defines two message types: `ThirdP message ThirdPartyBlockRequest { required PublicKey previousKey = 1; repeated PublicKey publicKeys = 2; + required bytes previousSignature = 3; } message ThirdPartyBlockContents { diff --git a/samples/current/README.md b/samples/current/README.md index 06b48e3..22d7c9c 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -1835,7 +1835,7 @@ allow if true; revocation ids: - `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03` -- `342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03` +- `901b2af4dacf33458d2d91ac484b60bad948e8d10faa9695b096054d5b46e832a977b60b17464cacf545ad0801f549ea454675f0ac88c413406925e2af83ff08` authorizer world: ``` @@ -2097,9 +2097,9 @@ allow if true; revocation ids: - `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04` -- `6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d` -- `5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04` -- `c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09` +- `7113d4dbb3b688b80e941f365a2c6342d480c77ed03937bccf85dc5cc3554c7517887b1b0c9021388a71e6ca9047aabaaad5ae5b511a2880902568444a98e50b` +- `d0e3fc4bbd1b7320022800af909585aa906f677c4ca79c275a10b6779f669384c464ee84a1b04f13877a25761a874748362c065f4d15a8cab5c5e16c34074403` +- `29b7e0a1f118a6185814a552660c516c43482044e280e7a8de85b8e7e54947e0ae82eb39d7b524d4b72cb9812a7a4b8871964f8f825b1c1ed85d344c05281d0d` - `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900` authorizer world: @@ -2657,88 +2657,45 @@ result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedB ### token authority: -symbols: ["fact", "value", "fact2"] +symbols: ["abcD12", "abcD12x"] public keys: [] ``` -check if fact(1, $value), 1 == $value; -check if fact2(1, $value), 1 != $value; +check if true == true; +check if false != false; +check if 1 != true; +check if 1 == 1; +check if 1 != 3; +check if 1 != true; +check if "abcD12" == "abcD12"; +check if "abcD12x" != "abcD12"; +check if "abcD12x" != true; +check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z; +check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z; +check if 2022-12-04T09:46:41Z != true; +check if hex:12abcd == hex:12abcd; +check if hex:12abcd != hex:12ab; +check if hex:12abcd != true; +check if {1, 2} == {1, 2}; +check if {1, 4} != {1, 2}; +check if {1, 4} != true; ``` -### validation for "authorized same type" - -authorizer code: -``` -fact(1, 1); -fact2(1, 2); - -allow if true; -``` - -revocation ids: -- `d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d` - -authorizer world: -``` -World { - facts: [ - Facts { - origin: { - None, - }, - facts: [ - "fact(1, 1)", - "fact2(1, 2)", - ], - }, -] - rules: [] - checks: [ - Checks { - origin: Some( - 0, - ), - checks: [ - "check if fact(1, $value), 1 == $value", - "check if fact2(1, $value), 1 != $value", - ], - }, -] - policies: [ - "allow if true", -] -} -``` - -result: `Ok(0)` -### validation for "unauthorized failed logic different type" +### validation authorizer code: ``` -fact(1, true); -fact2(1, false); - allow if true; ``` revocation ids: -- `d65b3aeceb6268124190f5eb87788a5eb81c89a3fc8370c9a3ea362731c55660b2b390ca6270e68afab90862bd2bbb808aa6b5576c975ae773a992a2434c930d` +- `4af245a2504ec00809bd0cd8d20ceaaac35f8ec5aaa8c7d3fd6652b126d2bf246d64fec8f0e65c409b196d4a60c9723dd4fbb3328988790e97fc4e08e9528208` authorizer world: ``` World { - facts: [ - Facts { - origin: { - None, - }, - facts: [ - "fact(1, true)", - "fact2(1, false)", - ], - }, -] + facts: [] rules: [] checks: [ Checks { @@ -2746,8 +2703,24 @@ World { 0, ), checks: [ - "check if fact(1, $value), 1 == $value", - "check if fact2(1, $value), 1 != $value", + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if false != false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}", ], }, ] @@ -2757,7 +2730,7 @@ World { } ``` -result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(1, $value), 1 == $value" })] }))` +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "check if false != false" })] }))` ------------------------------ diff --git a/samples/current/samples.json b/samples/current/samples.json index 140d3d7..322fddb 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -1795,7 +1795,7 @@ "authorizer_code": "allow if true;\n", "revocation_ids": [ "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03", - "342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03" + "901b2af4dacf33458d2d91ac484b60bad948e8d10faa9695b096054d5b46e832a977b60b17464cacf545ad0801f549ea454675f0ac88c413406925e2af83ff08" ] } } @@ -2087,9 +2087,9 @@ "authorizer_code": "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\nallow if true;\n", "revocation_ids": [ "3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04", - "6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d", - "5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04", - "c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09", + "7113d4dbb3b688b80e941f365a2c6342d480c77ed03937bccf85dc5cc3554c7517887b1b0c9021388a71e6ca9047aabaaad5ae5b511a2880902568444a98e50b", + "d0e3fc4bbd1b7320022800af909585aa906f677c4ca79c275a10b6779f669384c464ee84a1b04f13877a25761a874748362c065f4d15a8cab5c5e16c34074403", + "29b7e0a1f118a6185814a552660c516c43482044e280e7a8de85b8e7e54947e0ae82eb39d7b524d4b72cb9812a7a4b8871964f8f825b1c1ed85d344c05281d0d", "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900" ] } diff --git a/samples/current/test024_third_party.bc b/samples/current/test024_third_party.bc index d2aef52815e08c1d47cfaaec9ad0b8eaa1bc13e4..8b7b8645727732c9e2e510c7d3431e5c6233c506 100644 GIT binary patch delta 156 zcmV;N0Av5k1Iz=Ev;p#wwMT!D8!GhL&of1hEs?B9OJKU$Na)cIs+N_omIX~)M(8rB zceV=`Mog^rMXd+{^-1bQMs@J4h{O{>X(i&XgZ~I3XbM26-^aYLK@|_P$@gs!a(4cn zLA43wyl!%|7R3)jY4Ji-;5JwWyfcR`kygnnnBAt}(bm3CI!~q427(2(8vBC=lYjvx K0w@8KrU4`fM@Xyy delta 153 zcmV;K0A~Np1Ih!Cv;pvuwMTz6A!oc)yksk97@~HEURAc!o|_@$&J(#NqtlqSz*qc3 zV}-v=fqEAC?B5Fwl@5!7SfUE+KiG+EUYs8aQ`!R}XbM2xziGHPFJ%uTceGU^8b6lYjvx Hlc)hC)!|D? diff --git a/samples/current/test026_public_keys_interning.bc b/samples/current/test026_public_keys_interning.bc index 392d649c5f4827b695ef2f481eb9ab1b69de307d..47b139b3cb1177f3e2a0907f3c703b569b032da1 100644 GIT binary patch delta 454 zcmV;%0XhDQ43P|wxB`I#k-F7?aTCigD)3kVmSzs@1MrQ5q@ECydq6{yO!#o=r;2SfuRXbM0bxhQz#rXk{m$RwcTxeFJOA!cc59RfMp&D@*G6N=I@ek9>)f^w_i>N5|bPOB?Kq|8sC$f z1GIlBx8R}i7^WCl6s1yT3{h-DNFYSwfaj>*g}CSCNk`zWg6lcgwItNHEV+RydP|6L zmQRm@TO1zPT{KJuC>;$VXbM0m2ElJB-MddU5y337A5axGi;YU1k`ywD!op)Q0+x0| wNlQXr&#q*QC_AtZ`86&2pY4iL9&ia4iH!z+m<#U=5|bPOB?2e`v-t!P0XC1rjQ{`u delta 447 zcmV;w0YLtd42ukqxB~wIk-F7?WhmP$npPUxkcK9ONu~g(r7!d}>VboSCL`{^>9)nw z#2UAThzMdZA=x67)q}6!lJqr8&8i#41XJO-n*C!9B4`RglLC0oR9=W#e(f6(u#}li zw{_SCMOLMFWm_I8D&olFwfn|P?7-HRi|472Q#g9|+5M+EaL_V+I$n(i6eUje3=)wl zB?21VlRW~oe_d92{%ODGOL-YGH5KXXx}5<+D;BKN8lxdmBfs1R`h(K*d1!6n@P7XaA>l>{(nXbqev46`>>slHi6z z6FEAQzv~_6)(S;K8vy`6of*E8B4>AlgSwfW@vxEz1~lHbf(sIp-~%NB8r_qh1GIm` zd-6;MKLZf#%D9G3NZarH-Eu&*_|f1Vx=+Ug=E(>vgj=;$L$MD4jmPxog+M_W609FK z`YNda5!|E?GCK((XbM2&CFI_GWn8HPg+b*~|B-V2gxO4gQV75szkVe`yT2+rt-ay| pSMm(ON1*|k&^FY=SfDF+IdZeNMPCL%Tyj1J5|iKqCA0qo5&>p&&=CLt diff --git a/samples/current/test30_null.bc b/samples/current/test30_null.bc deleted file mode 100644 index 2337a1114ef4e0530bb0283a7e36ff07aa920989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 248 zcmWf-$jFt>#gdkoT*Ad#mY7qTD#2=`$)(Q4#33!j!_mMY#N@;v#LUsiAtlVk$^~L@ zv2X#!xLBl^I9QCdiB&2hz$B!?!62j{5PCddPP$2UNR<`+DIN%IdD0A-g5zynHfbpoUMiR^0))% znoDzSVrjhE<0dI#*E#)giF@0N2h2)JTnaN^RP#-Y2$p-dmHEG@TAsG@p+y1J!aZ}P M<+Zj%+}BM60M+S53jhEB diff --git a/schema.proto b/schema.proto index 5524582..c8cfceb 100644 --- a/schema.proto +++ b/schema.proto @@ -14,6 +14,7 @@ message SignedBlock { required PublicKey nextKey = 2; required bytes signature = 3; optional ExternalSignature externalSignature = 4; + optional uint32 version = 5; } message ExternalSignature { @@ -218,6 +219,8 @@ message AuthorizerPolicies { message ThirdPartyBlockRequest { required PublicKey previousKey = 1; repeated PublicKey publicKeys = 2; + required bytes previousSignature = 3; + } message ThirdPartyBlockContents { From 37cc137ba1f9c896bb2aa7a2b7e503df02638d7b Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Tue, 19 Nov 2024 17:42:01 +0100 Subject: [PATCH 13/19] update samples (lenient equals sample) --- samples/current/README.md | 108 ++++++++++++++++-- samples/current/samples.json | 107 +++++++++++++++-- .../current/test031_heterogeneous_equal.bc | Bin 748 -> 882 bytes 3 files changed, 199 insertions(+), 16 deletions(-) diff --git a/samples/current/README.md b/samples/current/README.md index 22d7c9c..11681f0 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -2657,13 +2657,14 @@ result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedB ### token authority: -symbols: ["abcD12", "abcD12x"] +symbols: ["abcD12", "abcD12x", "fact", "value", "fact2"] public keys: [] ``` check if true == true; -check if false != false; +check if false == false; +check if false != true; check if 1 != true; check if 1 == 1; check if 1 != 3; @@ -2680,22 +2681,37 @@ check if hex:12abcd != true; check if {1, 2} == {1, 2}; check if {1, 4} != {1, 2}; check if {1, 4} != true; +check if fact(1, $value), 1 == $value; +check if fact2(1, $value), 1 != $value; ``` ### validation authorizer code: ``` +fact(1, 1); +fact2(1, 2); + allow if true; ``` revocation ids: -- `4af245a2504ec00809bd0cd8d20ceaaac35f8ec5aaa8c7d3fd6652b126d2bf246d64fec8f0e65c409b196d4a60c9723dd4fbb3328988790e97fc4e08e9528208` +- `899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f` authorizer world: ``` World { - facts: [] + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(1, 1)", + "fact2(1, 2)", + ], + }, +] rules: [] checks: [ Checks { @@ -2713,7 +2729,77 @@ World { "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", "check if 2022-12-04T09:46:41Z != true", "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", - "check if false != false", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "evaluate to false" + +authorizer code: +``` +fact(1, 2); +fact2(1, 1); + +check if false != false; + +allow if true; +``` + +revocation ids: +- `899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(1, 2)", + "fact2(1, 1)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", "check if hex:12abcd != hex:12ab", "check if hex:12abcd != true", "check if hex:12abcd == hex:12abcd", @@ -2723,6 +2809,14 @@ World { "check if {1, 4} != {1, 2}", ], }, + Checks { + origin: Some( + 18446744073709551615, + ), + checks: [ + "check if false != false", + ], + }, ] policies: [ "allow if true", @@ -2730,7 +2824,7 @@ World { } ``` -result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "check if false != false" })] }))` +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Authorizer(FailedAuthorizerCheck { check_id: 0, rule: "check if false != false" }), Block(FailedBlockCheck { block_id: 0, check_id: 19, rule: "check if fact(1, $value), 1 == $value" }), Block(FailedBlockCheck { block_id: 0, check_id: 20, rule: "check if fact2(1, $value), 1 != $value" })] }))` ------------------------------ @@ -2948,7 +3042,7 @@ result: `Ok(0)` ------------------------------ -## test array and map operations (v5 blocks): test034_array_map.bc +## test array and map operations: test034_array_map.bc ### token authority: diff --git a/samples/current/samples.json b/samples/current/samples.json index 322fddb..80519a1 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -2514,17 +2514,84 @@ { "symbols": [ "abcD12", - "abcD12x" + "abcD12x", + "fact", + "value", + "fact2" ], "public_keys": [], "external_key": null, - "code": "check if true == true;\ncheck if false != false;\ncheck if 1 != true;\ncheck if 1 == 1;\ncheck if 1 != 3;\ncheck if 1 != true;\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if \"abcD12x\" != true;\ncheck if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != true;\ncheck if hex:12abcd == hex:12abcd;\ncheck if hex:12abcd != hex:12ab;\ncheck if hex:12abcd != true;\ncheck if {1, 2} == {1, 2};\ncheck if {1, 4} != {1, 2};\ncheck if {1, 4} != true;\n" + "code": "check if true == true;\ncheck if false == false;\ncheck if false != true;\ncheck if 1 != true;\ncheck if 1 == 1;\ncheck if 1 != 3;\ncheck if 1 != true;\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if \"abcD12x\" != true;\ncheck if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != true;\ncheck if hex:12abcd == hex:12abcd;\ncheck if hex:12abcd != hex:12ab;\ncheck if hex:12abcd != true;\ncheck if {1, 2} == {1, 2};\ncheck if {1, 4} != {1, 2};\ncheck if {1, 4} != true;\ncheck if fact(1, $value), 1 == $value;\ncheck if fact2(1, $value), 1 != $value;\n" } ], "validations": { "": { "world": { - "facts": [], + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(1, 1)", + "fact2(1, 2)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "fact(1, 1);\nfact2(1, 2);\n\nallow if true;\n", + "revocation_ids": [ + "899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f" + ] + }, + "evaluate to false": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(1, 2)", + "fact2(1, 1)" + ] + } + ], "rules": [], "checks": [ { @@ -2540,7 +2607,10 @@ "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", "check if 2022-12-04T09:46:41Z != true", "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", - "check if false != false", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", "check if hex:12abcd != hex:12ab", "check if hex:12abcd != true", "check if hex:12abcd == hex:12abcd", @@ -2549,6 +2619,12 @@ "check if {1, 4} != true", "check if {1, 4} != {1, 2}" ] + }, + { + "origin": 18446744073709551615, + "checks": [ + "check if false != false" + ] } ], "policies": [ @@ -2563,11 +2639,24 @@ "Allow": 0 }, "checks": [ + { + "Authorizer": { + "check_id": 0, + "rule": "check if false != false" + } + }, { "Block": { "block_id": 0, - "check_id": 1, - "rule": "check if false != false" + "check_id": 19, + "rule": "check if fact(1, $value), 1 == $value" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 20, + "rule": "check if fact2(1, $value), 1 != $value" } } ] @@ -2575,9 +2664,9 @@ } } }, - "authorizer_code": "allow if true;\n", + "authorizer_code": "fact(1, 2);\nfact2(1, 1);\n\ncheck if false != false;\n\nallow if true;\n", "revocation_ids": [ - "4af245a2504ec00809bd0cd8d20ceaaac35f8ec5aaa8c7d3fd6652b126d2bf246d64fec8f0e65c409b196d4a60c9723dd4fbb3328988790e97fc4e08e9528208" + "899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f" ] } } @@ -2752,7 +2841,7 @@ } }, { - "title": "test array and map operations (v5 blocks)", + "title": "test array and map operations", "filename": "test034_array_map.bc", "token": [ { diff --git a/samples/current/test031_heterogeneous_equal.bc b/samples/current/test031_heterogeneous_equal.bc index 8ca4ff20e3684c29cf2d6117eba3d745751c1f10..442623bc7e21f1511b161a37645e56d8148bae1c 100644 GIT binary patch delta 215 zcmaFE`iV_j=rkMG16D4!#H3^wLnAJB2wlO&l9rfU!o^yam{Xd{#R}pWO%%7BXd*T- zO?qSMZ^i&4O)hmVCJt#K9*!msAtnJvA!d$d4k=+S7A_!%iry8|k+uW%{uS2}5?%_KFM;StY%>2Cdkz4B4B8ILHuf3+iE(uc;|h3Bek dUjJd-vgF4nO&|B3C&zy@+W(5-pL~Kz1pqO|JYxU= delta 111 zcmeyw_J&nl=qM}KEfy}e#H3^wLnAJB2wgEz+j8O+xsCHaF;0HQq~YN8$#qeH-vJKJ zy*xKA@w{4fIKJ=bsujmC|4j?psCH?;N^Z)(6Ca+%ILwyJ^-4HdWP9cJW~0uIO1|lT P{5W0)HE~S#V^#qG?3OVq From 1c7ca0c22e7e48ab56750e1ea00bb6d7186adfe3 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Tue, 19 Nov 2024 11:45:12 +0100 Subject: [PATCH 14/19] ffi: intern function names --- schema.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schema.proto b/schema.proto index c8cfceb..0a45085 100644 --- a/schema.proto +++ b/schema.proto @@ -152,7 +152,7 @@ message OpUnary { } required Kind kind = 1; - optional string ffiName = 2; + optional uint64 ffiName = 2; } message OpBinary { @@ -189,7 +189,7 @@ message OpBinary { } required Kind kind = 1; - optional string ffiName = 2; + optional uint64 ffiName = 2; } message OpClosure { From ddb95cadc80ffd256ca4d5ada039917376d7c606 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Tue, 19 Nov 2024 11:47:37 +0100 Subject: [PATCH 15/19] ffi: add samples --- samples/current/README.md | 48 +++++++++++++++++++++++++++++++++ samples/current/samples.json | 42 +++++++++++++++++++++++++++++ samples/current/test035_ffi.bc | Bin 0 -> 234 bytes 3 files changed, 90 insertions(+) create mode 100644 samples/current/test035_ffi.bc diff --git a/samples/current/README.md b/samples/current/README.md index 11681f0..ec6e18f 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -3139,3 +3139,51 @@ World { result: `Ok(0)` + +------------------------------ + +## test ffi calls (v6 blocks): test035_ffi.bc +### token + +authority: +symbols: ["test", "a", "equal strings"] + +public keys: [] + +``` +check if true.extern::test(), "a".extern::test("a") == "equal strings"; +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `faf26fe6f5dfa08c114a0a29321405b6fb7be79b0d80694d27925f7deb01effe5707600e42fd74f9a1d2920466446d51949155f4548f0fd68f3e9326c7e12404` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if true.extern::test(), \"a\".extern::test(\"a\") == \"equal strings\"", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + diff --git a/samples/current/samples.json b/samples/current/samples.json index 80519a1..1401846 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -2913,6 +2913,48 @@ ] } } + }, + { + "title": "test ffi calls (v6 blocks)", + "filename": "test035_ffi.bc", + "token": [ + { + "symbols": [ + "test", + "a", + "equal strings" + ], + "public_keys": [], + "external_key": null, + "code": "check if true.extern::test(), \"a\".extern::test(\"a\") == \"equal strings\";\n" + } + ], + "validations": { + "": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if true.extern::test(), \"a\".extern::test(\"a\") == \"equal strings\"" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "faf26fe6f5dfa08c114a0a29321405b6fb7be79b0d80694d27925f7deb01effe5707600e42fd74f9a1d2920466446d51949155f4548f0fd68f3e9326c7e12404" + ] + } + } } ] } diff --git a/samples/current/test035_ffi.bc b/samples/current/test035_ffi.bc new file mode 100644 index 0000000000000000000000000000000000000000..d5bb3a8dce7887643122c4fe7c01dc441a4de614 GIT binary patch literal 234 zcmWeS%*YkV#Zr=5T*Aee$iX zA5+_9lsq%Wc$s^|s`VSyqnU*swMaSq`jr3d>-_~if?iyjMk1`+epf%A&D)Uat3D~d z_BG@Cf8p#2d`^E$elEN;i6zY?H*m_t&@UnV{MY*JCaWEPsKTP8#HBFvMK#~Vh+w&Q cTbcihs^w`bA6gVpE!;C#T3%~Q#C_dF0BaLTeE Date: Tue, 19 Nov 2024 14:01:20 +0100 Subject: [PATCH 16/19] ffi: mention that call names are interned --- SPECIFICATIONS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 8f18953..1fb2e53 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -479,7 +479,7 @@ Here are the currently defined unary operations: - `bool` - `set` - `null` -- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v6 only) Here are the currently defined binary operations: @@ -514,7 +514,7 @@ Here are the currently defined binary operations: - _get_, defined on arrays and maps (v6 only) on arrays, takes an integer and returns the corresponding element (or `null`, if out of bounds) on maps, takes either an integer or a string and returns the corresponding element (or `null`, if out of bounds) -- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v6 only) Integer operations must have overflow checks. If it overflows, the expression fails. @@ -523,7 +523,7 @@ Strict equality fails with a type error when trying to compare different types. Lenient equality returns false when trying to compare different types. -External calls are implementation defined. External calls carry a function name, which can be used to call a user-defined function provided to the biscuit library. +External calls are implementation defined. External calls carry a function name, which can be used to call a user-defined function provided to the biscuit library. The function name is an interned string, stored in the symbol table. #### Example From ed1c53d6db5811dfb9d9e395e95135f7f5660dbe Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 20 Nov 2024 09:52:58 +0100 Subject: [PATCH 17/19] Support for ECDSA signatures on curve secp256r1 (#165) This adds support for ECDSA signatures based on secp256r1. This will make it easier for biscuit tokens to work in environments with FIPS requirements, or with HSMs --- SPECIFICATIONS.md | 51 ++++++++++++++-- samples/current/README.md | 87 ++++++++++++++++++++++++++- samples/current/samples.json | 72 +++++++++++++++++++++- samples/current/test036_secp256r1.bc | Bin 0 -> 366 bytes schema.proto | 1 + 5 files changed, 205 insertions(+), 6 deletions(-) create mode 100644 samples/current/test036_secp256r1.bc diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 1fb2e53..35249c7 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -177,7 +177,7 @@ The logic language is described by the following EBNF grammar: ``` ::= ? "trusting " ? ("," ? ?)* ::= "authority" | "previous" | "/" - ::= "ed25519" + ::= "ed25519" | "secp256r1" ::= ( ";" ?)? ( | )* ::= ? ( | | ) ? ";" ? @@ -712,6 +712,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; @@ -782,13 +783,55 @@ is a Biscuit token, that base 64 string should be prefixed with `biscuit:`. ### Cryptography -Biscuit tokens are based on public key cryptography, with a chain of Ed25519 +Biscuit tokens are based on public key cryptography, with a chain of signatures. Each block contains the serialized Datalog, the next public key, and the signature by the previous key. The token also contains the private key corresponding to the last public key, to sign a new block and attenuate the token, or a signature of the last block by the last private key, to seal the token. +#### Algorithms + +Biscuit supports multiple signature algorithms for its blocks, that can change +between blocks in one token. The algorithm kind is defined in the `Algorithm` +enum of the protobuf serialization of the public key. The `nextSecret` field +in the proof section of the token uses the same algorithm as the `nextKey` +of the last block. + +The following algorithms are supported: + +##### Ed25519 + +The default signature algorithm is Ed25519 as introduced in [Bernstein, Daniel J.; +Duif, Niels; Lange, Tanja; Schwabe, Peter; Bo-Yin Yang (2012). "High-speed +high-security signatures" (PDF). Journal of Cryptographic Engineering](https://ed25519.cr.yp.to/ed25519-20110926.pdf) +and specified in [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032). + +The protobuf encoding is defined as follows: +- `key` field of the `Publickey` message: [compressed Edwards Y format](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.2) +- `nextSecret` in the `Proof` message: [32 bytes of cryptographically secure random data in little-endian](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5) +- `signature` field in `Signature` and `ExternalSignature` messages: [concatenation of R and S values](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6) + +##### ECDSA + +Biscuit supports the ECDSA algorithm over the secp256r1 curve as defined in +[SEC2v1](https://www.secg.org/sec1-v2.pdf), using the SHA-256 hashing +algorithm. It is recommended to use a deterministic signature algorithm +version like the one defined in [RFC 6979](https://datatracker.ietf.org/doc/html/rfc6979). + + +The protobuf encoding is defined as follows: +- `key` field of the `Publickey` message: [compressed SEC1 format, defined in section 2.3.3](https://www.secg.org/sec1-v2.pdf). Allowed prefixes: `02`, `03` +- `nextSecret` in the `Proof` message: big endian representation of the secret scalar +- `signature` field in `Signature` and `ExternalSignature` messages: [SEC1 ASN.1 format, defined in section C5](https://www.secg.org/sec1-v2.pdf), only using the `r` and `s` parameters + +``` +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} +``` + #### Signed payload generation The data covered by the signature algorithm depends on the `version` field of @@ -865,7 +908,7 @@ the signed payload format for external signatures, thereafter referred as "exter #### Signature (one block) -- `(pk_0, sk_0)` the root public and private Ed25519 keys +- `(pk_0, sk_0)` the root public and private keys - `data_0` the serialized Datalog - `(pk_1, sk_1)` the next key pair, generated at random - `alg_1` the little endian representation of the signature algorithm fr `pk1, sk1` (see protobuf schema) @@ -929,7 +972,7 @@ Token { ##### Optional external signature Blocks generated by a trusted third party can carry an *extra* signature to provide a proof of their -origin. Same as regular signatures, they rely on Ed25519. +origin. Same as regular signatures, they rely on public key cryptography. The external signature for block `n+1`, with `(external_pk, external_sk)` is `external_sig_n+1`, the signature of the payload in format "external signature payload v1" by `external_sk`. The authority block can't carry an external signature. This is necessary to make sure an external signature can't be used for any other token. diff --git a/samples/current/README.md b/samples/current/README.md index ec6e18f..78838b6 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -141,7 +141,7 @@ check if resource($0), operation("read"), right($0, "read"); ### validation -result: `Err(Format(InvalidSignatureSize(16)))` +result: `Err(Format(BlockSignatureDeserializationError("block signature deserialization error: [117, 149, 161, 18, 161, 235, 91, 129, 166, 227, 152, 133, 46, 97, 24, 183]")))` ------------------------------ @@ -3187,3 +3187,88 @@ World { result: `Ok(0)` + +------------------------------ + +## ECDSA secp256r1 signatures: test036_secp256r1.bc +### token + +authority: +symbols: ["file1", "file2"] + +public keys: [] + +``` +right("file1", "read"); +right("file2", "read"); +right("file1", "write"); +``` + +1: +symbols: ["0"] + +public keys: [] + +``` +check if resource($0), operation("read"), right($0, "read"); +``` + +### validation + +authorizer code: +``` +resource("file1"); +operation("read"); + +allow if true; +``` + +revocation ids: +- `760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09` +- `30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "operation(\"read\")", + "resource(\"file1\")", + ], + }, + Facts { + origin: { + Some( + 0, + ), + }, + facts: [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 1, + ), + checks: [ + "check if resource($0), operation(\"read\"), right($0, \"read\")", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + diff --git a/samples/current/samples.json b/samples/current/samples.json index 1401846..fbb9462 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -154,7 +154,7 @@ "result": { "Err": { "Format": { - "InvalidSignatureSize": 16 + "BlockSignatureDeserializationError": "block signature deserialization error: [117, 149, 161, 18, 161, 235, 91, 129, 166, 227, 152, 133, 46, 97, 24, 183]" } } }, @@ -2955,6 +2955,76 @@ ] } } + }, + { + "title": "ECDSA secp256r1 signatures", + "filename": "test036_secp256r1.bc", + "token": [ + { + "symbols": [ + "file1", + "file2" + ], + "public_keys": [], + "external_key": null, + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + }, + { + "symbols": [ + "0" + ], + "public_keys": [], + "external_key": null, + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "operation(\"read\")", + "resource(\"file1\")" + ] + }, + { + "origin": [ + 0 + ], + "facts": [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 1, + "checks": [ + "check if resource($0), operation(\"read\"), right($0, \"read\")" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n", + "revocation_ids": [ + "760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09", + "30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4" + ] + } + } } ] } diff --git a/samples/current/test036_secp256r1.bc b/samples/current/test036_secp256r1.bc new file mode 100644 index 0000000000000000000000000000000000000000..15a8a429e52823e318d362c4264507f2a92fc49d GIT binary patch literal 366 zcmWey!N_IH#hR9xlWGW|j3k(qc)7SaScI4*8aRZQBpBe_MpQ0XmQhHRgHcG4DQ;r_ z6*mi`b&Hy8|4tWMob5YXxO{K$-KM)=4(us?o4sGkp^Uxtp22mKzBw&btGlglU0ZM^ z`O8RpC-Q))O&X6YiBa=^-vqVbC;IZ-8VD4dZJ`=?8iWbWBPYb-@bH@Q)&() zmo^upfdsRW3YQWW6Nj`AI|q{xGe;AL5E}Joi6Mq$Qs}?-3+s?RB z)!LZ-vW|HD3MK{R??E;qHt}2Io}BvU+2GFfo^?4#^Xo5)ty{e>XVukQQBvYkIOTY2 jL+gaMOPmb1{rR$6kf&8!<%7ZgnOU75bj}>D+xigzPX&iC literal 0 HcmV?d00001 diff --git a/schema.proto b/schema.proto index 0a45085..2f6800d 100644 --- a/schema.proto +++ b/schema.proto @@ -27,6 +27,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; From d1badff930bd4053103e3f648cb4e7bb1ae6d4b4 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Wed, 20 Nov 2024 14:05:00 +0100 Subject: [PATCH 18/19] clarify datalog versions (3.x) improve a bit the specification for third-party block version constraints --- SPECIFICATIONS.md | 80 ++++++++++++++++++++++++++++------------------- schema.proto | 4 +-- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 35249c7..909f790 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -120,10 +120,10 @@ We will represent the various types as follows: - byte array: `hex:01A2` - date in RFC 3339 format: `1985-04-12T23:20:50.52Z` - boolean: `true` or `false` -- null: `null`, supported since block version 6 +- null: `null`, supported since v3.3 - set: `{ "a", "b", "c"}` -- array: `[ "a", true, null]`, supported since block version 6 -- map: `{ "a": true, 12: "a" }`, supported since block version 6 +- array: `[ "a", true, null]`, supported since v3.3 +- map: `{ "a": true, 12: "a" }`, supported since v3.3 As an example, assuming we have the following facts: `parent("a", "b")`, `parent("b", "c")`, `parent("c", "d")`. If we apply the rule @@ -315,8 +315,8 @@ succeeds (in the case of `reject if`, the check will fail if any query matches). - a `check all` query succeeds if all the sets of facts that match the body also succeed the expression. - a `reject if` query succeeds if no set of facts matches the body and expressions -`check all` can only be used starting from block version 4. -`reject if` can only be used starting from block version 6. +`check all` can only be used starting from `v3.1`. +`reject if` can only be used starting from `v3.3`. Here are some examples of writing checks: @@ -471,7 +471,7 @@ Here are the currently defined unary operations: - _parens_: returns its argument without modification (this is used when printing the expression, to avoid precedence errors) - _length_: defined on strings, byte arrays and sets (for strings, _length_ is defined as the number of bytes in the UTF-8 encoded string; the alternative of counting grapheme clusters would be inconsistent between languages) -- _type_, defined on all types, returns a string (v6 only) +- _type_, defined on all types, returns a string (v3.3+) - `integer` - `string` - `date` @@ -479,7 +479,7 @@ Here are the currently defined unary operations: - `bool` - `set` - `null` -- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v6 only) +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v3.3+) Here are the currently defined binary operations: @@ -488,7 +488,7 @@ Here are the currently defined binary operations: - _less or equal_, defined on integers and dates, returns a boolean - _greater or equal_, defined on integers and dates, returns a boolean - _strict equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean -- _strict not equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean (v4 only) +- _strict not equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean (v3.1+) - _contains_ takes a set and another value as argument, returns a boolean. Between two sets, indicates if the first set is a superset of the second one. between two strings, indicates a substring test. - _prefix_, defined on strings, returns a boolean @@ -502,19 +502,19 @@ Here are the currently defined binary operations: - _eager or_, defined on booleans, returns a boolean - _intersection_, defined on sets, return a set that is the intersection of both arguments - _union_, defined on sets, return a set that is the union of both arguments -- _bitwiseAnd_, defined on integers, returns an integer (v4 only) -- _bitwiseOr_, defined on integers, returns an integer (v4 only) -- _bitwiseXor_, defined on integers, returns an integer (v4 only) -- _lenient equal_, defined on all types, returns a boolean (v6 only) -- _lenient not equal_, defined on all types, returns a boolean (v6 only) -- _any_, defined on sets, takes a closure term -> boolean, returns a boolean (v6 only) -- _all_, defined on sets, takes a closure term -> boolean, returns a boolean (v6 only) -- _short circuiting and_, defined on booleans, takes a closure () -> boolean, returns a boolean (v6 only) -- _short circuiting or_, defined on booleans, takes a closure () -> boolean, returns a boolean (v6 only) -- _get_, defined on arrays and maps (v6 only) +- _bitwiseAnd_, defined on integers, returns an integer (v3.1+) +- _bitwiseOr_, defined on integers, returns an integer (v3.1+) +- _bitwiseXor_, defined on integers, returns an integer (v3.1+) +- _lenient equal_, defined on all types, returns a boolean (v3.3+) +- _lenient not equal_, defined on all types, returns a boolean (v3.3+) +- _any_, defined on sets, takes a closure term -> boolean, returns a boolean (v3.3+) +- _all_, defined on sets, takes a closure term -> boolean, returns a boolean (v3.3+) +- _short circuiting and_, defined on booleans, takes a closure () -> boolean, returns a boolean (v3.3+) +- _short circuiting or_, defined on booleans, takes a closure () -> boolean, returns a boolean (v3.3+) +- _get_, defined on arrays and maps (v3.3+) on arrays, takes an integer and returns the corresponding element (or `null`, if out of bounds) on maps, takes either an integer or a string and returns the corresponding element (or `null`, if out of bounds) -- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v6 only) +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v3.3+) Integer operations must have overflow checks. If it overflows, the expression fails. @@ -754,7 +754,7 @@ message Block { } ``` -Each block contains a `version` field, indicating at which format version it +Each block contains a `version` field, indicating at which datalog version it was generated. Since a Biscuit implementation at version N can receive a valid token generated at version N-1, new implementations must be able to recognize older formats. Moreover, when appending a new block, they cannot convert the @@ -766,12 +766,19 @@ each block must carry its own version. - An implementation may generate blocks with older formats to help with backwards compatibility, when possible, especially for biscuit versions that are only additive in terms of features. -- The lowest supported biscuit version is `3`; -- The highest supported biscuit version is `5`; +The format version is encoded as a single integer: -# Version 2 +- `v3.0` is encoded as `3` +- `v3.1` is encoded as `4` +- `v3.2` is encoded as `5` +- `v3.3` is encoded as `6` -This is the format for the 2.0 version of Biscuit. +- The lowest supported datalog version is `v3.0`; +- The highest supported datalog version is `v3.3`; + +# Format + +This is the format for the 3.x version of Biscuit. It transport expressions as an array of opcodes. @@ -837,6 +844,8 @@ ECDSA-Sig-Value ::= SEQUENCE { The data covered by the signature algorithm depends on the `version` field of the `SignedBlock` message. If the field is absent, it defaults to version 0. +Signature version 1 *must* be used for third-party blocks. + ##### Version 0 (deprecated) This defines the block signature payload v0. @@ -857,9 +866,9 @@ if `external_sig_n+1` is present, the signed payload format is instead the conca - `pk_n+2`: the next public key - `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` -This format is deprecated and will be replaced by version 1 in the future. +This format is deprecated and will be gradually replaced by version 1. -the signed payload format for external signatures, thereafter referred as "external signature payload v0", is the concatenation of: +The signed payload format for external signatures, thereafter referred as "external signature payload v0", is the concatenation of: - `data_n+1`: the serialized Datalog - `pk_n+1`: the public key for the next block - `alg_n+1`: the little endian representation of the signature algorithm for `pk_n+1` @@ -1133,7 +1142,7 @@ block in order, the block's symbols. It is important to verify that different blocks do not contain the same symbol in their list. -##### 3rd party blocks (with an external signature) +##### third party blocks (with an external signature) Blocks that are signed by an external key don't use the token symbol table and start from the default symbol table. Following blocks ignore the symbols @@ -1148,7 +1157,7 @@ Public keys carried in `SignedBlock`s are stored as is, as they are required for Public keys carried in datalog scope annotations are stored in a table, to reduce token size. -Public keys are interned the same way for first-party and third-party tokens, unlike symbols. +Third-party blocks use an isolated public keys table, same as for symbols. #### Reading @@ -1171,14 +1180,14 @@ that were not present in the table yet. Third party blocks are special blocks, that are meant to be signed by a trusted party, to either expand a token or fulfill special checks with dedicated public key constraints. -Unlike first-party blocks, the party signing the token should not have access to the token itself. The third party needs however some context in order to be able to properly serialize and sign block contents. Additionally, the third party needs to return both the serialized block and the external signature. +Unlike first-party blocks, the party signing the token should not have access to the token itself. The third party needs however some context in order to be able to properly sign block contents. Additionally, the third party needs to return both the serialized block and the external signature. To support this use-case, the protobuf schema defines two message types: `ThirdPartyBlockRequest` and `ThirdPartyBlockContents`: ``` message ThirdPartyBlockRequest { - required PublicKey previousKey = 1; - repeated PublicKey publicKeys = 2; + optional PublicKey legacyPreviousKey = 1; + repeated PublicKey legacyPublicKeys = 2; required bytes previousSignature = 3; } @@ -1190,8 +1199,9 @@ message ThirdPartyBlockContents { `ThirdPartyBlockRequest` contains the necessary context for serializing and signing a datalog block: -- `previousKey` is needed for the signature (it makes sure that a third-party block can only be used for a specific biscuit token -- `publicKeys` is the list of public keys already present in the token table; they are used for serialization +- `legacyPreviousKey` was needed for the signature. It is not needed anymore with `v1` signatures and must be empty. +- `legacyPublicKeys` was needed for serialization but is not used anymore, it must be empty. +- `previousSignature` is needed for the signature (to make sure that a third-party block can only be used for a specific biscuit token) `ThirdPartyBlockContents` contains both the serialized `Block` and the external signature. @@ -1211,6 +1221,10 @@ An implementation must be able to: Same as biscuit tokens, the `ThirdPartyBlockRequest` and `ThirdPartyBlockContents` values can be transfered in text format by encoding them with base64url. +### Third-party block datalog version + +Third-party blocks must at least have datalog version `3.2` (implementations not supporting at least version `3.2` have different symbol tables mechanisms and may interpret third-party blocks incorrectly). + ## Test cases We provide sample tokens and the expected result of their verification at diff --git a/schema.proto b/schema.proto index 2f6800d..02e9eab 100644 --- a/schema.proto +++ b/schema.proto @@ -218,8 +218,8 @@ message AuthorizerPolicies { } message ThirdPartyBlockRequest { - required PublicKey previousKey = 1; - repeated PublicKey publicKeys = 2; + optional PublicKey legacyPreviousKey = 1; + repeated PublicKey legacyPublicKeys = 2; required bytes previousSignature = 3; } From ca26dbc35ec41f0548cda32fd0ad872c8f0d7733 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Fri, 29 Nov 2024 11:32:12 +0100 Subject: [PATCH 19/19] document the empty set literal --- SPECIFICATIONS.md | 6 +++--- samples/current/README.md | 4 +++- samples/current/samples.json | 5 +++-- samples/current/test017_expressions.bc | Bin 1687 -> 1721 bytes 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 697039e..0ac3495 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -121,9 +121,9 @@ We will represent the various types as follows: - date in RFC 3339 format: `1985-04-12T23:20:50.52Z` - boolean: `true` or `false` - null: `null`, supported since v3.3 -- set: `{ "a", "b", "c"}` +- set: `{"a", "b", "c"}` (the empty set is `{,}`) - array: `[ "a", true, null]`, supported since v3.3 -- map: `{ "a": true, 12: "a" }`, supported since v3.3 +- map: `{ "a": true, 12: "a" }` (the empty map is `{}`), supported since v3.3 As an example, assuming we have the following facts: `parent("a", "b")`, `parent("b", "c")`, `parent("c", "d")`. If we apply the rule @@ -205,7 +205,7 @@ The logic language is described by the following EBNF grammar: ::= "true" | "false" ::= "null" ::= [0-9]* "-" [0-9] [0-9] "-" [0-9] [0-9] "T" [0-9] [0-9] ":" [0-9] [0-9] ":" [0-9] [0-9] ( "Z" | ( ("+" | "-") [0-9] [0-9] ":" [0-9] [0-9] )) - ::= "{" ? ( ( ? "," ? )* ? )? "}" + ::= "{" "," | (? ( ( ? "," ? )* ? ) )"}" ::= "[" ? ( ( ? "," ? )* ? )? "]" ::= ( | ) ? ":" ? ::= "{" ? ( ( ? "," ? )* ? )? "}" diff --git a/samples/current/README.md b/samples/current/README.md index 0d37829..4a7ad09 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -1321,6 +1321,7 @@ check if {1, 2}.intersection({2, 3}) === {2}; check if {1, 2}.union({2, 3}) === {1, 2, 3}; check if {1, 2, 3}.intersection({1, 2}).contains(1); check if {1, 2, 3}.intersection({1, 2}).length() === 2; +check if {,}.length() === 0; ``` ### validation @@ -1331,7 +1332,7 @@ allow if true; ``` revocation ids: -- `d0420227266e3583a42dfaa0e38550d99f681d150dd18856f3af9a697bc9c5c8bf06b4b0fe5b9df0377d1b963574e2fd210a0a76a8b0756a65f640c602bebd07` +- `fa358e4e3bea896415b1859e6cd347e64e1918fb86e31ae3fe208628321576a47f7a269760357e291c827ec9cbe322074f6860a546207a64e133c83a214bb505` authorizer world: ``` @@ -1372,6 +1373,7 @@ World { "check if true", "check if true === true", "check if {\"abc\", \"def\"}.contains(\"abc\")", + "check if {,}.length() === 0", "check if {1, 2, 3}.intersection({1, 2}).contains(1)", "check if {1, 2, 3}.intersection({1, 2}).length() === 2", "check if {1, 2} === {1, 2}", diff --git a/samples/current/samples.json b/samples/current/samples.json index 539d5e1..6a71317 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -1276,7 +1276,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if true;\ncheck if !false;\ncheck if true === true;\ncheck if false === false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 === 3;\ncheck if 1 + 2 * 3 - 4 / 2 === 5;\ncheck if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" === \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" === \"abcD12\";\ncheck if \"abcD12\".length() === 6;\ncheck if \"é\".length() === 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z;\ncheck if hex:12ab === hex:12ab;\ncheck if {1, 2}.contains(2);\ncheck if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z);\ncheck if {false, true}.contains(true);\ncheck if {\"abc\", \"def\"}.contains(\"abc\");\ncheck if {hex:12ab, hex:34de}.contains(hex:34de);\ncheck if {1, 2}.contains({2});\ncheck if {1, 2} === {1, 2};\ncheck if {1, 2}.intersection({2, 3}) === {2};\ncheck if {1, 2}.union({2, 3}) === {1, 2, 3};\ncheck if {1, 2, 3}.intersection({1, 2}).contains(1);\ncheck if {1, 2, 3}.intersection({1, 2}).length() === 2;\n", + "code": "check if true;\ncheck if !false;\ncheck if true === true;\ncheck if false === false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 === 3;\ncheck if 1 + 2 * 3 - 4 / 2 === 5;\ncheck if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" === \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" === \"abcD12\";\ncheck if \"abcD12\".length() === 6;\ncheck if \"é\".length() === 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z;\ncheck if hex:12ab === hex:12ab;\ncheck if {1, 2}.contains(2);\ncheck if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z);\ncheck if {false, true}.contains(true);\ncheck if {\"abc\", \"def\"}.contains(\"abc\");\ncheck if {hex:12ab, hex:34de}.contains(hex:34de);\ncheck if {1, 2}.contains({2});\ncheck if {1, 2} === {1, 2};\ncheck if {1, 2}.intersection({2, 3}) === {2};\ncheck if {1, 2}.union({2, 3}) === {1, 2, 3};\ncheck if {1, 2, 3}.intersection({1, 2}).contains(1);\ncheck if {1, 2, 3}.intersection({1, 2}).length() === 2;\ncheck if {,}.length() === 0;\n", "version": 3 } ], @@ -1317,6 +1317,7 @@ "check if true", "check if true === true", "check if {\"abc\", \"def\"}.contains(\"abc\")", + "check if {,}.length() === 0", "check if {1, 2, 3}.intersection({1, 2}).contains(1)", "check if {1, 2, 3}.intersection({1, 2}).length() === 2", "check if {1, 2} === {1, 2}", @@ -1339,7 +1340,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "d0420227266e3583a42dfaa0e38550d99f681d150dd18856f3af9a697bc9c5c8bf06b4b0fe5b9df0377d1b963574e2fd210a0a76a8b0756a65f640c602bebd07" + "fa358e4e3bea896415b1859e6cd347e64e1918fb86e31ae3fe208628321576a47f7a269760357e291c827ec9cbe322074f6860a546207a64e133c83a214bb505" ] } } diff --git a/samples/current/test017_expressions.bc b/samples/current/test017_expressions.bc index 7be7a4fda92f3feecff08e8c3a68d1c53bea2100..5b28d3609afbfeade00001e1228898200c837181 100644 GIT binary patch delta 116 zcmbQvyOWnyXc8~i@{O!)Y%)d)Tyk7Y9MVz}Tr6BnRt#J$LQEV?AhrO*WL7pkhhL_B ze%7x#Q$#nm&da&%{>)EO;&>5P}!eo9Tg4Hh*tBj tnrVB<#mK(~w6OkLo$xn(8Ty$6$(1|$ZpCIA2c