try·st·imu·li

13.80940

i’ve been prototyping versioned nodes implementations. one thing that is proving difficult is managing the sheer number of types of capabilities.

the basic capabilities are:

  • fetch blob (hash)
  • fetch version (signature)
  • fetch any version of braid (public key)
  • read blob/version (shared key)
  • write new version to braid (secret key)

fetch capabilities are usually included in the public data of a node. read capabilities are generally included in the encrypted data, so that reading a node will usually provide the capability to read nodes that it references. however, write capabilities are more complicated.

if we want to embed write access to node a in node b at all, we usually want to give it only to those with write access to node b. so a plain write capability can’t be written directly in the encrypted data. instead, we encrypt write capability again, “sealing” it with another write capability. this may not be the write capability for the current node, because the current node may be a blob under a version…

so we have another basic capability:

  • sealed “write a new version to braid” (encrypted secret key)

then we combine them.


the capabilities written into the nodes are pretty easy:

  • fetch (written outside) + read + optional sealed write (only if fetch is a version or public key)

but once they are read into the program for use, it quickly becomes more complicated.

when we’re writing an updated to a node, we face three scenarios:

  1. we are updating a blob, we need:
    • a context for the convergence domain
    • a secret key to seal any other secret keys with
  2. we are updating a braid but only have a sealed secret key for it, we need:
    • the current version
    • the secret key our secret key was sealed with
  3. we are updating a braid and have the secret key for it, we need:
    • the current version (if any)

this could be simplified by providing a dedicated read+write capability store in each node.

  • fetch capabilities are stored in the plaintext and are sorted.
  • read capabilities are stored in the encrypted data.
  • write capabilities are stored in the encrypted data and sealed by the relevant write capability.

here, i imagine the encrypted data contains, in addition to the normal data, a sequence of read and (possibly) sealed write capabilities. the typical arrangement might be to place them in an array, ordered by the fetch capabilities outside.

decrypting the node with just a read capability discards the sealed write capabilities, while decrypting with both a read and write capability will preserve them.

then in the body of the node, capabilities can simply be referred to by their index.

this changes the scenarios we face:

  1. updating a blob with no context:
    • we don’t need anything
    • but cannot save write capabilities!
  2. updating a blob in the context of a braid:
    • need the write capability for that braid (for context and saving write capabilities)
  3. updating a braid:
    • need to have read the braid for writing
    • need the current version (if any)
    • need the write capability for that braid

this significantly simplifies the combinations of capabilities exposed to libraries/programs.

any node decrypted with a read capability comes with:

  • its fetch (hash or signature) and read capability
  • a set of fetch+read capabilities for linked nodes
  • the user data

any node decrypted with both a read and write capability comes with:

  • its fetch (hash or signature), read, and write capability for the nearest braid
  • a set of fetch (hash, signature or public key)+read+maybe write capabilities for linked nodes
  • the user data
published