microsoft / CCF

Confidential Consortium Framework
https://microsoft.github.io/CCF/
Apache License 2.0
777 stars 211 forks source link

Commit evidence in receipts #3295

Closed achamayou closed 2 years ago

achamayou commented 2 years ago

Commit receipts

Terminology: Execution Receipt vs Commit Receipt

Commit Receipt := Execution Receipt + Evidence of Commit

How can a user trust a receipt is for a committed state?

1. The receipt or its constituent parts are only ever produced, or released out of the enclave after commit happens

The contents of the signature Tx stay in enclave until commit?

No

The contents of the signature tx are temporarily encrypted when written out, and decrypted and re-written in place on commit.

No

2. The receipt contains an additional piece of evidence, produced or released after commit happens.

- A later signature

TxID <- Sig1 = Sig([..TxID..]) <- Sig2([commit >= Sig1])

No

TxID <- Sig(commit >= TxID)? Doesn't bound commit latency. Lose provenance. Also No

- Another signature

Can work, but expensive

- A Nonce/Secret

Cheap to produce, include digest in receipt (committment), release in the fullness of time on commit.

TxDigest := Digest(Write Set) + Digest(User claims) + Digest(Commit Nonce/Secret [+ TxID])
Commit Nonce/Secret := Digest(Ledger Secret[TxID], TxID)

Note: ledger alone doesn't tell you what's committed. Need a receipt (or a snapshot). Doesn't seem like a big problem, if service is live, can ask for receipt. If not, members decide, persistence is meaningless and provenance can still be checked.

If Digest(Nonce) in ledger, then:

Else:

Seems best, simple and low overhead

What goes in the nonce?

Granular, unique per-Tx.

Same nonce for all transactions between Sig and next(Sig) => fewer nonces if we decide to store them.

But more difficult for a node to derive the nonce, must find signature that immediately precedes transaction. Unless we tag each Tx with the TxID of the previous signature. Or tag the TxID in the next signature, but then there's no provenance.

Intuition of difficulties around rekey, but no obvious counter-example.

Can the nonce go in the ledger?

To make sure the ledger alone is enough to produce commit receipts (assuming transparent user claims!), we could store the nonces in either their own transaction, or a signature, from time to time.

It must not be a signature, signatures can only contain a signature!

If we store the nonces, having them per signature rather than per transaction may be attractive.

But storing the nonces in a separate Tx generates a constant stream of transactions, the "Treadmill problem".

If we batch, we must batch per signature because:

TxID in receipt

How can a user trust a receipt is for a specific TxID?

  1. Bind at the leaf: include the TxID in a user separable way inside the TxDigest (ie. not in the WriteSet) Yes
  2. Bind at the signature: execution receipt could sign over (root + TxID), path offset to get TxID, ONLY for canonical receipt, otherwise need view history. No

Preferred direction summary

Top-level

User Claims Digest := Digest(User Claims)
TxDigest := Digest(Service Claims Digest + User Claims Digest)

Service Claims Digest A := Digest(Digest(Write Set), Digest(Commit Nonce), Digest(TxID))
Service Claims Digest B := Digest(Digest(Write Set), Digest(Commit Nonce + TxID))
Service Claims Digest C := Digest(Digest(Write Set), Digest(Commit Nonce), TxID))

or

TxDigest := Digest(Digest(Write Set), Digest(User claims), Digest(Commit Nonce/Secret + TxID))

Commit evidence

Commit Nonce/Secret := Digest(Ledger Secret[TxID], TxID)

Easy to derive, requires no storage.

achamayou commented 2 years ago
TxDigest := Digest(Digest(Write Set), Digest(User claims), Digest(Commit Evidence))

Commit Secret:= HMAC(Ledger Secret[TxID], TxID)
Commit Evidence:="ce:{TxID}:{Commit Secret}", eg. ce:2.57:06fef62c80b6471c7005c1b114166fd1b0e077845f5ad544ad4eea4fb1d31f78