You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DIDPublish is a powerful StreamType which enables a DID to publish any structured content to a global decentralized context.
Abstract
The DIDPublish stream type makes it possible for a DID to publish any structured content which can be represented by a single CID. The stream itself is ephemeral, i.e. the commit log is not persisted, this means that it is fast to sync since there is no history that needs to be verified. The content a DID publishes can be associated with some metadata information (e.g. family, tags) and the relevant DID(s). Any observer that only knows the DID and metadata can resolve the published CID.
Motivation
Traditionally Ceramic streams have relied on an append-only data structure where all history is present and conflicts are resolved though the earliest anchor rule. This works great when there is a need for strong verifiability of the history of the log or as a primitive for secure key revocation, but it requires the entire log to be processed in order to get the latest state. In a lot of use cases however, we just want to find the current state as fast as possible and we might not care so much about the history of the stream. This is where the DIDPublish stream type comes in handy. DIDPublish uses a largest nonce rule to determine which signed commit is canonical. This reduces the need to keep the entire history of events. Instead DIDPublish simply refers to one CID which can include any content that is possible to represent as IPLD.
Fast sync
When syncing a DIDPublish stream we simply query the network for the latest tip given the StreamID. The response can either be a signed commit or an anchor commit. In the first case we simply verify that the commit was signed by a VerificationMethod in the latest version of the controller DID document. In the second case we verify the anchor commit, then verify that the signed commit was signed by a VerificationMethod in the DID document which was valid at the timestamp retrived from the anchor commit. If there is a conflict, i.e. we get multiple tips, then we simply choose the valid tip with the largest nonce in the signed commit.
Any content
Using the DIDPublish stream a user can publish any content that can be represented with a CID. Essentially any content representable as IPLD. Below some examples are listed.
IPFS
IPFS uses IPLD as it's internal data structure, so any file/data on IPFS can be published. In particular the UNIX-fs subsystem of IPFS might be of particular interest here.
Blockchain data
The blockchains of Ethereum, Bitcoin, Zcash, and Filecoin are representable as IPLD and can thus be published using DIDPublish. We could for example publish a reference to a specific block or transaction. For Filecoin specifically it might be interesting to publish information about a particular storage deal.
P2P databases
DIDPublish can also be used to publish the latest tip of existing p2p databases that utilize IPFS. Examples here include Textile threads, Fission WINFS, Peergos, and OrbitDB.
StreamTypes based on DIDPublish
It is also possible to create new StreamTypes that build on top of the DIDPublish primitive. For example it may be interesting to create a stream where the history can be dynamically loaded.
Specification
StreamID code: 0xXX (to be assigned)
Commit Formats
Genesis commit
The genesis commit has to be a dag-cbor IPLD object with the following structure:
type GenesisCommit struct {
controllers [String]
family optional String
tags optional [String]
}
Signed commits
A signed commit has to be a JWS with the following structure:
The three properties in the protected header are required.
kid - the DID URL of the DID which signed the JWS
Has to include the versionId or versionTime query parameter. This is to indicate which version of the DID document was active when the signature was made.
url - the Ceramic url for the stream that is being updated
The format for this would be ceramic://<streamid>
nonce - a nonce to indicate the priority of this commit (bytestring, encoded as base64url)
When comparing two different signed commits, the one with the largest nonce will get priority.
Note that multiple singatures from different DIDs MAY be included in the signatures array.
State Transitions
Applying the Genesis Commit
When the genesis commit is applied a StreamState object is created that looks like this:
{
type: 0xXX,// to be assingedmetadata: {controllers: genesisCommit.controllers,family: genesisCommit.family,tags: genesisCommit.tags},content: null
signature: SignatureStatus.GENESIS,anchorStatus: AnchorStatus.NOT_REQUESTED,log: [newCID(genesisCommit)]}
In addition to this, the following should be verified:
controllers is an array of DID strings
If family is defined it should be a string
If tags is defined it should be an array of strings
Applying a Signed Commit
When a signed commit is applied the StreamState object should be modified as stated below:
state.content=newCID(signedCommit.payload)state.signature=SignatureStatus.SIGNEDstate.anchorStatus=AnchorStatus.NOT_REQUESTED// or AnchorStatus.REQUESTEDstate.log=[newCID(genesisCommit),newCID(signedCommit)]
In addition the following should be validated:
The url of the protected header should be equal to the StreamID of the current stream
The JWS should be valid and signed by the DID(s) in the controllers array
The JWS should include a kid property in it's header which specifies the keyFragment as well as the version-id/versionTime of the public key that was used to sign the commit
Applying an Anchor Commit
When an anchor commit is applied the StreamState object should be modified as stated below:
In addition to this, the following should be verified:
the timestamp from the anchorProof should be between the updated and nextUpdate properties from the didDocumentMetadata of the resolved DID document from the kid(s) that signed the JWS in the previous step
Conflict resolution
This stream type defines a new conflict resolution rule called: largest nonce rule. If there are two conflicting valid tips this rule simply picks the tip which includes the larger nonce in the signed commit. In the edge case where there are two signed commits with the same nonce, the one that was anchored earliest is selected.
Rationale
The DIDPublish stream type only stores the most recent signed commit and one anchor commit on top of that. This makes sync and verification time fast. The signed commit is a JWS which is stored in IPFS using dag-jose, but unlike the TileDocument stream type the JWS contains a url property with the StreamID (as oppsed to an id property for tiles). This makes it possible for the CID in the JWS to point to content directly.
Implementation
No implementation yet.
Security Considerations
DIDPublish requires support for configurable conflict resolution logic in Ceramic. TileDocument and Caip10 Link both use the earlies anchor rule, but in this CIP we introduced the new largest nonce rule. Since we only verify the genesis + signed + anchor record for DIDPublish it means that we can't rotate the owner DID. Instead DIDPublish streams are always tied to a specific DID. By default no history is keep in this stream type, this can be useful if you want your users to be able to delete data. However, if you want to preserve auditability of all events a different stream type should be used.
Right now this is not being prioritized. Over the next year the 3Box Labs team will put focus on building a node that only does event streaming. The idea is that various streamtypes could more easily be built on top of that core primitive.
Simple Summary
DIDPublish is a powerful StreamType which enables a DID to publish any structured content to a global decentralized context.
Abstract
The DIDPublish stream type makes it possible for a DID to publish any structured content which can be represented by a single CID. The stream itself is ephemeral, i.e. the commit log is not persisted, this means that it is fast to sync since there is no history that needs to be verified. The content a DID publishes can be associated with some metadata information (e.g.
family
,tags
) and the relevant DID(s). Any observer that only knows the DID and metadata can resolve the published CID.Motivation
Traditionally Ceramic streams have relied on an append-only data structure where all history is present and conflicts are resolved though the earliest anchor rule. This works great when there is a need for strong verifiability of the history of the log or as a primitive for secure key revocation, but it requires the entire log to be processed in order to get the latest state. In a lot of use cases however, we just want to find the current state as fast as possible and we might not care so much about the history of the stream. This is where the DIDPublish stream type comes in handy. DIDPublish uses a largest nonce rule to determine which signed commit is canonical. This reduces the need to keep the entire history of events. Instead DIDPublish simply refers to one CID which can include any content that is possible to represent as IPLD.
Fast sync
When syncing a DIDPublish stream we simply query the network for the latest tip given the StreamID. The response can either be a signed commit or an anchor commit. In the first case we simply verify that the commit was signed by a VerificationMethod in the latest version of the controller DID document. In the second case we verify the anchor commit, then verify that the signed commit was signed by a VerificationMethod in the DID document which was valid at the timestamp retrived from the anchor commit. If there is a conflict, i.e. we get multiple tips, then we simply choose the valid tip with the largest nonce in the signed commit.
Any content
Using the DIDPublish stream a user can publish any content that can be represented with a CID. Essentially any content representable as IPLD. Below some examples are listed.
IPFS
IPFS uses IPLD as it's internal data structure, so any file/data on IPFS can be published. In particular the UNIX-fs subsystem of IPFS might be of particular interest here.
Blockchain data
The blockchains of Ethereum, Bitcoin, Zcash, and Filecoin are representable as IPLD and can thus be published using DIDPublish. We could for example publish a reference to a specific block or transaction. For Filecoin specifically it might be interesting to publish information about a particular storage deal.
P2P databases
DIDPublish can also be used to publish the latest tip of existing p2p databases that utilize IPFS. Examples here include Textile threads, Fission WINFS, Peergos, and OrbitDB.
StreamTypes based on DIDPublish
It is also possible to create new StreamTypes that build on top of the DIDPublish primitive. For example it may be interesting to create a stream where the history can be dynamically loaded.
Specification
StreamID code:
0xXX
(to be assigned)Commit Formats
Genesis commit
The genesis commit has to be a dag-cbor IPLD object with the following structure:
Signed commits
A signed commit has to be a JWS with the following structure:
The three properties in the protected header are required.
kid
- the DID URL of the DID which signed the JWSHas to include the
versionId
orversionTime
query parameter. This is to indicate which version of the DID document was active when the signature was made.url
- the Ceramic url for the stream that is being updatedThe format for this would be
ceramic://<streamid>
nonce
- a nonce to indicate the priority of this commit (bytestring, encoded asbase64url
)When comparing two different signed commits, the one with the largest nonce will get priority.
Note that multiple singatures from different DIDs MAY be included in the
signatures
array.State Transitions
Applying the Genesis Commit
When the genesis commit is applied a
StreamState
object is created that looks like this:In addition to this, the following should be verified:
controllers
is an array of DID stringsfamily
is defined it should be a stringtags
is defined it should be an array of stringsApplying a Signed Commit
When a signed commit is applied the
StreamState
object should be modified as stated below:In addition the following should be validated:
url
of the protected header should be equal to the StreamID of the current streamcontrollers
arraykid
property in it's header which specifies thekeyFragment
as well as theversion-id
/versionTime
of the public key that was used to sign the commitApplying an Anchor Commit
When an anchor commit is applied the
StreamState
object should be modified as stated below:In addition to this, the following should be verified:
updated
andnextUpdate
properties from the didDocumentMetadata of the resolved DID document from thekid
(s) that signed the JWS in the previous stepConflict resolution
This stream type defines a new conflict resolution rule called: largest nonce rule. If there are two conflicting valid tips this rule simply picks the tip which includes the larger nonce in the signed commit. In the edge case where there are two signed commits with the same nonce, the one that was anchored earliest is selected.
Rationale
The DIDPublish stream type only stores the most recent signed commit and one anchor commit on top of that. This makes sync and verification time fast. The signed commit is a JWS which is stored in IPFS using dag-jose, but unlike the TileDocument stream type the JWS contains a
url
property with the StreamID (as oppsed to anid
property for tiles). This makes it possible for the CID in the JWS to point to content directly.Implementation
No implementation yet.
Security Considerations
DIDPublish requires support for configurable conflict resolution logic in Ceramic. TileDocument and Caip10 Link both use the earlies anchor rule, but in this CIP we introduced the new largest nonce rule. Since we only verify the genesis + signed + anchor record for DIDPublish it means that we can't rotate the owner DID. Instead DIDPublish streams are always tied to a specific DID. By default no history is keep in this stream type, this can be useful if you want your users to be able to delete data. However, if you want to preserve auditability of all events a different stream type should be used.
Copyright
Copyright and related rights waived via CC0.
The text was updated successfully, but these errors were encountered: