Skip to content

Commit 76e4e79

Browse files
committed
COSE-only ledgers
1 parent 2a4963a commit 76e4e79

30 files changed

+1016
-276
lines changed

doc/host_config_schema/cchost_config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,12 @@
623623
"type": "string",
624624
"default": "1000ms",
625625
"description": "Maximum duration after which a signature transaction is automatically generated"
626+
},
627+
"mode": {
628+
"type": "string",
629+
"enum": ["Dual", "COSE"],
630+
"default": "Dual",
631+
"description": "Ledger signature mode. Dual emits both regular and COSE signatures. COSE emits only COSE signatures."
626632
}
627633
},
628634
"description": "This section includes configuration for the ledger signatures emitted by this node (note: should be the same for all other nodes in the service). Transaction commit latency in a CCF network is primarily a function of signature frequency. A network emitting signatures more frequently will be able to commit transactions faster, but will spend a larger proportion of its execution resources creating and verifying signatures. Setting signature frequency is a trade-off between transaction latency and throughput",

doc/schemas/app_openapi.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,34 @@
16921692
}
16931693
}
16941694
},
1695+
"/app/receipt/cose": {
1696+
"get": {
1697+
"description": "A COSE Sign1 envelope containing a signed statement from the service over a transaction entry in the ledger, with a Merkle proof in the unprotected header.",
1698+
"operationId": "GetAppReceiptCose",
1699+
"parameters": [
1700+
{
1701+
"in": "query",
1702+
"name": "transaction_id",
1703+
"required": true,
1704+
"schema": {
1705+
"$ref": "#/components/schemas/TransactionId"
1706+
}
1707+
}
1708+
],
1709+
"responses": {
1710+
"204": {
1711+
"description": "Default response description"
1712+
},
1713+
"default": {
1714+
"$ref": "#/components/responses/default"
1715+
}
1716+
},
1717+
"summary": "COSE receipt for a transaction",
1718+
"x-ccf-forwarding": {
1719+
"$ref": "#/components/x-ccf-forwarding/sometimes"
1720+
}
1721+
}
1722+
},
16951723
"/app/tx": {
16961724
"get": {
16971725
"description": "Possible statuses returned are Unknown, Pending, Committed or Invalid.",

doc/schemas/node_openapi.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,34 @@
16831683
}
16841684
}
16851685
},
1686+
"/node/receipt/cose": {
1687+
"get": {
1688+
"description": "A COSE Sign1 envelope containing a signed statement from the service over a transaction entry in the ledger, with a Merkle proof in the unprotected header.",
1689+
"operationId": "GetNodeReceiptCose",
1690+
"parameters": [
1691+
{
1692+
"in": "query",
1693+
"name": "transaction_id",
1694+
"required": true,
1695+
"schema": {
1696+
"$ref": "#/components/schemas/TransactionId"
1697+
}
1698+
}
1699+
],
1700+
"responses": {
1701+
"204": {
1702+
"description": "Default response description"
1703+
},
1704+
"default": {
1705+
"$ref": "#/components/responses/default"
1706+
}
1707+
},
1708+
"summary": "COSE receipt for a transaction",
1709+
"x-ccf-forwarding": {
1710+
"$ref": "#/components/x-ccf-forwarding/sometimes"
1711+
}
1712+
}
1713+
},
16861714
"/node/self_signed_certificate": {
16871715
"get": {
16881716
"operationId": "GetNodeSelfSignedCertificate",

include/ccf/node/startup_config.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,17 @@ namespace ccf
5353
};
5454
Ledger ledger = {};
5555

56+
enum class LedgerSignMode
57+
{
58+
Dual = 0,
59+
COSE = 1
60+
};
61+
5662
struct LedgerSignatures
5763
{
5864
size_t tx_count = 5000;
5965
ccf::ds::TimeString delay = {"1000ms"};
66+
LedgerSignMode mode = LedgerSignMode::Dual;
6067

6168
bool operator==(const LedgerSignatures&) const = default;
6269
};

python/src/ccf/cose.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ def verify_receipt(
195195
"""
196196
Verify a COSE Sign1 receipt as defined in https://datatracker.ietf.org/doc/draft-ietf-cose-merkle-tree-proofs/,
197197
using the CCF tree algorithm defined in https://datatracker.ietf.org/doc/draft-birkholz-cose-receipts-ccf-profile/
198+
199+
If claim_digest is None, the claims digest in the leaf is not verified.
198200
"""
199201
key_pem = key.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo).decode(
200202
"ascii"
@@ -227,7 +229,7 @@ def verify_receipt(
227229
proof = cbor2.loads(inclusion_proof)
228230
assert CCF_PROOF_LEAF_LABEL in proof, "Leaf must be present"
229231
leaf = proof[CCF_PROOF_LEAF_LABEL]
230-
if claim_digest != leaf[2]:
232+
if claim_digest and claim_digest != leaf[2]:
231233
raise ValueError(f"Claim digest mismatch: {leaf[2]!r} != {claim_digest!r}")
232234
accumulator = hashlib.sha256(
233235
leaf[0] + hashlib.sha256(leaf[1].encode()).digest() + leaf[2]

python/src/ccf/ledger.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,10 +724,15 @@ def add_transaction(self, transaction):
724724
else:
725725
self.node_certificates[node_id] = endorsed_node_cert
726726

727-
# This is a merkle root/signature tx if the table exists
728-
if SIGNATURE_TX_TABLE_NAME in tables:
727+
# This is a merkle root/signature tx if either signature table exists
728+
is_signature_tx = (
729+
SIGNATURE_TX_TABLE_NAME in tables
730+
or COSE_SIGNATURE_TX_TABLE_NAME in tables
731+
)
732+
if is_signature_tx:
729733
self.signature_count += 1
730734

735+
if SIGNATURE_TX_TABLE_NAME in tables:
731736
if self.verification_level >= VerificationLevel.MERKLE:
732737
signature_table = tables[SIGNATURE_TX_TABLE_NAME]
733738

samples/config/join_config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
},
4343
"ledger_signatures": {
4444
"tx_count": 5000,
45-
"delay": "1s"
45+
"delay": "1s",
46+
"mode": "Dual"
4647
},
4748
"jwt": {
4849
"key_refresh_interval": "30min"

samples/config/recover_config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
},
4343
"ledger_signatures": {
4444
"tx_count": 5000,
45-
"delay": "1s"
45+
"delay": "1s",
46+
"mode": "Dual"
4647
},
4748
"jwt": {
4849
"key_refresh_interval": "30min"

samples/config/start_config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@
7171
},
7272
"ledger_signatures": {
7373
"tx_count": 5000,
74-
"delay": "1s"
74+
"delay": "1s",
75+
"mode": "Dual"
7576
},
7677
"jwt": {
7778
"key_refresh_interval": "30min"

src/common/configuration.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,15 @@ namespace ccf
6767
DECLARE_JSON_OPTIONAL_FIELDS(
6868
CCFConfig::Ledger, directory, read_only_directories, chunk_size);
6969

70+
DECLARE_JSON_ENUM(
71+
CCFConfig::LedgerSignMode,
72+
{{CCFConfig::LedgerSignMode::Dual, "Dual"},
73+
{CCFConfig::LedgerSignMode::COSE, "COSE"}});
74+
7075
DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(CCFConfig::LedgerSignatures);
7176
DECLARE_JSON_REQUIRED_FIELDS(CCFConfig::LedgerSignatures);
72-
DECLARE_JSON_OPTIONAL_FIELDS(CCFConfig::LedgerSignatures, tx_count, delay);
77+
DECLARE_JSON_OPTIONAL_FIELDS(
78+
CCFConfig::LedgerSignatures, tx_count, delay, mode);
7379

7480
DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(CCFConfig::JWT);
7581
DECLARE_JSON_REQUIRED_FIELDS(CCFConfig::JWT);

0 commit comments

Comments
 (0)