Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC4161: Crypto terminology for non-technical users #4161

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Changes from 6 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5f08ae9
Initial commit for MSC4161: Crypto terminology for non-technical users
andybalaam Jun 27, 2024
32f386b
First draft
andybalaam Jun 27, 2024
cd26b70
Fix typo
andybalaam Jun 27, 2024
a7b5a77
Fix mis-formatted heading
andybalaam Jun 27, 2024
a79b289
Fix incorrect bolding
andybalaam Jun 27, 2024
89412cc
Ensure we are consistently saying Alice's identity appears to have ch…
andybalaam Jun 27, 2024
d15576e
Add another example for key storage
andybalaam Sep 5, 2024
af70e43
Link to MSC4153 where we mention it.
andybalaam Sep 5, 2024
720cdeb
Make the wording about resetting keys more precise.
andybalaam Sep 5, 2024
de285aa
Re-word the paragraph about the importance of verified identity chang…
andybalaam Sep 5, 2024
57fc5c1
Link to the spec equivalent wording for our recovery key
andybalaam Sep 5, 2024
a4b95b4
Re-word the paragraph about Invisible Crypto
andybalaam Sep 5, 2024
0499900
Propose being an appendix to the spec
andybalaam Sep 6, 2024
b919630
Add a section on what to say when a message can't be decrypted
andybalaam Sep 6, 2024
007a15f
Add a missing 's'
andybalaam Sep 6, 2024
45928bb
changes->changed
andybalaam Sep 6, 2024
3a2d012
Remove erroneous UTD message
andybalaam Sep 6, 2024
56b5daf
Mention that clients SHOULD follow this guide and document any except…
andybalaam Oct 7, 2024
fba4f5c
person->user
andybalaam Oct 7, 2024
9246021
Reword sentence on cross-signing
andybalaam Oct 7, 2024
0c9d812
Re-word the "Waiting for this message" sentence
andybalaam Oct 7, 2024
705f7bb
Add missing word "message"
andybalaam Oct 7, 2024
4bcee33
Remove unneeded 'private key' warning
andybalaam Oct 7, 2024
f654c2e
Re-word 'key-backup' paragraph to contrast with export.
andybalaam Oct 7, 2024
3c7695f
Make clear that 'insecure device' is permitted
andybalaam Oct 7, 2024
7a789c5
Remove 'cryptographic' before 'identity', and also tone down the warn…
andybalaam Dec 17, 2024
3ed51ec
Link to spec sections on QR and emoji, and transitive trust MSC
andybalaam Dec 17, 2024
b44397b
Add a section about why this is important
andybalaam Dec 17, 2024
04df819
Add a paragraph about losing the recovery key
andybalaam Dec 17, 2024
bdbd7b4
Remove the 'appears to have changed' wording and add explanation
andybalaam Dec 17, 2024
7a9a84b
Note that older spec versions say 'recovery key'
andybalaam Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 276 additions & 0 deletions proposals/4161-crypto-terminology.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation requirements (in my opinion):

  • User research to show these terms as helpful and easily understood.

The research may be done through studies or deployment to a portion of the user base with analytics to show "easier" use of the app.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall review: The MSC appears to describe features and requirements of Element, and assumes that all clients in the ecosystem have similar or comparable features/needs. The assumptions read fine when applying this MSC to an Element client, but when comparing to the spec there feels like there's a gap in understanding.

Significant review from other client authors/developers, and their respective product/design teams, I think would be extremely valuable to help ensure this MSC does not solely apply to Element. This kind of review may need to be chased down as it's somewhat uncommon for a product-y MSC to be in the spec process.

Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
# MSC4161: Crypto terminology for non-technical users

## Background

Matrix makes use of advanced cryptographic techniques to provide secure
messaging. These techniques often involve precise and detailed language that is
unfamiliar to non-technical users.

This document provides a list of concepts and explanations that are intended to
be suitable for use in Matrix clients that are aimed at non-technical users.

