Repository navigation
Expand file tree
/
Copy pathcore.html
More file actions
256 lines (226 loc) · 16.4 KB
/
Copy pathcore.html
File metadata and controls
256 lines (226 loc) · 16.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
<h2>Core Characteristics</h2>
<section class="normative">
<h3>Namestring</h3>
<p>The namestring that identifies this DID method SHALL be: <code>peer</code></p>
<p>A DID that uses this method MUST begin with the following prefix: <code>did:peer:</code>.
Per the DID specification, this string MUST be in lowercase. The remainder of the DID, after the prefix,
is the <a href="#namespace-specific-identifier-nsi">namespace specific identifier described below</a>.
</p>
<p class="note">Early feedback on this method suggested that we embed it beneath the namespace of a particular
blockchain, as in <code>did:sov:peer</code> or <code>did:v1:nym</code>.
However, this DID method is not captive to any particular blockchain, does not take its resolution rules
from a parent method, and does not require anchoring or reference to a blockchain to be valid.
Furthermore, any direct or indirect anchoring of a peer DID to a specific blockchain is driven by
circumstance and changeable at any time. For example, a peer DID could specify that it is using
a dead drop on blockchain 1, then change to blockchain 2, then change to blockchains 3 and 4 at
the same time. Therefore, "peer" belongs at the top of the DID namespace. How this method may be
used with various blockchains is discussed <a href="#grafting">later</a>.
</p>
</section>
<section class="normative">
<h3>Target System(s)</h3>
<p>This DID method applies to any identity management implementation that meets the following two
requirements:</p>
<ul>
<li><em>Generation Algorithm</em> — The DIDs are created using the <a href="#namespace-specific-identifier-nsi">
algorithm described below</a>, endowing them with properties vital to trust between peers that is not
dependent on a central source of truth.
</li>
<li>
<em>Protocol</em> — The metadata for DIDs (what would be stored in an on-chain DID doc in other methods)
is communicated and maintained as described in the <a href="#protocols">Protocols</a> section.
</li>
</ul>
</section>
<section class="normative">
<h3>Namespace Specific Identifier (NSI)</h3>
<p>The peer DID scheme is defined by the following ABNF (see [[RFC5234]] for syntax):</p>
<pre class="example" class="ABNF" title="ABNF for peer DIDs">
peer-did = "did:peer:" numalgo encalgo "-" numbasis
numalgo = "1"
encalgo = "1"
numbasis = 64*hex
</pre>
<p>The meaning of <code>hex</code> is the traditional one for hexadecimal digits.</p>
<p>Peer DIDs use an underlying number with high entropy, called the <dfn>numeric basis</dfn>, as the source of their
uniqueness. This version of the spec requires a 256-bit numeric basis generated from a hash
of the initial content of a DID doc. The <a href="#namestring-generation-method">next section</a> has details.
The requirement about size and origin of numeric basis is represented in the DID value with <code>numalgo
</code> == <code>1</code>. Subsequent versions of the spec may describe additional methods of generating the
numeric basis; each new method is associated with the next unused <code>numalgo</code> digit as it is defined.
Only a single digit is used, giving a maximum of 16 possible evolutions.
</p>
<p>This <em>numeric basis</em> is transformed to text using an encoding algorithm. This version of the spec encodes
using 64 hexadecimal digits, and represents that choice in the DID value with <code>encalgo</code> == <code>1
</code>. Subsequent versions of the spec may describe additional encodings; each new encoding is associated with
the next unused <code>encalgo</code> digit as it is defined. Only a single digit is used, giving a maximum of 16
possible evolutions.
</p>
<p class="note">Implementations of <code>encalgo</code> == <code>1</code> SHOULD render the numeric basis in lower
case. However, the <code>numbasis</code> portion of peer DIDs MUST be compared according to
whatever case-sensitivity is implied by the encoding algorithm they use. Hex is not case-sensitive,
so two peer DID strings using <code>encalgo</code> == <code>1</code>, that differ only in
the <code>numbasis</code> portion, are equivalent. If a future version of the spec
defines <code>encalgo</code> == <code>2</code> to be something case-sensitive, such as <a target="_blank"
href="https://en.bitcoin.it/wiki/Base58Check_encoding">base58</a> or base64 [[RFC4648]], comparison of
the <code>numbasis</code> values for peer DIDs with <code>encalgo</code> == <code>2</code> will be
case-sensitive. Therefore, routines that handle peer DIDs MUST NOT normalize or ignore case unless they
take into account the encoding algorithm of each individual peer DID.</p>
</section>
<section class="normative">
<h3>Namestring Generation Method</h3>
<p>The unique <em>numeric basis</em> underlying a Peer DID MUST be generated as follows:</p>
<ul>
<li>Create a <dfn>genesis version</dfn> of JSON text of the DID doc for the DID. The genesis version MUST
include enough keys and <a target="#authorization">authorization</a> that the genesis version of the doc
can be signed, to prevent man-in-the-middle attacks during initial DID exchange. It SHOULD also include
enough state that subsequent evolutions to the doc are authorized; otherwise, the doc is a dead end.
It MUST NOT include the DID itself (either the root <code>id</code> property or its value). This
lets the doc be created without knowing the DID's value in advance.
Suppressing the DID value creates a <dfn>stored variant</dfn> of peer DID doc data,
as opposed to the <dfn>resolved variant</dfn> that would have an actual DID value in the root <code>id
</code> property. (In either the stored or resolved variant of the doc, anywhere else that the DID value
would appear, it should appear as a relative reference rather than an absolute value. For example, each
<code>controller</code> property of a <a href="#publickey">publicKey that is owned by this DID would say
<code>"controller": "#id"</code></a>.)
</li>
<li>Calculate the SHA256 [[!RFC4634]] hash of the bytes of the <a>stored variant</a> of the <a>genesis
version</a> of the DID doc, and make this value the new DID's <a>numeric basis</a>.
</li>
</ul>
<p>By basing the numeric value of the DID on the <a>genesis version</a> of the DID doc, the DID can begin its
lifecycle with any number of keys and endpoints, and when the doc is signed or auth-encrypted by one
of the keys, the recipient can know it has not been modified since creation. This guarantees the
initial integrity of the DID's chain of custody.</p>
<p>By hashing the stored variant, we avoid the circular problem of including the DID in the data that's being
hashed. This means that a peer DID doc must be resolved by converting a <a>stored variant</a> of DID doc
data into a <a>resolved variant</a> by inserting the value of the DID being resolved, during resolution.</p>
</section>
<section class="informative">
<h3>Recognizing and handling peer DIDs</h3>
<p>A valid <code>peer</code> DID might be:</p>
<pre class="example nohighlight" title="A typical peer DID" id="typical-did">
did:peer:11-479cbc07c3f991725836a3aa2a581ca2029198aa420b9d99bc0e131d9f3e2cbe
</pre>
<p>Peer DIDs consist entirely of printable ASCII characters and are exactly 76 characters long. They have no
whitespace, and the only punctuation they use are the characters <code>:</code> and <code>-</code>. When
rendering in columns with a constrained width, they could be hyphenated one or more times as needed, at any
position after offset 14 (the 2nd hex character); the hyphens would not be confused with meaningful delimiters,
and the final character of the DID would be easy to find. They could also be rendered in a short form with the
middle of the long hex section elided, if it is not necessary to compare them with precision: <code>
did:peer:11-479cbc0...f3e2cbe</code>. The ellipsis should not obscure the prefix or the initial or final few
characters of the hex, to preserve enough info for casual distinction. This might be a useful rendering in log
files, for example.
</p>
<p>A convenient regex to match <code>peer</code> DIDs is:</p>
<pre class="example nohighlight" title="Matching regex" id="matching-regex">
^did:peer:(1)(1)-([a-fA-F0-9]{64})$
</pre>
<p>A match against this regex places <code>numalgo</code> (the algorithm for choosing a numeric basis) in
capture group 1, <code>encalgo</code> (the algorithm for encoding) in capture group 2, and the numeric
basis itself, in properly encoded form, in capture group 3.</p>
<p>Javascript to sort two peer DIDs or test them for equality might be:</p>
<pre class="example" title="JavaScript to compare two peer DIDs" id="js-compare-func">
function comparePeerDIDs(didA, didB) {
a = didA.substring(0,12);
b = didB.substring(0,12);
// Compare the prefix case-sensitively.
n = (a < b) ? -1 : (a > b ? 1 : 0);
if (n == 0) {
// Don't use .localeCompare() or .toLocaleLowerCase();
// we want raw ASCII comparison. Just normalize to
// lower case before comparing.
a = didA.substring(12).toLowerCase();
b = didB.substring(12).toLowerCase();
n = (a < b) ? -1 : (a > b ? 1 : 0);
}
return n;
}
</pre>
<p>See also the <a href="compare.py">Python equivalent</a>. Note that more robust and efficient versons of this code
could be written; this merely illustrates a correct algorithm.</p>
<p>Examples of a DID doc for this method are explored in greater detail <a href="#diddocs">below</a>.</p>
</section>
<section class="normative">
<h3>Reserved Values</h3>
<p class="note">This section is still being debated and may be removed. It got merged as a matter of git
merge convenience, a bit before it was mature.</p>
<p>The sixteen peer DID values that have 64 identical hex digits (all 0s, all 1s, all 2s, etc) are reserved for
testing, debugging, and other meta purposes. They cannot be resolved in a normal and valid way, since we haven't
done the massive amount of computation that would tell us what DID Doc content would produce the associated numeric
bases. Instead, they MAY trigger the special handling described below, beginning in implementations that offer
<a>Level 2a</a> or <a>Level 2b</a> support</a> for this spec. Implementations SHOULD NOT define semantics that
contradict these.
</p>
<dl>
<dt>The <dfn>bitbucket DID</dfn> (did:peer:11-0000...0000)</dt>
<dd><p>This DID is somewhat like <code>/dev/null</code>; it is a predefined identity that acts as a sink, accepting
incoming messages but refusing to respond. Messages routed to this DID should be swallowed/deleted without an error.
Thus <a href="https://github.com/hyperledger/aries-rfcs/tree/master/concepts/0003-protocols#types-of-protocols"
target="aries">1-step notification protocols</a> will always succeed when this DID is the target, and
<a href="https://github.com/hyperledger/aries-rfcs/tree/master/concepts/0003-protocols#types-of-protocols"
target="aries">2-step request-response protocols</a> will always timeout waiting for a response. Resolving
this DID should return a DID doc containing at least <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0114-predefined-identities#key-1-ed25519">
key-1</a>, <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0114-predefined-identities#key-3-secp256k1">
key-3</a>, and <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0114-predefined-identities#key-5-4096-bit-rsa">
key-5</a> from the <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0114-predefined-identities">Aries
Predefined Identities RFC (0114)</a>. This allows zero-setup interactions from various crypto foundations.
[TODO: Do we need other key types?]</p>
</dd>
<dt>The <dfn>anywise self DID</dfn> (did:peer:11-1111...1111)</dt>
<dd><p>
This DID is somewhat analogous to the use of "loopback" or "localhost" in TCP/IP; it means an anywise or
public "self" for whatever entity sees it in a DIDComm stack. An agent that emits a message for this DID
should see the message come back to itself without passing through any mediators or relays, with no trust
degradation in its <a href="https://github.com/hyperledger/aries-rfcs/blob/master/concepts/0029-message-trust-contexts/README.md"
target="aries">message trust context</a> and with minimal latency. Protocols that depend on cooperation from
another party should always get maxiumum cooperation from this one; for example, an invitation to connect
that arrives at this DID should always be accepted <code>:-)</code> — though negotiation of a new
pairwise DID should ensue. Attempts to resolve this DID should return a DID Doc that contains the same set
of keys as the <a>bitbucket DID</a>. This makes it a flexible, low-risk identity to connect with or talk to
in a way that short-circuits many layers of communication complexity.
</p>
<dt>The <dfn>pairwise self DID</dfn> (did:peer:11-2222...2222)</dt>
<dd><p>
This DID is like the <a>anywise self DID</a> (including a DID doc the resolves to identical content except
for the DID value). It differs in that it is assumed to already be connected in a pairwise relationship, and
to be private. Thus, interacting with this DID is a great way
to exercise any pairwise protocol without going through <a target="aries"
href="https://github.com/hyperledger/aries-rfcs/tree/master/features/0033-did-exchange">DID Exchange</a>.
</p>
</dd>
<dt>The <dfn>n3 DID</dfn> (did:peer:11-3333...3333) and the <dfn>n4 DID</dfn> (did:peer:11-4444...4444)</dt>
<dd><p>
These two DID are like the <a>pairwise self DID</a> (including a DID doc the resolves to identical content except
for the DID value). They differ in that they are assumed to already be connected to the current context and
to one another in a 3-wise relationship. That is:
</p>
<figure id="n3-n4">
<img src="n3-n4.png"/>
<figcaption>n3 and n4 are pre-connected to self and to each other</figcaption>
</figure>
</dd>
<dt>did:peer:11-5555...5555 to did:peer:11-bbbb...bbbb</dt>
<dd>No special semantics are defined for these, in the current version of the spec. Implementations or
particular software packages may define them (or not) according to preference.</dd>
<dt>The <dfn>corrupted DID</dfn> (did:peer:11:cccc...cccc)</dt>
<dd>This DID should resolve to the string <code>invalid DID doc</code>, triggering JSON deserialization
errors.</dd>
<dt>The <dfn>disconnected DID</dfn> (did:peer:11-dddd...ddddd)</dt>
<dd>This is a pairwise DID that does NOT have an active connection (e.g., that someone else knows about but
that is unrecognized in the current context, or that has sent an <code>abandon_connection/announce</code>
message).
</dd>
<dt>The <dfn>empty DID</dfn> (did:peer:11:eeee...eeee)</dt>
<dd>This DID should resolve to a DID doc that is well formed JSON-LD but that contains no keys, no service
endpoints, and empty containers for other sections. Attempting to interact with such a DID should trigger
DID Doc validation errors but not raw JSON deserialization errors.</dd>
<dt>The <dfn>never resolvable DID</dfn> (did:peer:11:ffff...ffff)</dt>
<dd>This DID is reserved for triggering resolution errors. [[TODO: Markus, what is the equivalent of
"not found" as a DID resolution error?]]</dd>
</dl>
</section>