Skip to content

Commit

Permalink
RFC: Identity Proofs
Browse files Browse the repository at this point in the history
Signed-off-by: Kim Altintop <[email protected]>
  • Loading branch information
kim committed Mar 17, 2021
1 parent e1aac4a commit 45d7336
Showing 1 changed file with 212 additions and 0 deletions.
212 changes: 212 additions & 0 deletions docs/rfc/0002-identity_proofs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# RFC: Identity Proofs

* Author: @kim
* Date: 2021-02-23
* Status: draft
* Community discussion: n/a

## Motivation

A `radicle-link` [identity][ids] is a hash-linked sequence of signed statements
about public-key delegations: if an entry in this sequence is found to conform
to a quorum rule of cryptographic signatures, the set of keys it delegates to
can be considered trustworthy _iff_ the previous set was. Yet, how can we trust
the initial set of keys in this chain?

## Overview

We consider it impractical for most participants in the `radicle-link` network
to exchange public keys out-of-band, given a pattern of casual interaction with
others. While the protocol mandates connections between participants, similar to
"following" relationships found in social media, we thus consider it
insufficient to infer a [web of trust][wot] from those relationships.

To lift the requirement for physical authenticity checks, but still increase
confidence of a given public key being associated with a particular person,
[keybase] have popularised a scheme dubbed "Social Proofs": a statement claiming
ownership of a particular account on a social media site is written to the
keybase "sigchain" (which has properties similar to a `radicle-link` identity).
This claim (implying also the history of the sigchain) is signed using a key
currently valid according to the chain, and the signature (along with the public
key) is stored at the social media site. To verify the claim, the signature is
retrieved from the social media site in such a way that it could _plausibly_
only be created by the owner of the claimed account. If both the sigchain
integrity and the claim signature can be verified, the association is proven.

This mechanism can be considered a practical application of the [Turing
test][tt]: even though it can not be proven beyond doubt that the account is
indeed associated with a real person, the evidence of others accepting it as
such, as well as conversational behaviour, can increase the confidence in the
authenticity of the online persona. Because key and account ownership at a given
point in time can be cryptographically verified, this confidence can be extended
to the proving side.

We conclude that this mechanism would be a good fit for `radicle-link` (due to
the similarities), and a desirable feature of applications built on top of it.

The following sections describe how such claims shall be stored in the identity
payload of a `radicle-link` identity, how to obtain a publishable proof, and how
to verify it.

## Claims

Claims can only be made by identities of kind `Person`, and claim a single
external account identifier. They are introduced by defining a new payload type,
identified by the URL:

https://radicle.xyz/link/claim/v1

The shape of the JSON structure is:

```json
{
"SERVICE": {
"account": "STRING"
"expiration": {
"created": INTEGER,
"expires": INTEGER
},
"proof": "URL"
}
}
```

Where the fields denote:

* `SERVICE`

A conventional identifier of the external service, e.g. "github", "twitter",
"radicle-ethereum"

* `account`

The unique account identifier within the service, using the service-specific
canonical string representation e.g. "kim", "0x32be343b94f860124dc4fee278fdcbd38c102d88".

* `expiration` (optional)
* `created`

Creation timestamp of the claim, in seconds since 1970-01-01T00:00:00Z.

* `expires`

Seconds relative to `created`, after which the claim should no longer be
considered.

* `proof` (optional)

A URL to assist verification tooling in retrieving the proof from the external
system. This is mainly a convenience, and obviously requires creation of a new
revision after the fact.

## Proof Generation

The above claim payload is committed to the identity history as a new revision.
Technically, this revision needs to be approved by all key delegations for
verification to pass later on, but since we assume that eligible keys are held
by the same person, it may be acceptable to publish the proof right away for
user experience reasons.

The actual proof consists of the following tuple:

(root, revision, public-key, signature)

Note that the "git" protocol specifier of `radicle-link` URNs is implied, that
is, future version MUST treat the absence of a disambiguating value as denoting
"git".

The values `root`, `revision`, and `public-key` are specified in
[identities][ids], and it is RECOMMENDED to follow the serialisation formats
devised there. `signature` is the Ed25519 signature over `revision`, in much the
same way as the actual revision is signed. All values can thus be obtained by
inspecting the identity storage.

It is beyond the scope of this document to devise the exact external format to
serialise the tuple into, as this is expected to vary from service to service.

## Revocation

A claim can be revoked by creating a new identity revision which simply does not
contain the claim payload. Likewise, a later claim describing the same `SERVICE`
invalidates an earlier one.

## Verification

Inputs: the 4-tuple as specified [above](#proof-generation), and `(SERVICE,
account)` as inferred from the source it was retrieved from.

1. Given the 4-tuple specified, it is first verified that the signature is valid
for the given `revision` and `public-key`.

2. If it is, the identity history needs to be resolved from local storage, or
the network.

Using `git` storage, the history tip should be located at

refs/namespaces/<root>/refs/remotes/<public-key>/rad/id

substituting `<root>` and `<public-key>` with their respective encodings as
defined in [`Identities`][ids].

3. If the history tip could be resolved, the identity MUST be verified as per
[`Identities`][ids]. If this fails, the proof is rejected.

4. If the identity could be verified, the identity document is read from its
latest valid tip (recall that this is not necessarily the same as what the
ref points to). The proof is rejected if one of the following is true:

4.1 `root` does not match

4.2 the document does not contain a claim for `(SERVICE, account)`

4.3 the document contains a claim for `(SERVICE, account)`, has an
`expiration`, and `expiration.expires` is smaller than `time() -
expiration.created`

5. Lastly, the identity history is walked backwards until `revision` is found
(or else, the proof is rejected). The proof is accepted _iff_ all of the
following are true:

5.1 the document's `delegations` at `revision` contain `public-key`

5.2 the document at `revision` contains a claim for `(SERVICE, account)`, and
the claim is not expired as described in 4.3

Note that steps 3.-5. can be optimised by persisting verification results, or by
adding an additional accumulator to the verification fold which yields the
targeted `revision`.

## Discussion

The inclusion of the `revision` in the proof allows to assert that `root` is
indeed an ancestor, which opens up another way to detect "forks" of the identity
history: due to the peer-to-peer nature of the `radicle-link` network, it is
vulnerable to attacks which involve withholding data from other participants, in
which case a fork may go unnoticed.

It should be noted, however, that refreshing the proof from time to time in
order to ensure freshness of the data retrieved through `radicle-link` is not
always practicable.

In order to prove that the(ir own) server is not lying by omission, Keybase
[anchors a merkle root][keybase-stellar] on a blockchain, which includes all
sigchains registered in the Keybase directory. Because `radicle-link` does not
have such a central directory, this approach could only be applied to a partial
view of the network.

While conceivable that, given the right incentives, such a directory service
could be operated independently (similar to what the [ceramic] network devises),
it is unclear what value blockchain anchors of individual identities have, given
that transaction costs discourage frequent updates.

We thus RECOMMEND to explore Layer 2 solutions for blockchain anchoring.

---

[ids]: ../spec/sections/002-identities/index.md
[wot]: https://en.wikipedia.org/wiki/Web_of_trust
[keybase]: https://book.keybase.io/account#proofs
[tt]: https://en.wikipedia.org/wiki/Turing_test
[keybase-stellar]: https://book.keybase.io/docs/server/stellar
[ceramic]: https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md#blockchain-anchoring
[radicle-contracts]: https://github.com/radicle-dev/radicle-contracts

0 comments on commit 45d7336

Please sign in to comment.