Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signature payload format v1 #175

Merged
merged 15 commits into from
Nov 19, 2024
52 changes: 48 additions & 4 deletions SPECIFICATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ message SignedBlock {
required PublicKey nextKey = 2;
required bytes signature = 3;
optional ExternalSignature externalSignature = 4;
optional uint32 version = 5;
}

message ExternalSignature {
Expand Down Expand Up @@ -722,7 +723,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
Expand Down Expand Up @@ -780,13 +782,52 @@ 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)

To sign the block at index `n`, we would have:
- `data_n`: the serialized Datalog
- `pk_n+1`: the next public key
- `alg_n+1`: the little endian representation of the signature algorithm for `pk_n+1`
- `external_sig_n`: te optional external signature of the block
Geal marked this conversation as resolved.
Show resolved Hide resolved

if `external_sig_n` is present, the signed payload format, thereafter referred as "block signature payload v0", would be the concatenation of:
- `data_n`
- `external_sig_n`
- `pk_n+1`
- `alg_n+1`

otherwise, we would have:
- `data_n`
- `pk_n+1`
- `alg_n+1`

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", would be the concatenation of:
- `data_n`
- `pk_n+1`
- `alg_n+1`

This format is not supported anymore and should be replaced by version 1.

##### Version 1

TODO

#### 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 signature payload by `sk_0`

The token will contain:

Expand Down Expand Up @@ -819,7 +860,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 signature payload by `sk_n+1`.

The token will contain:

Expand All @@ -845,8 +888,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`).
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`.
It is 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`).
Geal marked this conversation as resolved.
Show resolved Hide resolved
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).

Expand Down Expand Up @@ -1055,6 +1098,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 {
Expand Down
117 changes: 45 additions & 72 deletions samples/current/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1835,7 +1835,7 @@ allow if true;

revocation ids:
- `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03`
- `342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03`
- `8556bc91ed8bd1e4c0b6b37bead75d91d332c4144d72e7db715e6300732dc691dbd1f444f1a7a07be8bac60358bf14330b5b8963685490cfb648df879efc9e0a`

authorizer world:
```
Expand Down Expand Up @@ -2097,9 +2097,9 @@ allow if true;

revocation ids:
- `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04`
- `6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d`
- `5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04`
- `c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09`
- `87ce330211e0bca95aebcbbe349c954473f49e6593b6fee34f2be93122d4f930f0fc2dedfc1721b9d2e5346befb97aef75c28a13cc2647bb99e499ceb565470d`
- `f3dc02647a3c011e87dda6050fbd67c2e037454f186eb4ba0c029c0da7b0eb309c7d24ad5f073571b11876ef9bb7955ecb462c00457a258c4e1ba4eafbae420c`
- `88c9eea7c2e17409ce542a0e8fe78c53627fc2346ffde3d8d280eb86250c6c84efa5d84ea1f644a7bcfdfc68e2efc07350132c7fc80061014fa9d678c201b20a`
- `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900`

authorizer world:
Expand Down Expand Up @@ -2657,97 +2657,70 @@ 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 {
origin: Some(
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}",
],
},
]
Expand All @@ -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" })] }))`


------------------------------
Expand Down
8 changes: 4 additions & 4 deletions samples/current/samples.json
Original file line number Diff line number Diff line change
Expand Up @@ -1795,7 +1795,7 @@
"authorizer_code": "allow if true;\n",
"revocation_ids": [
"470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03",
"342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03"
"8556bc91ed8bd1e4c0b6b37bead75d91d332c4144d72e7db715e6300732dc691dbd1f444f1a7a07be8bac60358bf14330b5b8963685490cfb648df879efc9e0a"
]
}
}
Expand Down Expand Up @@ -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",
"87ce330211e0bca95aebcbbe349c954473f49e6593b6fee34f2be93122d4f930f0fc2dedfc1721b9d2e5346befb97aef75c28a13cc2647bb99e499ceb565470d",
"f3dc02647a3c011e87dda6050fbd67c2e037454f186eb4ba0c029c0da7b0eb309c7d24ad5f073571b11876ef9bb7955ecb462c00457a258c4e1ba4eafbae420c",
"88c9eea7c2e17409ce542a0e8fe78c53627fc2346ffde3d8d280eb86250c6c84efa5d84ea1f644a7bcfdfc68e2efc07350132c7fc80061014fa9d678c201b20a",
"3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900"
]
}
Expand Down
Binary file modified samples/current/test024_third_party.bc
Binary file not shown.
Binary file modified samples/current/test026_public_keys_interning.bc
Binary file not shown.
26 changes: 26 additions & 0 deletions schema.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ message SignedBlock {
required PublicKey nextKey = 2;
required bytes signature = 3;
optional ExternalSignature externalSignature = 4;
optional uint32 version = 5;
}

message ExternalSignature {
Expand Down Expand Up @@ -99,13 +100,35 @@ message TermV2 {
bool bool = 6;
TermSet set = 7;
Empty null = 8;
Array array = 9;
divarvel marked this conversation as resolved.
Show resolved Hide resolved
Map map = 10;
}
}

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;
}
Expand Down Expand Up @@ -159,6 +182,7 @@ message OpBinary {
LazyOr = 24;
All = 25;
Any = 26;
Get = 27;
}

required Kind kind = 1;
Expand Down Expand Up @@ -191,6 +215,8 @@ message AuthorizerPolicies {
message ThirdPartyBlockRequest {
required PublicKey previousKey = 1;
repeated PublicKey publicKeys = 2;
required bytes previousSignature = 3;

}

message ThirdPartyBlockContents {
Expand Down