To add someone as a contact you have to meet up in person and scan QR codes from each other's screens. The QR codes contain data that allows your devices to connect to each other and verify that they're connected to the right device.
The devices exchange public keys and derive a shared secret. Then they upgrade to a secure connection, exchange Briar identities, and verify that the identity they've received belongs to the user whose QR code was scanned.
An identity consists of a nickname that you choose when creating your account, and a public key that's used for signing messages. There's nothing to stop users from choosing the same nickname, so we call it a nickname rather than a username.
Once the devices have exchanged and verified identities, you and the other user are added to each other's contact lists.
Connecting to contacts
Your device will only connect to your contacts, not to any other users, and it will only accept connections from your contacts.
You can communicate with your contacts over various transports: the Android version of Briar supports Tor, wifi and Bluetooth, and the desktop version will also support memory sticks and dialup modems (useful during internet blackouts).
Your device exchanges data with your contacts' devices about how to connect over each transport. For example, when you're connected to wifi, your phone opens a socket and listens for connections, and it sends the IP address and port number of the socket to your contacts so they can connect if they're on the same wifi network.
Each transport is implemented as a plugin, which has a simple interface for making and accepting connections. Plugins aren't responsible for authenticating the devices they communicate with or securing the data that's transferred. They just make connections.
The security of the data (authentication, confidentiality, integrity and forward secrecy) is handled by the transport security protocol, BTP. The same protocol is used for all transports.
BTP is an obfuscated protocol: to anyone except the intended sender and recipient, all data is indistinguishable from random. So BTP's first job is to let the recipient know who sent the data, so the recipient can use the right key to authenticate and decrypt it.
This is done by attaching a pseudo-random tag to the data. The sender and recipient generate identical sequences of tags, and the sender attaches one tag to each stream of data it sends. The recipient recognises the tag, removes it from her sequence, and uses the corresponding key to authenticate and decrypt the stream.
The recipient keeps a sliding window containing the next few expected tags, so she can recognise streams that arrive out of order if the transport drops or reorders connections.
Each tag is only used once, and nobody except the sender and recipient can distinguish the tags from random. Everything except the tag is encrypted, so the whole stream is indistinguishable from random.
The sender and recipient keep two keys for each transport: one for generating tags and the other for authenticating and encrypting streams. These keys are rotated periodically to provide forward secrecy.
How often the keys are rotated depends on the latency of the transport. (We don't want to delete a key while a stream is still on its way from the contact's device to our device, otherwise we won't be able to recognise or decrypt the stream.)
The rotation period also depends on the maximum possible clock difference between the devices. (We don't want to delete a key that our contact's still using due to an inaccurate clock.)
Clocks on consumer devices can be very inaccurate because people don't always set the right timezone, so we assume a clock difference of up to 24 hours. This means the rotation period is at least 24 hours for all transports. For high-latency transports like memory sticks (which might be hidden in someone's shoe and smuggled across a border) we'll use a longer rotation period, maybe 4 weeks.
BTP streams can carry any kind of data. Briar uses them to carry a data sync protocol called BSP. Its job is to synchronise chunks of immutable data between pairs of devices.
Each chunk of data is called a message, and it's addressed to a group. A group is just a label that devices can subscribe to. It works much like a Usenet newsgroup.
You can create a group that's just stored on your own device, or shared with one other user, or with a known set of users, or with an open-ended set of users that may contain people you don't know.
Briar uses these groups to implement private messaging, group messaging, blogs and forums, and also for automatic tasks like exchanging information with your contacts about how to connect over various transports.
Groups can also be used to implement multi-party protocols, like the protocol for introducing your contacts to each other.
BSP doesn't understand the content of messages. It just syncs the messages in each group with whichever contacts you've chosen to share the group with.
It does this by exchanging four types of record with your contacts: offers, requests, messages and acks.
An offer contains the unique IDs of some messages that belong to groups you've shared with the contact. The contact responds by requesting any messages she hasn't seen and acking any messages she has seen. You send any messages the contact requested, and the contact acks them.
When operating over a unidirectional transport like memory sticks, we skip the offer and request stages and just send any messages the contact hasn't previously acked. This cuts down the number of round-trips.
If we don't get a response to an offer or message after a certain amount of time, we assume it was lost and retransmit it. The timeout depends on the latency of the transport and the number of times we've offered or sent the message.
BSP doesn't know what a valid message looks like for each group, or how to determine the relationships between messages. All of that is handled by a sync client, which is an application component that makes use of BSP and BTP to sync data with contacts. For example, private messaging is a sync client.
When the sync layer receives a message addressed to a group, it looks up which sync client the group belongs to and passes the message to the client for validation. The client parses the message, extracts the unique IDs of any other messages the message depends on, and returns the IDs to the sync layer. When all the dependencies have been received, the message is passed back to the client for processing (this is called delivery).
The client is responsible for deciding which groups to share with which contacts. This is how Briar handles sharing blogs, forums and private groups, and ensures that private messages are only shared with a single contact.