Object Signing ============== Signing objects is very important. But the other issue is authenticating that the signed object is valid. One issue that is if a key is compromised, it can be used to sign statements that objects in the past are valid. One way to address this situation is to sign the current Merkle DAG that contains all the "produced" objects by that author. The tree structure of a Merkle DAG with selective split locations allow the tree to add additional objects w/o recalculating the entire tree. This also allows rolling keys more simply, as the new key starts signing the new root, and once verification of the new key has been done, the objects are now authenticated again. When this happens, no old keys need be kept, and it's encouraged to remove the old keys and only keep one, the current key, for each identity. As this spec is geared toward JSON encoding, but Objects: Identity - uuid: UUIDv4 - updated: Date that this object was last updated - name: Common name of this identity. - email (optional) - info - tree_hash: Hash of the root of the object tree - public_key: A publicKey object as specified in [JSF] - sig: The signature of the object, a signaturecore as defined by [JSF]. name: Note that it is recommended to ensure that this is unique among all the identities imported/trusted, and that work is done to present look alike names. Giving an option to rename an Identity locally is highly recommended to make it easier for the user. info: General information text about this identity. tree_hash: The multihash of the root of the object tree. sig: Note that keyId and publicKey should not be included, as the public key used to verify the signature MUST be the publick_key as specified by the public_key property of the Identity object. ValidIdentity - identity: UUIDv4 of the identity. - identity_pubkey: The publicKey object, per [JSF], of the Identity object being asserted. - assertee: UUIDv4 of the identity asserting the validity. - assertee_pubkey: The publicKey object, per [JSF], of the Identity object being asserted. - sig: Signature of the assertion, a signateurecore by [JSF]. It is yet to be decided if the ValidIdentity object will be used. The tree_hash is a [multihash]. The data refered will be a JSON [JCS] encoded object or array. If it is an array, then each element of the array will be a multihash refering to an object that validated by the tree. The array MUST on contain unique multihashes, that is the array is the equivalent of a set. The array MUST be sorted, so that a binary search may be used over the array to find if a multihash is present or not. If the data is an object, it will contain a key to help locate the object, with the value being another multihash, refering to either an object or array again. In all cases, the order of objects MUST be: tree_hash -> [ object -> ]* array -> authenticated object. If objects are used, the keys SHALL be based upon the last modified date of the object. The first level MUST be year, then month, then day, then hour, then minute, then second, then milisecond, then microsecond. If the encoded array is longer than 256KiB, it MUST be broken up, and a new level of objects MUST be added. Note that the contents of the multihash are NOT distributed w/ the Identity object. The entire tree may be very large, and a complete tree is NOT needed to verify a subset of the tree. It is expected that the parts will be hosted via IPFS, or another mechanism allowing the retrival of the data. Questions: - Should ranges be supported for keys? That is, days could be `05-13`. Advantages, easier to split nodes. Actually, better will be to use a proper B-tree style structure, where there's a left node, and then each key has all the values between it and the next node. - Use Base64URL or Base32? JSF uses Base64URL though. - Should hard limits be enforced on the array length? - IPFS has a 1MiB block size limit, and it looks like UnixFS uses a default block size of 256KiB, so something similar should be used. Maybe recommend even smaller, say 8KiB? - What should block garbage collection be? That is when a block is no longer in the tree, how long should it be "available" for? This partly depends upon how often the Identity object is published, that is, only push a complete tree when an Identity hash is "published" or fetched publicly. - When distributing a set, use the IPFS CAR format? or something else? - Should the merkle tree objects be a proper object themselves? That is have their own UUID? If anything, this is more like a UUIDv5 type thing where the object would have a UUIDv5, BUT why use that when hashing the object directly gives the same results? Advantage, the objects can be passed as normal, everyday objects, disadvantage is that there will be more overhead, and cannot use IPFS directly for serving the blocks. Answered: - Should a [Rabin fingerprint] be used? Other option is to create a n-tree. No, as this needs to be an append (in time) friendly structure, where inserting hashes into a sorted list will be random, causing lots of blocks to be created and unable to be cached. [Rabin fingerprint]: https://en.wikipedia.org/wiki/Rabin_fingerprint [multihash]: https://multiformats.io/multihash/ [JCS]: https://tools.ietf.org/html/rfc8785 [JSF]: https://cyberphone.github.io/doc/security/jsf.html