Certified Assets from Motoko (PoC/Tutorial)

Every now and then someone asks whether Motoko canisters can use certified variables, or whether they can serve HTTP requests with certification, and I always responded that yes, Motoko can do that, all that’s missing are a few libraries. But I figured I should put my hand where my mouth is, and actually demonstrate that it’s possible.

So here we go. If you go to https://ce7vw-haaaa-aaaai-aanva-cai.ic0.app/ you will see that

To prove the latter claim, here is the commented code; you can also browse the full repository.

Actually, the code is not here, because of this annoying 403 bug of the forum where after carefully editing and formatting the post, it says I can’t post it. Too many URLs maybe? :frowning: So unfortunately, you’ll have to go to https://gist.github.com/nomeata/f325fcd2a6692df06e38adedf9ca1877 to read it.

10 Likes

Oh, even nicer: This file can be loaded into Motoko Playground! So if you go to Motoko Playground - DFINITY you can click Deploy, and see it in action! You’ll have to take the canister it reported by Motoko Playground and construct the .ic0.app URL from it. And certification will fail until you send a message (most easily done directly from Motoko Playground) or upgrade the canister.

6 Likes

Great works.

This demo is very helpful to understand certificate.

I have some questions:

  1. If leave_message is not called, the signature of the certificate should be the same, but each time the certificate obtained has a small part of the string different, and the guess /time field is different, is it right?
  2. The /time field is not included in the signed message, can the node theoretically modify /time field?
  3. Similar to “http_assets” in asset_tree, is there any other? What are the other certificate application scenarios, and how do they need to construct this asset_tree.
1 Like

Correct

No: while it is possible to omit data from a Merkle tree without breaking the signature, you can’t add or modify fields.

But since the spec says that the time field ought to be there, a validating client should reject a certificate that doesn’t include it.

The canister signature schemes used by the Internet Identity is another protocol based on certified variables. I don’t know of any other common protocols yet, but assume that there could be application-specific ones.

1 Like

Thanks for this guide.

I’m trying to wrap my head around certified variables, and it seems like there are two Merkle trees (and their respective root hashes) at play here.

  1. The system-level Merkle tree representing the IC state tree. This is returned by CertifiedData.getCertificate in Motoko, which can be passed to a client in the response of a query call for verification. It is always passed to a client who polls for the response of an update call. This Merkle tree includes the 32-byte blob that represents the certified variable at /canisters/<canister_id>/certified_data. This Merkle tree is updated and appropriately pruned by the replica.
  1. The application-level Merkle tree representing the application-specific data that needs to be certified and thus made secure. This is constructed and maintained in memory inside the canister, and must be updated and pruned by the canister logic. The root hash of this Merkle tree is stored as a certified variable inside /canisters/<canister_id>/certified_data using CertifiedData.set in Motoko, and is signed by the subnet by virtue of being part of the IC state tree, whose root hash is always signed by the subnet.

It seems to me that both Merkle trees are necessary to implement certified variables—having one is not enough. The second Merkle tree is directly related to the first Merkle tree, because the root hash of the second tree is stored inside the first tree (whose root hash is returned to the user as part of a Certificate).

The client that queries for a certified asset (or other certified data) must validate both Merkle trees by recomputing the root hash and comparing it with the provided root hash, for each tree. The client only needs to validate one signature, however, and that’s the signature of the root hash of the first Merkle tree for the IC state tree.

Does this sound right to you @nomeata? This was not trivial to figure out.

1 Like

Yes, absolutely! Nice summary :slight_smile:

Note that always pruned merkle trees are passed around, revealing different information. Certified.getCertificate reveals the certified_data of the canister, while the partial merkle tree polled in an update call reveals the request status. But they are both part of the same per-subnet state tree.

1 Like