Ideally, encryption in Matrix should be entirely invisible to end-users (much as
WhatsApp or Signal users are not exposed to encryption specifics) - as outlined
in [MSC4153](https://github.com/matrix-org/matrix-spec-proposals/pull/4153).
However, consistent terminology is still required, especially during the
transition period to Invisible Cryptography.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

## Goals

We hope that Matrix client developers will like the terms and wording we
provide, and adapt their user interfaces and documentation to use them. (If this
MSC is accepted, Element will use it as a reference for English wording in its
clients.)

Where concepts and terms exactly match existing terms in the Matrix spec, we
propose changing the spec to use the terms from this document. Where they do not
match, we are very comfortable with different words being used in the spec,
given it is a highly technical document, as opposed to a client user interface.

We hope that this MSC will:

* Cause small changes in the spec (as described in the previous paragraph), and
* Become a document, blessed by the spec core team and available on the spec web
site, but probably separate from the spec proper.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

Clients may, of course, choose to use different language. Some clients may
deliberately choose to use more technical language, to suit the profiles of
their users. This document is aimed at clients targeting non-technical users.
Comment on lines +66 to +68
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's unclear if this is part of the proposal, or accepting fate. If it's part of the proposal, I suggest moving it down to the normative sections (under "Proposal").

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote some words in 56b5daf - let me know what you think.


Where changes are made in the spec, we suggest that notes be added mentioning
the old name, as in [this
example](https://github.com/matrix-org/matrix-spec/pull/1819/files#diff-8b25d378e077f18eb06ebdb9c376e194c8a4c8b95cf909fca6448659a627f283R1326).

## Proposal

When communicating about cryptography with non-technical users, we propose using
the following terms and concepts.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

### Devices

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like calling sessions devices. It may work well for other, mobile first networks, but with matrix it's not all that uncommon to run multiple sessions on the same device.

Copy link
Member

@uhoreg uhoreg Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that "sessions" is used to refer to other things in the spec. So it would be more confusing to call something else "sessions".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about explicitly naming them "Crypto-Sessions" or something in this direction? I agree with the initial mention about devices. This is already these days due to some UIs a bit confusing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My personal take is that most people are familiar with "devices", and non-technical users will probably only have one crypto session per device. Further, where people do have multiple sessions on a device I think is it relatively easy to explain that they look like multiple devices to Matrix even though they exist on the same physical device.

In contrast, when I started using Matrix I had no idea what a "session" was, and as I learned more I became further confused because the word is used for several other concepts, including e.g message keys.

So I plan to propose this as-is.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as much as i hate the "devices" terminology, this is also how it's named over on eg. Discord.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as much as i hate the "devices" terminology, this is also how it's named over on eg. Discord.

or Whatsapp or Signal or other platforms. Which is why we suggest it in the first place.

Has user research shown that devices are preferred over sessions? Does Element have some data on their existing transition from devices to sessions?

Not sure whether we have something dedicated to exactly this comparison. @americanrefugee might know more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gmail uses “session”. I’m sure others do too. I don’t think it’s such a foreign term for laypeople, or that it can’t be understood by them.

image

Whatsapp and Signal are more or less tied to phones and don’t expect any other client than “the one app” you have on said phones. In their context, device works. Comparing to them doesn’t work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that "sessions" is used to refer to other things in the spec. So it would be more confusing to call something else "sessions".

This MSC is about terms to use for non-technical users as far as I can see. I reckon it is not a problem to use a word for something in a given context, and a different word for the same thing in another context. The spec can call these crypto-sessions as was suggested above, or even devices if further disambiguation is deemed necessary. In a technical context, it can be clear that a “device” is not a piece of equipment, whereas it is really not clear for non-technical users.

Without even thinking about multiple distinct clients on the same device, a single client can become a new session if access to the previous session is lost for some reason. And so now you have two “devices” listed even though you used a single computer and a single client.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Element's product people favour "devices", as do Discord, Signal and WhatsApp. We have a counter-example in Google, but I personally find much of Google's UI quite confusing, especially gmail.

As for having two devices listed even though you only used one: the proposed wording seems helpful to me - the mismatch between the wording and reality indicates a problem: they should remove the old device.

Perhaps the product designers from other products could chip in, but at the moment the scale seems to be tipping towards "devices".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as do Discord, Signal and WhatsApp

Again: you are comparing apples to oranges. Signal and WhatsApp have a very different relationship to clients and devices.


Instances of a client are called 'devices' (not 'sessions'). Aligned with
MSC4153, we take it as granted that all devices have been cross-signed by the
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
user who owns them, and we call these **devices**.

Devices which have not been cross-signed by the user are considered an error
state, primarily to be encountered during the transition to MSC4153 and/or due
to buggy/incomplete/outdated clients. These devices are referred to as **not
secure** and presence of them are considered a serious and dangerous error
condition, similar to an invalid TLS certificate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this appears to extend beyond definition and into specification. Is there existing spec which describes the 'error state'? Should we explore the concepts of error and security through another MSC?

andybalaam marked this conversation as resolved.
Show resolved Hide resolved

> "This device is not secure. Please verify it to continue."
> "Ignoring 5 messages that were sent from a device that is not secure."
> "Confirm it's you" (when asking to verify a device during login)
⚠️ Avoid saying "secure device". All devices are considered secure by default;
the user doesn't typically need to worry about the fact that insecure devices
are a thing, given they should only ever occur in error (or transitional)
scenarios.

⚠️ Avoid saying "trusted device" or "verified device". Devices are not people,
and it is helpful to use different language for people vs. devices. (However, we
do use the verb "verify" to describe how to make a device secure. By using the
same verb, we help users understand the confusing fact that verifying devices
and verifying people are similar processes, but with different outcomes.)

⚠️ Avoid using "cross-signing", which requires a deeper understanding of
cryptography to understand.

⚠️ Avoid mentioning "device keys" - a device is just secure or not.

⚠️ Avoid "session" to mean device. Device better describes what most people
encounter, and is more commonly used in other products.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

### Verified person

When you verify a person they become **verified**. This means that you have
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
cryptographic proof that no-one is listening in on your conversations. (You need
this if you suspect someone in a room may be using a malicious homeserver.)

In many contexts, most people are **not verified**: verification is a manual
step (scanning a QR code or comparing emojis). (In future, verification will
probably become more common thanks to "transitive trust" or "key transparency").
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
When an unverified person resets their cryptographic identity, we should warn
the user, so they are aware of the change.

If a verified person's cryptographic identity changes (i.e. they reset their
recovery key) then this is very important: we verified them because we care
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
about proof that no-one is listening, and now someone could be. The user can
choose to **withdraw verification** (i.e. "demote" them from being verified), or
**re-verify** them. Until they do one or the other, communication with them should
contain a prominent and serious warning that the user's **verified identity has
changed**.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

> "This person is verified."
> "WARNING: Bob's verified identity has changed!"
> "You verified this person's identity, but it has changed. Please choose to
> re-verify them or withdraw verification."
⚠️ Avoid using "cross-signing", which requires a deeper understanding of
cryptography to understand.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

⚠️ Avoid using "trust on first use (TOFU)", which is a colloquial name for noting
the identity of people who are not verified so that we can notify the user if it
changes. (This is a kind of "light" form of verification where we assume that
the first identity we can see is trusted.)

⚠️ Avoid confusing verification of people with verification of devices: the
mechanism is similar but the purpose is different. Devices must be verified to
make them secure, but people can optionally be verified to ensure no-one is
listening in or tampering with communications.

⚠️ Avoid talking about "mismatch" or "verification mismatch" which is very
jargony - it is the identity which is mismatched, not the verification process.
Just say "Bob's verified identity has changed".
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

⚠️ Avoid talking about "cryptographic identity" which is very jargony. Just call
it "identity" where possible - i.e. the non-technical dictionary definition of
identity such that someone is who they claim they are, not someone else. The
fact we confirm identity cryptographically is irrelevant to the user;
cryptography should be invisible.

### Identity

A person's **identity** is proof of who they are, and, if they are verified,
proof that you have a secure communication channel with them.

> "Warning: Alice's identity appears to have changed" (when a non-verified
> person resets their recovery key)
> "WARNING: Bob's verified identity has changed!" (when a verified person resets
> their recovery key)
(During login, at the "Confirm it's you" stage):

> "If you don't have any other device and you have lost your recovery key, you
> can create a new identity. (Warning: you will lose access to your old
> messages!)" button text (in red or similar): "Reset my identity"
⚠️ Avoid saying "master key" - this is an implementation detail.

⚠️ Avoid saying "reset their encryption" - the reason that Alice's identity
changes could be due to attack rather than because they reset their encryption
(plus "encryption" is jargony).

### Message key
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

A **message key** is used to decrypt a message. The metaphor is that messages
are "locked in a box" by encrypting them, and "unlocked" by decrypting them.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

> "Store message keys on the server."
> "This message could not be decrypted because its key is missing."
⚠️ Avoid saying "key" without a previous word saying what type of key it is.

⚠️ Avoid using "room key". These keys are used to decrypt messages, not rooms.

Note: this clashes with the term "message key" in the double ratchet. Since the
double ratchet algorithm is for a very different audience, we think that this is
not a problem.

### Message history

Your **message history** is a record of every message you have received or sent,
and is particularly used to describe messages that are stored on the server
rather than your device(s)

### Key storage
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this "Secret storage".

The mechanism in question can store arbitrary data, not all of which are keys. The next paragraph already has to perform significant linguistic gymnastics in order to explain that the user's identity is also stored in the key storage, even though it is called an identity, not a key. (The fact that it is a key is an unimportant technical detail from a user perspective and is very jargony.)

On the other hand, explaining that a key is a certain type of secret should be very natural.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this "Secret storage".

We discussed this. The challenge we see is that it could be mixed up. It could either mean

  1. a storage for secrets
  2. a storage that is secret

That's why we discarded it and propose "Key storage". For a user it is irrelevant if something is a secret or a key or a token or a hash or whatnot, technically speaking. From a users point of view it should be a safe place that holds keys to open up stuff on new devices or in case of an emergency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the problem will be further exacerbated if/when new non-key things start getting stored in secret storage.

Copy link

@Xiretza Xiretza Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this. The challenge we see is that it could be mixed up. It could either mean

  1. a storage for secrets

  2. a storage that is secret

Wouldn't "Secrets storage" fix that problem?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Secrets storage" is feels unnatural to say in English. The justification for "key storage" is that the most important things (from a non-technical user's point of view) that are stored in this storage are message keys.

