CIP-7: CAIP-10 Link
Author | Joel Thorstensson, Michael Sena |
---|---|
Discussions-To | https://github.com/ceramicnetwork/CIP/issues/15 |
Status | Final |
Category | RFC |
Created | 2020-07-24 |
Requires | 5 |
Table of Contents
Simple Summary
This CIP describes the CAIP-10 Link stream type which is used to create a public link between a blockchain account (formatted as a CAIP-10 accountId) and a DID. This enables the owner of an account to associate it with a DID.
Abstract
The CAIP-10 Link stream type enables the linking of a blockchain account to a DID. Blockchain accounts are represented using CAIP-10 accountIds, which is a cross-chain standard for referencing blockchain accounts. The stream type allows anyone with knowledge of a particular CAIP-10 accountId to look up which DID it is associated with using the Ceramic network. To make such a lookup, anyone can simply recreate the genesis event, which only contains the CAIP-10 accountId as unique data, to get the streamId of the particular stream and then look it up in the network.
Motivation
While it’s always possible to associate a blockchain account with some external identifier (such as a DID) by submitting a transaction on-chain, doing so can be expensive due to transaction costs and likely needs to be done in a single registry so lookups can occur. Ceramic provides a better infrastructure for making these public associations.
In many cases, blockchain accounts are just simple cryptographic key pairs and can create an association with a DID only using a signature. The CAIP-10 Link stream type provides this with the addition of strict ordering, which allows an account to be securely relinked to a different DID at a later point in time.
For smart contract based accounts, the association can happen in different ways depending on the implementation of the contract. At times this can happen on-chain or off-chain. A particular example is ERC1271 which is a standard for contract based “signatures”. CAIP-10 Link can be extended to support any number of these use cases.
Specification
Below the event formats and state transitions of the CAIP-10 Link stream type are specified. Together they should include all information needed to implement this stream type in Ceramic.
StreamID code: 0x01
event formats
The InitEvent is stored in IPLD using the dag-cbor codec. It has the following required properties:
owners
- one blockchain account encoded as CAIP-10
No other properties are allowed to be defined.
DataEvents of a CAIP-10 Link stream are also encoded using dag-cbor. Other than that they conform to the standard event format. The content of the data
property should be a proof as returned by the 3id-blockchain-utils library. This library has a general structure for creating and verifying “link proofs” for any blockchain.
Note that because the signature in included in the proof object, the rest of the DataEvent is not authenticated. This could pose a potential problem, but can be mitigated if the proof timestamp is verified as described below.
State transitions
Below the state transition logic for the three different supported events is described.
Applying the InitEvent
When the InitEvent is applied a StreamState
object is created that looks like this:
{
metadata: {
owners: initEvent.owners
},
content: null,
signature: SignatureStatus.GENESIS,
anchorStatus: AnchorStatus.NOT_REQUESTED,
log: [new CID(initEvent)]
}
In addition to this, the following should be verified:
owners
is a CAIP-10 AccountId
Applying a DataEvent
When a DataEvent is applied the StreamState
object should be modified in the following way:
state.next = {
content: verifiedProof.DID
}
state.signature = SignatureStatus.SIGNED
state.anchorStatus = AnchorStatus.NOT_REQUESTED
state.log.push(new CID(dataEvent))
Where verifiedProof.DID
is the DID contained in the proof object from initEvent.data
. In addition it needs to be verified that this proof was signed by the CAIP-10 accountId that is represented in owners
. If the variable state.anchorProof
is present the implementation MUST also verify that proof.timestamp
is larger than state.anchorProof.blockTimestamp
.
For an example of how this verification can take place have a look in the 3id-blockchain-utils library.
Applying an TimeEvent
When an TimeEvent is applied the StreamState
object should be modified in the following way:
state.anchorStatus = AnchorStatus.ANCHORED
state.anchorProof = timeEvent.proof
state.content = state.next.content
state.metadata = Object.assign(state.metadata, state.next.metadata)
delete state.next
state.log.push(new CID(timeEvent))
No additional validation needs to happen at this point in the state transition function.
Examples
When resolving an caip10-link stream that is linked to a 3ID, the result looks like the examples below.
Ethereum account-link
{
metadata: {
owners: ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb@eip155:1"]
},
content: "did:3:bafyreiecedg6ipyvwdwycdjiakhj5hiuuutxlvywtkvckwvsnu6pjbwxae"
}
Polkadot account-link
{
metadata: {
owners: ["5hmuyxw9xdgbpptgypokw4thfyoe3ryenebr381z9iaegmfy@polkadot:b0a8d493285c2df73290dfb7e61f870f"],
},
content: "did:3:bafyreiecedg6ipyvwdwycdjiakhj5hiuuutxlvywtkvckwvsnu6pjbwxae"
}
Cosmos account-link
{
metadata: {
owners: ["cosmos1t2uflqwqe0fsj0shcfkrvpukewcw40yjj6hdc0@cosmos:cosmoshub-3"],
},
content: "did:3:bafyreiecedg6ipyvwdwycdjiakhj5hiuuutxlvywtkvckwvsnu6pjbwxae"
}
Bitcoin account-link
{
metadata: {
owners: ["128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6@bip122:000000000019d6689c085ae165831e93"],
},
content: "did:3:bafyreiecedg6ipyvwdwycdjiakhj5hiuuutxlvywtkvckwvsnu6pjbwxae"
}
Rationale
The CAIP-10 Link allows blockchain accounts to be linked to DIDs by signing a simple message. The signature is only over this message itself and not the entire DataEvent. This provides less strong security guarantees and instead opts for user experience, since the user will be able to read the message and have a better understanding of what is going on. The use of CAIP-10 future proofs this stream type by allowing any blockchain account to be linked to a DID by extending the implementation of the stream type with additional verification methods.
Implementation
A reference implementation of the CAIP-10 Link stream type is provided in js-ceramic. (see the stream-caip10-link
package).
Security Considerations
Since the entire payload of the DataEvent is not included in the payload of the signature used for this stream type, care needs to be taken so that the stream can not be attacked by a replay attack. For example, lets imagine that account 0xabc123@eip155:1
is first linked to did:3:A
, then after that is updated to link to did:3:B
. A malicious attacker could now take the proof from the first linkage and update the stream with a new DataEvent which points to the latest update but contains the first proof link object. The account would now be linked to did:3:A
once again which is not desirable.
To circumvent this, each proof contains a timestamp
which is the unix timestamp of when the message was signed. If we simply verify that this timestamp is larger than the timestamp of the most recent TimeEvent we can be sure that this is not a reply attack. Further attacks could possibly include modification of the refs
property, but this could in the worst case just make syncing of the stream slower.
Copyright
Copyright and related rights waived via CC0.
Citation
Please cite this document as:
Joel Thorstensson, Michael Sena, "CIP-7: CAIP-10 Link," Ceramic Improvement Proposals, no. 7, July 2020. [Online serial]. Available: https://github.com/ceramicnetwork/CIPs/blob/main/CIPs/cip-7.md