Closed TelegramSam closed 4 years ago
I'm just leaving a comment so I'm subscribed to this issue. (Clicking "subscribe" in github hasn't been working for me.)
Can someone with more experience using did:peer
describe in concrete terms what the KERI inception event like thing is that happens when a did:peer
is first created?
I have a feeling understanding that is the key to this issue.
In sidetree the initial-state
is an unwitnessed inception event, which is acceptable only when no witnessed inception event is observable on the ledger.
In sidetree the
initial-state
is an unwitnessed inception event, which is acceptable only when no witnessed inception event is observable on the ledger.
I like how you put this, that's a great way to word it!
@SmithSamuelM ^ We have a couple conversations floating around related to this, which I would love your thoughts on.
I'll answer Orie's question for peer DIDs specifically. Then I'll make some observations about principles of self-certifying identifiers that @smithsamuelm has been talking about. Sam's principles are embodied in did:peer, but not as purely as the way Sam advocates (peer DIDs mix in a couple other concerns). Sam has done a beautiful job of abstracting some ideas further than peer DID does.
A peer DID's state is just a bunch of signed deltas to a DID doc. The first delta is between null state and the genesis state of the DID doc. The genesis state of the DID doc must include one key that is special -- the inception key. This is the key that authorizes the DID to be shared, either with a blockchain or with a peer., which means that the inception key must sign the first delta. The value of the DID itself (its "numeric basis") has to be provably derived from the genesis state, including the inception key. If someone tries to register the DID (either with a peer or a blockchain) using any key other than the inception key, they are doing something invalid, no matter what other privileges that key has. Requiring that only the creator's inception key can authorize the initial state prevents various attacks. (There's more to this story, including how registrations for non-genesis state can happen, but let's set that aside for now.)
Now, peer DIDs are exchanged between peers using a message. This message could be part of the Aries Connection or DID Exchange protocol, or it could be just the payload of an HTTP POST that has nothing to do with DIDComm. The peer DID spec contemplates both. Either way, the message must represent the state of the other party byte-for-byte, not just a semantic equivalence of it. That's because what's signed is the byte-for-byte genesis state, and it's this signature that's tested to make sure the peer DID has the self-certifying property (inception key authorizing). We are not doing any JSON normalization in the style of LD-Signatures.
If I understand the proposal correctly, we want to stop attaching genesis DID docs to messages, and instead simply tell the other party "here's my initial state" using the initial-state
matrix parameter. If the state in question is the initial state of a peer DID, then what we would be encoding in the matrix parameter is a binary representation of the full text of a peer's DID document. As long as initial-state
is capable of holding such a thing, the idea is probably viable, though we could easily be talking about 1k-2k of data. What it cannot be is a normalized version of a DID doc, or just a few values for a DID doc that's derivable from those values like did:key; these would invalidate our signature test.
Sam Smith's ideas about KERI and self-certification basically genericize peer DIDs. Where peer DIDs assumes that all changes are authorized and propagated and witnessed by peer agents, KERI assumes a similar concept, but allows the participants to be anything the parties like -- peer agents, blockchains, or other systems of record. They are thus blockchain agnostic and portable.
KERI also simplifies some stuff out of peer DIDs. A peer DID allows initial state to be complex; KERI requires it to be simple. This makes a KERI impl of peer DID concepts far closer to did:key; the amount of material you have to transfer might be much less than the 1k-2k for peer DIDs, and closer to 100-200 bytes.
I am going to bring the peer DID method to the DIF's WG that's looking at KERI, and ask that it be rolled in to the work agenda. I think the result will be a reframing of peer DIDs, explaining them as a special case of KERI.
@dhh1128 @OR13 Daniel’s comments don’t a good job of summarizing the similarities of KERI and peer dids. From a design perspective KERI is meant to be the minimalist set of key events primitives upon which any DKMI can be built using best practices. Thus one could refactor peer dids to use KERI plus some extensions
@dhh1128 thanks this is super helpful. I've also be advocating for considering sidetree as a case of KERI as well, with the ledger as the witness.
The genesis state of the DID doc must include one key that is special -- the inception key. This is the key that authorizes the DID to be shared, either with a blockchain or with a peer., which means that the inception key must sign the first delta.
So in a world where the inception key were a did:key
.. you could start with a did:key
, and end with a peer did. I assume that a key rotation of the inception key is possible, you would no longer need to retain the did:key
(its not revocable, so you don't want to use it long term anyway).
The problem with did:key
is that it does not have a services section... which is necessary to support the initial invitation flows used by didcomm IIRC.
If we found a way to use initial-state
or something similar to augment a did key, you would have everything you need to covert that identifier to a peer did, and it would be globally resolvable.
I think the flow would be as follows:
You could skip the did:key
part, but I'd like to see it there because I think it is likely to help with adoption of dids generally...
initial-state
is feeling not generic enough... what we are really wanting to do is pass some attributes which are signed by a did, along with that did as matrix parameters... a method resolver that supports these matrix parameters will use them to augment the resolution process.
In the case of sidetree, it tries to resolve the did, and then uses the initial-state
to construct the did and did document if none exists... this allows us to transmit the inception event as a did uri.
In the case of did key, it might add a service endoint to a did document, if it were signed properly... this would allow for did key to be used as an ephemeral globally resolvable did, with the serviceEndpoint mechanism as a way to upgrade to a longer term did... and with key agreement section, you could make sure all communication was encrypted from the start.
In the case of did peer, if we had an ephemeral globally resolvable did, like the example above, we could reduce the attachment of the did document to the use of a did uri... because the peer did would now be resolvable globally.
This would simplify the didcomm protocol, by removing the need to handle special cases for did:peer
.
@OR13 the way you pose that, it does sound like initial-values
would be the more generic term/concept to go with, vs mentioning 'state'.
@OR13 : I followed most of what you said, and it made sense to me. But then your comment near the end threw me for a loop. I think I'm missing something, so I'm hoping you'll elaborate. You said:
"...because the peer did would now be resolvable globally."
The whole point of peer DIDs is that they should NOT be resolvable globally. That what "peer" in the name means. They're only supposed to be resolvable by each other. So I'm a bit puzzled as to why making them resolvable globally is a good thing.
Having did:peer
not be globally resolvable is IMO, a defect and not a feature.... Since we know that the inception event for a did:peer
is a function of a publicKey
and a serviceEndpoint
... we could use initial-state
to make the did resolvable, it would only be resolvable by parties which held a did uri akin to the sidetree inception event:
did:peer:<id>;initial-state=<signed_first_delta>
... now your did peer is resolvable by anyone who has this... but its still private... as long as you share this over a secure channel you are in the same place we are today with passing a key and service endpoint....
Same thing could apply to did:key
and if did:key
supported initial-state
or something similar: https://github.com/digitalbazaar/did-method-key/issues/5
Having did:peer not be globally resolvable is IMO, a defect and not a feature....
I can't NOT comment on a statement that provocative. :-) However, the next paragraph can be ignored for the purpose of this thread, so if you want to skip the controversy and get to what matters, jump past this next part...
Alice is the one who decides whether resolvability of her identifier is a bug or a feature. If she creates an identifier to use only with Bob, the rest of the world can have whatever opinion it likes about whether Alice's DID with Bob should resolvable for them -- but only Alice's opinion matters. It's her DID, after all. Having a DID like this be publicly resolvable is a little bit like two lovers saying, "Hey, let's invent pet names for each other that only we know. But then let's go and list them in a public registry so the whole world can know what they are. You know, 'cause names are meant to be public." I think that's silly -- not just for privacy reasons, but because it's totally unnecessary to construct systems that support this. Nobody's asking for it. Of course we want resolvability for DIDs that are intended to be public. But peer DIDs aren't intended to be public, by definition. Where I really think we have a disconnect is on whether most DIDs should be public or private, and on whether we believe discoverability, routability, and resolvability are functional synonyms. I believe the vast majority of relationships that will ever exist are non-public ones -- not because I'm hung up on privacy, but because I think it's just reality that the world doesn't care about them and shouldn't be burdened with them. Anyway, we should set aside some time to talk about this face to face; we won't resolve this in an isolated github issue.
Back to the main topic: you said "as long as you share this over a secure channel you are in the same place we are today with passing a key and service endpoint...." I can agree with this, which is why I think this mechanism would work. I don't actually think it de-complicates DIDComm at all, because the mechanism for attaching content is generic to all DIDComm; its cost in the connection or DID Exchange protocol is essentially zero. But I don't mind going this direction for other reasons (like de-complicating the exchange of DIDs over non-DIDComm channels).
What it cannot be is a normalized version of a DID doc, or just a few values for a DID doc that's derivable from those values like did:key; these would invalidate our signature test.
Can you explain why this is true a bit more? An example would be really helpful I think. From what I’ve read in KERI and sidetree making ‘initial-value‘ normalized wouldn’t change anything so I must be missing the core point here.
@kdenhartog I had the same question when reading that, because initial-values
doesn't care, and you should feel free to construct your DID Method's initial values data in whatever way securely maps those values to the DID they are attached to.
I believe the vast majority of relationships that will ever exist are non-public ones.
I actually agree that the average user's number of private DIDs will outnumber their public ones by a ratio of hundreds or thousands to one, but here's where I differ: the vast majority of data traffic/volume will occur via the 1 or 2 public DIDs a user has. This is because those 1 or 2 public DIDs will be the ones used to represent a user's public persona, which spans across social media, professional networks, and other intended-public forums. I believe intended-public communications from public persona DIDs will dwarf all other types of DID communications by orders of magnitude, as evidenced by the volume of intended-public traffic that currently runs across apps like Twitter, LinkedIn, Facebook, Yelp, Pinterest, Stack Overflow, Medium, YouTube, etc.
@csuwildcat : I'll reply to the bulk-of-communications-being-public issue on the DIDComm channel on slack, since it's a tangent to this github issue.
What it cannot be is a normalized version of a DID doc, or just a few values for a DID doc that's derivable from those values like did:key; these would invalidate our signature test.
Can you explain why this is true a bit more? An example would be really helpful I think. From what I’ve read in KERI and sidetree making ‘initial-value‘ normalized wouldn’t change anything so I must be missing the core point here.
This has to do with signatures. JSON is hard to canonicalize. Forcing the representation to be bytes makes it possible to sign and validate.
Alice is the one who decides whether resolvability of her identifier is a bug or a feature.
I think we are struggling with the meaning of globally resolvable
. I think Alice should be the one who decides as described by Daniel. Perhaps the term we are looking for is something like globally usable
or globally distributable
.
I believe even did:ethr
could benefit from initial-state
. By doing so, we could add the key agreement key and default service endpoint to the initial DID Doc and bypass the Ethereum transaction problem. If we need to update these values at a later point we would use our ERC1056 smart contract for this. Anyways, supporting initial-state
would increase privacy (by avoiding potential PII on the Blockchain) which is why I sympathise with this proposal.
@OR13 What prevents me to have different initial-state
with other peers in case I decide to reuse my did:ethr
with other connections? Would this be a non-issue (except correlation of course)?
There were more comments related to this on: https://github.com/w3c-ccg/did-method-key/issues/5
I think if this is generalized properly, it will allow privacy features for did methods that rely on ledgers, and usability features for methods like did:peer
and did:key
...
I think its likely to be up to the method implementer what to support, so while the mechanism might be generic, the method implementer would still be responsible for deciding if you can add a phone number to did document using matrix parameters.
@OR13 What prevents me to have different
initial-state
with other peers in case I decide to reuse mydid:ethr
with other connections? Would this be a non-issue (except correlation of course)?
@awoie To answer this directly... I think its a non-issue / feature, but you can certainly combine this approach with did:peer
or some HD-Wallet scheme to get better privacy features.... you could also choose to embed different key agreement keys for different parties.
For example, you might inject controller information that provides for correlation, such that the ledger does not have the correlation details but the did uris do.
@dhh1128 when you say normalize do you mean the same thing as canonicalize or something different? As I understand sidetree today, the base64url encoding of the did doc that's passed with the initial value parameter would satisfy this requirement because it's a method of canonicalizing.
What I understood from the comment was that normalization (I'm assuming it means the same as canonicalization) would mess things up.
What it cannot be is a normalized version of a DID doc
This is the part that through me off. In my mind it MUST be a normalized (canonicalized) version of the DID doc.
With that in mind, I think the tricky part would be keeping the b64url form so that it can remain self certifying later. However that's more an implementation detail that doesn't prevent things from moving forward afaik.
Yes, I mean "canonicalized" when I said "normalized."
The peer DID method requires peers to receive the bytes exactly as the other peers create them, and imposes no canonicalization requirement. Thus, we can't send DID docs unless we transmit them exactly as the other part sent them.
Discussed at length in the 2020-March-09 WG Call, with the following summary:
initial-state
to convey the necessary items for the Peer DID spec, either as a matrix param or as a query param (in the event that matrix params don't make it into the spec)did:key
with endpoint information passed in initial-state
, or did:peer
with the same, to accomplish ephemeral use cases.did_do
c attributes in the request and response messages in the did exchange protocol.Ended up here looking for an answer to: *how can I create an OOB invitation without incurring the costs of creating a public DID?".
For reference:
service
array from didcomm v1, hence no way to specify an explicit invitationfrom
be a valid DID.#generic-did-syntax
section which is today just #did-syntax
.Problem 1: the DIDComm JWM profile mandates that from
be a valid DID that satisfies the did syntax... which prohibits us the use of initial-state
or any other parameter or fragment.
But let's assume that we can put initial-state
in from
....
The only feasible way I see this happening is - as described in this thread - put a did:key
with initial-state
and then immediately rotate or "upgrade" to a did:peer
using from_prior
.
Ok. Now I look up the sparse specification for the did:key
method and see no generic algorithm to "create" a did:key
doc from any key type... keeping in mind we need to keep encryption keys separate from signing keys as best practice...
Problem 2: the did:key
method is under-specified. Eg. it's not clear to me how, according to the spec, one can inflate a did doc from a P-256 key?
Of course, problem 2 goes away if I just use a did:peer
+ initial-state
.
https://github.com/w3c-ccg/did-method-key/issues/16 https://github.com/w3c-ccg/did-method-key/issues/17
In order to get a JWK from a did key, you only need to know the DID... and be clever enough to convert multicodec to JWK...
I personally prefer the use of multicodec to what KERI is doing reinventing it slowly with base64url and a custom table mapping....
The next version of did peer if based on KERI, will be capable of doing the same thing however, they just won't be able to use off the shelf libraries like https://github.com/multiformats/js-multicodec/issues/64 ...
Discussed on today's call:
initial-state
was excluded from did-coresigned-ietf-json-patch
)from
and from_prior
to be DID URLs (not just DIDs) and prohibit fragmentsfrom - OPTIONAL. Sender identifier. The from attribute MUST be a string that is a valid DID which identifies the sender of the message. The from field MUST be included if authentication of the DIDComm message is needed. See the message authentication section for additional details.
If a DID doc has multiple keyAgreement keys, how to specify which one? Requires a DID URL. from
is at the inner message layer, not at the outer encryption layer.
Close in WG Meeting 2020-11-02
Per discussion on Slack, it has been suggested that we leverage the
initial-state
matrix parameter to represent service block info when unattached to a DID. This is common both in the invitation stage of exchanging DIDs and with ephemeral challenges, where endpoint, encryption keys, and routing keys are passed.Each DID method can define how
initial-state
values apply to the method.did:peer
could use this, and we might also work this intodid:key
to attach the additional needed information. As the method defines use, we can design this to be concise.Thoughts:
initial-state
feels young, even to the point of renaming what the name will be. Matrix parameters are also under active discussion. Using the same approach may provide external pain as we adapt to changing external decisions.