The fact that other things also get stored there doesn't need to prevent us naming it after the most important thing. For example, if I have a school locker for P.E. kit that I commonly call a "kit locker" I think it would be perfectly natural for me to say "I keep my Sony Walkman and Rubik's cube in my kit locker"...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that other things also get stored there doesn't need to prevent us naming it after the most important thing

It doesn't need to, but I think it should, considering that the whole point of this exercise is to make the language used less confusing.


**Key storage** means keeping cryptographic information on the server. This
includes the user's cryptographic identity, and/or the message keys needed to
decrypt messages.
Copy link
Member Author

@andybalaam andybalaam Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to split this into 2 separate concepts: I thought we could run storage of message keys together with storage of identity keys etc (recovery) but recently I realised they a really separate, so we probably need something like this:

  • Room key storage - store room message keys on the server, protected by a room message key storage key. This room message key storage key can be passed around between devices even if you don't have recovery storage.
  • Recovery storage - store identity keys and the room message key storage key on the server, protected by a recovery code. This allows us to recover both our identity and our room message key storage key even if we lose all our devices.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth noting that the EX designs (https://www.figma.com/design/qTWRfItpO3RdCjnTKPu4mL/Settings?node-id=1653-29941&node-type=frame&t=LeUe8iJVmzG8srM5-0 etc) refer to "key storage" to cover both of these concepts. I think that's ok; we just need to be clear that "key storage" is used for both room keys and recovery, and that they are set up separately.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Room key storage - store room keys on the server, protected by a room key storage key.

NB they are message keys, not room keys.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it would be great if we could abstract the details to the user. It should just be one feature from a user POV. Either you want the server to store some information for you and get benefits from it or you don't. I don't see a reason why the user should need to understand the exact concepts behind it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it would be quite a change from the way the apps currently work. Currently EX sets up key backup on registration, but doesn't set up recovery until you actively go through the steps (and EW is even more flexible). That's also why the designs above have separate entries for "Allow key storage" and "set up recovery".

Possibly we could change that, and force the user to set up recovery during the registration/login flow; but it would go against the desire to get people using the app quickly. (Also, this MSC is intended to cover matrix clients in general: even if the Element clients force you to set up recovery at the same time as key backup, other clients may not, and having the terminology available to refer to that situation is important.)


If a user loses their recovery key, they may **reset** their key storage. Unless
they have old devices, they will not be able to access old encrypted messages
because the message keys are stored in key storage, and their cryptographic
identity will change, because it too is stored in key storage.

> "Allow key storage"
> "Key storage holds your cryptographic identity on the server along with the
> keys that allow you to read your message history."
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
⚠️ Avoid distinguishing between "secret storage" and "key backup" - these are
both part of key storage.

⚠️ Avoid talking about more keys: "the backup key is stored in the secret
storage, and this allows us to decrypt the messages keys from key backup".
Instead, we simply say that both cryptographic identity and message keys are
stored in key storage.

⚠️ Avoid using "key backup" to talk about storing message keys: keeping things on
the server is not a "backup", but a reliable, cross-device place where this
information is stored. The word "backup" implies a redundant way to recover lost
information, but if the user loses their recovery key, this information is lost.
Clients and servers may wish to offer additional backup services that provide
true redundancy and disaster recovery, but key storage is not this.
dkasak marked this conversation as resolved.
Show resolved Hide resolved

⚠️ Avoid "4S" or "quad-S" - these are not descriptive terms.

⚠️ Avoid "private key" - this is an implementation detail and a term with
specific meaning from cryptography.
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

### Recovery key (and recovery passphrase)

A **recovery key** is a way of regaining access to key storage if the user loses
all their devices. Using key storage, they can preserve their cryptographic
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, Beeper settled on "recovery code" after considering other options including "recovery key", but I don't remember the exact reasoning since the switch was made 2 years ago

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asked for the reasoning internally:

Code sounded more friendly than key (in an unscientific review).
e.g. people know what a pin code is. Code is a numerical thing but a 'key' to most people is a physical object

identity (meaning other people don't see "Alice's identity appears to have
changed" messages), and also read old messages using the stored message keys.

A **recovery passphrase** is an easier-to-remember way of accessing the recovery
key and has the same purpose as the recovery key.

> "Write down your recovery key in a safe place"
> "If you lose access to your devices and your recovery key, you will need to
> reset your key storage, which will create a new identity"
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
> "If you lose your recovery key you can generate a new one if you are signed in
> elsewhere"
⚠️ Avoid using "security key", "security code", "recovery code", "master key". A
recovery key allows "unlocking" the key storage, which is a "box" that is on the
server, containing your cryptographic identity and message keys. It is used to
recover the situation if you lose access to your devices. None of these other
terms express this concept so clearly.

⚠️ Remember that users may have historically been trained to refer to these
concepts as "security key" or "security passphrase", and so user interfaces
should provide a way for users to be educated on the terminology change (e.g. a
tooltip or help link): e.g. "Your recovery key may also have been referred to as
a security key in the past"

## Potential issues
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MSC should address why it's important that all clients use the same language, and why the language of the MSC is generic enough to fit the language and feel of all client applications. An app which has a less professional feel may prefer to use different terms for brand identity/recognition, for example. This MSC feels a bit too prescriptive for all audiences.

A common language feels important to me, regardless of audience impact, but the MSC does not really tell me why I should feel that way.


Lots of existing clients use a whole variety of different terminology, and many
users are familiar with different terms. Nevertheless we believe that working
together to agree on a common language is the only way to address this issue
over time.

## Further work

Several other concepts might benefit from similar treatment. Within
cryptography, "device dehydration" is a prime candidate. Outside cryptography,
many other terms could be agreed, including "export chat" (particularly in
contrast to "export message keys").

## Security considerations

In order for good security practices to work, users need to understand the
implications of their actions, so this MSC should be reviewed by security
experts to ensure it is not misleading.

## Dependencies

None

## Credits

Written by Andy Balaam, Aaron Thornburgh and Patrick Maier as part of our work
for Element. Richard van der Hoff, Matthew Hodgson and Denis Kasak contributed
many improvements before the first draft was published.