<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="https://learn.equalit.ie/mw/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://learn.equalit.ie/mw/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Infinity0</id>
		<title>learn.equalit.ie - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://learn.equalit.ie/mw/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Infinity0"/>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Special:Contributions/Infinity0"/>
		<updated>2026-04-05T21:30:44Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.23.1</generator>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/Specification</id>
		<title>Np1sec/Specification</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/Specification"/>
				<updated>2014-09-19T21:38:01Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: add category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Procedures ==&lt;br /&gt;
&lt;br /&gt;
=== Chat setup ===&lt;br /&gt;
&lt;br /&gt;
In almost any practical case, participants join the chat sequentially. It is assumed that multiple participants cannot join simultaneously. For the sake of efficiency one can tweak the implementation to have a threshold to wait and start a chat with more participants. However, this makes the implementation significantly more complicated without an evident efficiency benefit.&lt;br /&gt;
&lt;br /&gt;
Therefore, our assumption is that a secure chat is always set up when a participant starts the chat room. Additional participants would be added sequentially using Algorithm [[mpCAT#VIII.3_Joining|VIII.3]], as they enter the chat. Algorithm [[mpCAT#Chatroom_setup|1]] describes the chat room setup protocol.&lt;br /&gt;
&lt;br /&gt;
====Chatroom setup====&lt;br /&gt;
&amp;lt;!--alg_chat_setup--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Chatroom Init}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;newRoomName&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;participantNick&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;myId := 1&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;Nick_{myId} := participantNick&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;roomName := newRoomName&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;x_{myId}, y_{myId} :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Generate Initial Paramters&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;signatureKey_{myId} := (x_{myId},y_{myId})&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;participantList := [Nick_{myId}]&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;ephemeralPublicPointList := [y_{myId}, y_{other}]&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Joining ===&lt;br /&gt;
&lt;br /&gt;
Joining a chat involves two different procedures: the Join procedure, described in Algorithm [[mpCAT#Join|2]], which runs on the new participant’s instance, and an Accept New Participant Procedure, described in Algorithm [[mpCAT#Protocol_for_other_participants_already_in_the_chat_to_accept_the_newcomer|3]], which runs on the clients of participants that are already in the chat.&lt;br /&gt;
&lt;br /&gt;
When a new participant &amp;lt;math&amp;gt;U_{n+1}&amp;lt;/math&amp;gt; joins the chat, current participants can still use their established authenticated ephemeral public key (to derive the &amp;lt;math&amp;gt;sessionKey_{new}&amp;lt;/math&amp;gt; and as their signature verification key). Confidentiality of &amp;lt;math&amp;gt;sessionKey_{old}&amp;lt;/math&amp;gt; is guarded against the new participant by Diffie-Hellman key shares hashed alongside the session id (which is dependent on the list of participants). The new participant cannot combine the old and new shares to recover &amp;lt;math&amp;gt;sessionKey_{old}&amp;lt;/math&amp;gt;. The fact that old participants do not need to compute new ephemeral keys (and re-verify their ephemeral identities) decreases the computational complexity of the protocol.&lt;br /&gt;
&lt;br /&gt;
====Join====&lt;br /&gt;
&amp;lt;!--alg_join--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Join}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;newRoomName&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Nickname_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;participantId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;myId := participantId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;roomName := newRoomName&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;x_{myId}, y_{myId} := &amp;lt;/math&amp;gt;&amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Generate Initial Paramters&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;signatureKey_{myId} := (x_{myId},y_{myId})&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3Join:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Nickname_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;y_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;participantList, ephemeralPublicPointList :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionId := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Id&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;roomName&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;participantList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPointList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign and Send Key Confirmation and Shares&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyConfirmationShare:3&amp;quot;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;keyShareList, keyConfirmationList, signatureList :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Verify Key Confirmations and Signatures&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyConfirmationList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Receive Session Digest}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;currentSessionHistoryDigest&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionDigest := currentSessionHistoryDigest&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
====Protocol for other participants already in the chat to accept the newcomer====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--alg_accept--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Accept}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;newParticipant&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3Join:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Nickname_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;y_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3Join:3&amp;quot;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;nick_{NewParticipant}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPoint_{NewParticipant} := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Lists&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;nick_{NewParticipant}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPoint_{NewParticipant}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionId := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Id&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;roomName&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;participantList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPointList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign and Send Key Confirmation and Shares&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyConfirmationShare:3&amp;quot;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;keyShareList, keyConfirmationList, signatureList :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Verify Key Confirmations and Signatures&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyConfirmationList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Send&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Sending and receiving messages while joining is in progress ===&lt;br /&gt;
In situations where a prolonged joining process (due to connection problems or malicious activities) has an adverse effect on the user experience, it might be desirable to enable the joining users to communicate with the parties in the room, while maintaining minimum assurances of authenticity, confidentiality, forward secrecy, as well as consistency only among participants.&lt;br /&gt;
&lt;br /&gt;
Consistency aspects of mpCat, both for the room view (plist) and for the transcript, are reached through group agreement. However, there are times when group agreement may be hard or impossible to reach either due to latency in a single participant connection or due to a single participant broadcasting incorrect confirmation data (such as wrong plist, sid, key share, etc).&lt;br /&gt;
&lt;br /&gt;
We offer an extension to the mpCat protocol to tackle this problem during the joining process. When a new participant joins the room, they send their DH key shares to the other participants. The other participants send their ephemeral key in return. They then send their key confirmation and key share. If this extension is to be considered, as soon as each user receives a key confirmation from another user, who is not currently part of the session, mpCat displays a message highlighting the fact that although the user is not part of the session, the conversation is being shared with them (through P2P encryption using the key derived from DH Key). The protocol, however, does not honour their input into the consistency check, until a new session including the new user is set up. Each client can decide whether to disable this option.&lt;br /&gt;
&lt;br /&gt;
The user remains in the list of those not part of the current session, but receives the session messages until a new session is set up. Similarly, when a user receives a message from a user who is not part of the session, mpCat will decrypt the message and display it with a disclaimer that the user is not yet part of the session and that some participants may not receive the same message.&lt;br /&gt;
&lt;br /&gt;
In this model, a room is a forwardly secure authenticated communication channel while a session is a subset of the room, which additionally offers a consistent view&lt;br /&gt;
of the room and consistent messages among participants.&lt;br /&gt;
&lt;br /&gt;
=== Leave ===&lt;br /&gt;
&lt;br /&gt;
Leaving a chatroom involves only one procedure for those who are staying in the chatroom (Procedure Farewell) which is described in Algorithm [[mpCAT#Farewell|4]]. The remaining participants only need a notice from the server that the user is leaving to re-run the one round key update algorithm. Also, failure to receive a heartbeat from a user will result in executing Algorithm [[mpCAT#Farewell|4]] excluding users which did not update their key.&lt;br /&gt;
&lt;br /&gt;
====Farewell====&lt;br /&gt;
&amp;lt;!--alg_farewell--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Shrink on Leave}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;leaverId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''remove''' &amp;lt;math&amp;gt;leaverId&amp;lt;/math&amp;gt; from &amp;lt;math&amp;gt;participantIdList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionId :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Id&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   '''if''' &amp;lt;math&amp;gt;|participantList| &amp;gt; 1&amp;lt;/math&amp;gt;''', then'''&lt;br /&gt;
     &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign and Send Key Shares&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
     &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyShare:3&amp;quot;)&lt;br /&gt;
     &amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
     &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Sign and Send Key Shares}}&lt;br /&gt;
 Input: &lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId -1, myId} := Hash(k_{myId,myId-1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId, myId+1} := Hash(k_{myId,myId+1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;keyShare_{myId} := z_{myId -1, myId} \oplus z_{myId, myId+1}&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;originAuthSignature :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519Sign&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;SignatureKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;z_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyShare:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;keyShare_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;)  # we can send this encrypted but leaving person can read it, hence theoretically it is the same as sending it unencrypted.&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Secure Send and Receive ===&lt;br /&gt;
&lt;br /&gt;
After the session key is established, participants will use Algorithms [[mpCAT#Send|5]] and [[mpCAT#Receive|6]] to communicate securely.&lt;br /&gt;
&lt;br /&gt;
On Send, the protocol checks the status of the new ephemeral Diffie-Hellman and key share using messages it receives from participants. It (re)sends any missing pieces. It also informs other participants which part of the key share is received by that user. The metadata flag indicates if the message being sent only contains meta data (e.g. heartbeat) or actual user communication.&lt;br /&gt;
&lt;br /&gt;
On Receive, the protocol updates who has which pieces of the key shares. The protocol also generates a new group key if the new key shares have been received from all participants or those who have not updated their key shares time out on their heartbeat interval.&lt;br /&gt;
&lt;br /&gt;
====Send====&lt;br /&gt;
&amp;lt;!--alg_send--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Send}}&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;metaMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;keyShareMessage&amp;lt;/math&amp;gt; = &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''NewKeyShareMessage&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;metaMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;math&amp;gt;cryptMessage&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''AES CTR Encrypt&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionKey&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;message | keyShareMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519Sign&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;SignatureKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;cryptMetatMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Digest&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;lastMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3&amp;quot;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;cryptMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;,&amp;quot;:3&amp;quot;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
====Receive====&lt;br /&gt;
&amp;lt;!--alg_recv--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Receive}}&lt;br /&gt;
Input: &amp;lt;math&amp;gt;sender&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;encryptedMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;v := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519VerifySignature&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;ephemeralPublicKeyList[Sender]&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId || encryptedMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Assert&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;) or '''return''' Reject&lt;br /&gt;
   &amp;lt;math&amp;gt;message, keyShareMessage :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''AES CTR Decrypt&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;encryptedMessage&amp;lt;/math&amp;gt;){}&lt;br /&gt;
   &amp;lt;math&amp;gt;isMetaMessage = &amp;lt;/math&amp;gt;&amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''UpdateNewKeyStatus&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyShareMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Verify Digests&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionDiges&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''return'''{&amp;lt;math&amp;gt;isMetaMessage, message&amp;lt;/math&amp;gt;}  # isMetaMessage is true if the message is purely meta message and there is nothing to display&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Common functions ===&lt;br /&gt;
&lt;br /&gt;
====Common functions used by other procedures in different stages====&lt;br /&gt;
&amp;lt;!--alg_comm--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Generate Initial Paramters}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;signaturePrivateKey := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''RandomBits&amp;lt;/span&amp;gt;'''(256)&lt;br /&gt;
   &amp;lt;math&amp;gt;x_{myId} :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Ed25519 Scalar&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;signaturePrivateKey&amp;lt;/math&amp;gt;)) #{This is both Diffie-Hellman secret and ephemeral signature private key}&lt;br /&gt;
   &amp;lt;math&amp;gt;y_{myId} := x_{myId}P&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;math&amp;gt;x,y&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Verify Key Confirmation and Signatures}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;keyConfirmationList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;participant \in participantList&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
     '''if''' &amp;lt;math&amp;gt;keyConfirmationList[participant][myId] \neq Hash(k_{myId,participant} , U_{myId} )&amp;lt;/math&amp;gt;''', then'''&lt;br /&gt;
       &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Halt&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
     '''else''' '''if''' &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519VerifySignature&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;ephemeralPublicKeyList[particicpant]&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId | keyShares[myId]&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;) = Fail ''', then'''&lt;br /&gt;
       &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Halt&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Compute Session Id}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;participantList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPointList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;math&amp;gt;Hash(roomName, zip(participantList, ephemeralPublicPointList))&amp;lt;/math&amp;gt;  # &amp;lt;math&amp;gt;zip([a,b],[c,d]):=[(a,c),(b,d)]&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Verify Signatures}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;longPublicList&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;schnorrRandomPointList&amp;lt;/math&amp;gt;, &lt;br /&gt;
 # standard signature verification&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Sign and Send Key Confirmation and Share}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;schnorrRandomPointList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;participant \in participantList&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
     &amp;lt;math&amp;gt;k_{myId, participant} := Hash(x_{myId}LP_{participant} |lp_{myId}y_{participant} | x_{myId}y_{participant})&amp;lt;/math&amp;gt;  # Triple DH&lt;br /&gt;
     &amp;lt;math&amp;gt;kc_{myId} := kc_{myId} | Hash(k_{myId,participant}, U_{participant})&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId -1, myId} := Hash(k_{myId,myId-1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId, myId+1} := Hash(k_{myId,myId+1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;keyShare_{myId} := z_{myId -1, myId} \oplus z_{myId, myId+1}&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;originAuthSignature :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519Sign&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;SignatureKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;z_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyConfirmationAndShare:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;keyShare_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;kc_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Update Session Key}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;i := myId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;{j \in [i,...,i+n-1]}&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
      &amp;lt;math&amp;gt;z_{j,j+1} := z_{j-1,j} \oplus keyShareListe[j+1]&amp;lt;/math&amp;gt;&lt;br /&gt;
     # recovered &amp;lt;math&amp;gt;z_{i-1,i}&amp;lt;/math&amp;gt; should be equal to its original value&lt;br /&gt;
    '''global''' &amp;lt;math&amp;gt;sessionKey := Hash(z_{j,j+1} | j \in [1...n])&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Sign Params Update Session Key}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;toBeSigned&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;math&amp;gt;toBeSigned := Hash(sessionId, ||Hash(verifierList, ephemeralPublicPointList, keyShareList)))&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;signature_{myId} := &amp;lt;/math&amp;gt;&amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign Session and Send&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;toBeSigned&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3SignedSessionParameters:3&amp;quot;,&amp;lt;math&amp;gt;signature_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=ComputeSessionDigest}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;lastMessage&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt; in Messages Received from &amp;lt;math&amp;gt;lastDigestedMessage&amp;lt;/math&amp;gt;+1 till &amp;lt;math&amp;gt;lastMessage&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
      &amp;lt;math&amp;gt;sesionDigest := Hass(sessionDigest, message)&amp;lt;/math&amp;gt; &lt;br /&gt;
      &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''LRU Cache Store Digest&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''return''' &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;lastMessageId&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=NewKeyShareMessage}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;metaMessage&amp;lt;/math&amp;gt;&lt;br /&gt;
 # Based on metaMessage Determines what type of keyshare needs to be send (Ephemeral point or Group key share) and returen it.&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=UpdateNewKeyStatus}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;keyShareMessage&amp;lt;/math&amp;gt;&lt;br /&gt;
 # Update the table of which participant has sent its new ephemeral point or its new group key share&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Hash}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;&lt;br /&gt;
    '''return''' &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''SHA-512&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Main_Page</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Main_Page"/>
				<updated>2014-09-19T21:37:30Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: relink to landing page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''eQualit.ie's whitepapers, documentation and training guides. Free to use and share'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Curricula|a Digital Security Trainer's Curricula]]&lt;br /&gt;
* Online manual on [http://equalit.ie/esecman/index.html Digital Security for Human Rights Defenders]&lt;br /&gt;
* [[Secure hosting guide]]&lt;br /&gt;
* [[Online Learning|Digital Security lessons]]&lt;br /&gt;
* [[MpOTR|mpOTR: multi-party OTR protocol]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [//meta.wikimedia.org/wiki/Help:Contents User's Guide] for information on using the wiki software.&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/MpOTRPages</id>
		<title>MpOTRPages</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/MpOTRPages"/>
				<updated>2014-09-19T21:37:11Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: ask to delete&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;obsolete, sysops please delete&lt;br /&gt;
&lt;br /&gt;
[[Category: Delete]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/Sept9</id>
		<title>Np1sec/Sept9</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/Sept9"/>
				<updated>2014-09-19T21:32:59Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Infinity0 moved page MpOTRSept9 to MpOTR/Meetings/Sept9&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Preliminary agenda for the September 9th meeting in DC.&lt;br /&gt;
&lt;br /&gt;
*Transport assumptions:&lt;br /&gt;
**Investigating properties offered by XMMP-MUC (and cost of considering other protocols)&lt;br /&gt;
**Offering reliable transport (deciding if its part of this protocol or part of the transport layer and implications over transcript consistency)&lt;br /&gt;
&lt;br /&gt;
*Transcript consistency:&lt;br /&gt;
**Choice between simple consistency for globally order messages or incremental for less reliable transport.&lt;br /&gt;
**Figuring out if mpOTR is only responsible for announcing inconsistency or it is also need to try to recover from inconsistency.&lt;br /&gt;
 &lt;br /&gt;
*Consistence view:&lt;br /&gt;
**mpOTR require that member of each session has the same view of the room before the session starts and all see the same text.&lt;br /&gt;
**The DoS attacks that can be applied to consistence room view scenario and its mitigation.&lt;br /&gt;
**The benefit of having a shared key or each individual manages their own key.&lt;br /&gt;
&lt;br /&gt;
By the end of the meeting, final protocol specification should be decided, specifically:&lt;br /&gt;
&lt;br /&gt;
*Simple consistency vs incremental consistency&lt;br /&gt;
*Requiring a consistent view of the room&lt;br /&gt;
*Shared key or independent key &lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/MpOTRSept9</id>
		<title>MpOTRSept9</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/MpOTRSept9"/>
				<updated>2014-09-19T21:32:59Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Infinity0 moved page MpOTRSept9 to MpOTR/Meetings/Sept9&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[MpOTR/Meetings/Sept9]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Talk:MpOTR/Overview</id>
		<title>Talk:MpOTR/Overview</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Talk:MpOTR/Overview"/>
				<updated>2014-09-19T21:29:45Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Infinity0 moved page Talk:MpOTR to Talk:MpOTR/Overview: splitting doc into Overview/Specification&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a threaded discussion list to collate all discourse on protocol creation, adversarial models, et al. Should you wish to contact us directly by email, please use http://equalit.ie/#contact&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Talk:MpOTR</id>
		<title>Talk:MpOTR</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Talk:MpOTR"/>
				<updated>2014-09-19T21:29:45Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Infinity0 moved page Talk:MpOTR to Talk:MpOTR/Overview: splitting doc into Overview/Specification&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Talk:MpOTR/Overview]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/TransportAssumptions</id>
		<title>TransportAssumptions</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/TransportAssumptions"/>
				<updated>2014-09-19T21:28:57Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: content is redundant, repeated elsewhere&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;obsolete, sysops please delete&lt;br /&gt;
&lt;br /&gt;
[[Category: Delete]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-19T21:26:12Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* General concepts */ move ordering/consistency stuff to main page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/Specification</id>
		<title>Np1sec/Specification</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/Specification"/>
				<updated>2014-09-19T21:18:29Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: import content from overview&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Procedures ==&lt;br /&gt;
&lt;br /&gt;
=== Chat setup ===&lt;br /&gt;
&lt;br /&gt;
In almost any practical case, participants join the chat sequentially. It is assumed that multiple participants cannot join simultaneously. For the sake of efficiency one can tweak the implementation to have a threshold to wait and start a chat with more participants. However, this makes the implementation significantly more complicated without an evident efficiency benefit.&lt;br /&gt;
&lt;br /&gt;
Therefore, our assumption is that a secure chat is always set up when a participant starts the chat room. Additional participants would be added sequentially using Algorithm [[mpCAT#VIII.3_Joining|VIII.3]], as they enter the chat. Algorithm [[mpCAT#Chatroom_setup|1]] describes the chat room setup protocol.&lt;br /&gt;
&lt;br /&gt;
====Chatroom setup====&lt;br /&gt;
&amp;lt;!--alg_chat_setup--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Chatroom Init}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;newRoomName&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;participantNick&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;myId := 1&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;Nick_{myId} := participantNick&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;roomName := newRoomName&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;x_{myId}, y_{myId} :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Generate Initial Paramters&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;signatureKey_{myId} := (x_{myId},y_{myId})&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;participantList := [Nick_{myId}]&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;ephemeralPublicPointList := [y_{myId}, y_{other}]&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Joining ===&lt;br /&gt;
&lt;br /&gt;
Joining a chat involves two different procedures: the Join procedure, described in Algorithm [[mpCAT#Join|2]], which runs on the new participant’s instance, and an Accept New Participant Procedure, described in Algorithm [[mpCAT#Protocol_for_other_participants_already_in_the_chat_to_accept_the_newcomer|3]], which runs on the clients of participants that are already in the chat.&lt;br /&gt;
&lt;br /&gt;
When a new participant &amp;lt;math&amp;gt;U_{n+1}&amp;lt;/math&amp;gt; joins the chat, current participants can still use their established authenticated ephemeral public key (to derive the &amp;lt;math&amp;gt;sessionKey_{new}&amp;lt;/math&amp;gt; and as their signature verification key). Confidentiality of &amp;lt;math&amp;gt;sessionKey_{old}&amp;lt;/math&amp;gt; is guarded against the new participant by Diffie-Hellman key shares hashed alongside the session id (which is dependent on the list of participants). The new participant cannot combine the old and new shares to recover &amp;lt;math&amp;gt;sessionKey_{old}&amp;lt;/math&amp;gt;. The fact that old participants do not need to compute new ephemeral keys (and re-verify their ephemeral identities) decreases the computational complexity of the protocol.&lt;br /&gt;
&lt;br /&gt;
====Join====&lt;br /&gt;
&amp;lt;!--alg_join--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Join}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;newRoomName&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Nickname_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;participantId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;myId := participantId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;roomName := newRoomName&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;x_{myId}, y_{myId} := &amp;lt;/math&amp;gt;&amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Generate Initial Paramters&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;signatureKey_{myId} := (x_{myId},y_{myId})&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3Join:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Nickname_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;y_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;participantList, ephemeralPublicPointList :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionId := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Id&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;roomName&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;participantList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPointList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign and Send Key Confirmation and Shares&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyConfirmationShare:3&amp;quot;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;keyShareList, keyConfirmationList, signatureList :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Verify Key Confirmations and Signatures&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyConfirmationList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Receive Session Digest}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;currentSessionHistoryDigest&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionDigest := currentSessionHistoryDigest&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
====Protocol for other participants already in the chat to accept the newcomer====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--alg_accept--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Accept}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;newParticipant&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3Join:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;Nickname_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;y_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3Join:3&amp;quot;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;nick_{NewParticipant}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPoint_{NewParticipant} := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Lists&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;nick_{NewParticipant}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPoint_{NewParticipant}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionId := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Id&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;roomName&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;participantList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPointList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign and Send Key Confirmation and Shares&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyConfirmationShare:3&amp;quot;)&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;keyShareList, keyConfirmationList, signatureList :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Verify Key Confirmations and Signatures&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyConfirmationList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Send&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Sending and receiving messages while joining is in progress ===&lt;br /&gt;
In situations where a prolonged joining process (due to connection problems or malicious activities) has an adverse effect on the user experience, it might be desirable to enable the joining users to communicate with the parties in the room, while maintaining minimum assurances of authenticity, confidentiality, forward secrecy, as well as consistency only among participants.&lt;br /&gt;
&lt;br /&gt;
Consistency aspects of mpCat, both for the room view (plist) and for the transcript, are reached through group agreement. However, there are times when group agreement may be hard or impossible to reach either due to latency in a single participant connection or due to a single participant broadcasting incorrect confirmation data (such as wrong plist, sid, key share, etc).&lt;br /&gt;
&lt;br /&gt;
We offer an extension to the mpCat protocol to tackle this problem during the joining process. When a new participant joins the room, they send their DH key shares to the other participants. The other participants send their ephemeral key in return. They then send their key confirmation and key share. If this extension is to be considered, as soon as each user receives a key confirmation from another user, who is not currently part of the session, mpCat displays a message highlighting the fact that although the user is not part of the session, the conversation is being shared with them (through P2P encryption using the key derived from DH Key). The protocol, however, does not honour their input into the consistency check, until a new session including the new user is set up. Each client can decide whether to disable this option.&lt;br /&gt;
&lt;br /&gt;
The user remains in the list of those not part of the current session, but receives the session messages until a new session is set up. Similarly, when a user receives a message from a user who is not part of the session, mpCat will decrypt the message and display it with a disclaimer that the user is not yet part of the session and that some participants may not receive the same message.&lt;br /&gt;
&lt;br /&gt;
In this model, a room is a forwardly secure authenticated communication channel while a session is a subset of the room, which additionally offers a consistent view&lt;br /&gt;
of the room and consistent messages among participants.&lt;br /&gt;
&lt;br /&gt;
=== Leave ===&lt;br /&gt;
&lt;br /&gt;
Leaving a chatroom involves only one procedure for those who are staying in the chatroom (Procedure Farewell) which is described in Algorithm [[mpCAT#Farewell|4]]. The remaining participants only need a notice from the server that the user is leaving to re-run the one round key update algorithm. Also, failure to receive a heartbeat from a user will result in executing Algorithm [[mpCAT#Farewell|4]] excluding users which did not update their key.&lt;br /&gt;
&lt;br /&gt;
====Farewell====&lt;br /&gt;
&amp;lt;!--alg_farewell--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Shrink on Leave}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;leaverId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''remove''' &amp;lt;math&amp;gt;leaverId&amp;lt;/math&amp;gt; from &amp;lt;math&amp;gt;participantIdList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;sessionId :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Id&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   '''if''' &amp;lt;math&amp;gt;|participantList| &amp;gt; 1&amp;lt;/math&amp;gt;''', then'''&lt;br /&gt;
     &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign and Send Key Shares&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
     &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Wait On Receive&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyShare:3&amp;quot;)&lt;br /&gt;
     &amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Receive&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
     &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Sign and Send Key Shares}}&lt;br /&gt;
 Input: &lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId -1, myId} := Hash(k_{myId,myId-1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId, myId+1} := Hash(k_{myId,myId+1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;keyShare_{myId} := z_{myId -1, myId} \oplus z_{myId, myId+1}&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;originAuthSignature :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519Sign&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;SignatureKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;z_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyShare:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;keyShare_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;)  # we can send this encrypted but leaving person can read it, hence theoretically it is the same as sending it unencrypted.&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Secure Send and Receive ===&lt;br /&gt;
&lt;br /&gt;
After the session key is established, participants will use Algorithms [[mpCAT#Send|5]] and [[mpCAT#Receive|6]] to communicate securely.&lt;br /&gt;
&lt;br /&gt;
On Send, the protocol checks the status of the new ephemeral Diffie-Hellman and key share using messages it receives from participants. It (re)sends any missing pieces. It also informs other participants which part of the key share is received by that user. The metadata flag indicates if the message being sent only contains meta data (e.g. heartbeat) or actual user communication.&lt;br /&gt;
&lt;br /&gt;
On Receive, the protocol updates who has which pieces of the key shares. The protocol also generates a new group key if the new key shares have been received from all participants or those who have not updated their key shares time out on their heartbeat interval.&lt;br /&gt;
&lt;br /&gt;
====Send====&lt;br /&gt;
&amp;lt;!--alg_send--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Send}}&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;metaMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;keyShareMessage&amp;lt;/math&amp;gt; = &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''NewKeyShareMessage&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;metaMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;math&amp;gt;cryptMessage&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''AES CTR Encrypt&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionKey&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;message | keyShareMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519Sign&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;SignatureKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;cryptMetatMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt; := &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Compute Session Digest&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;lastMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3&amp;quot;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;cryptMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;,&amp;quot;:3&amp;quot;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
====Receive====&lt;br /&gt;
&amp;lt;!--alg_recv--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Receive}}&lt;br /&gt;
Input: &amp;lt;math&amp;gt;sender&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;encryptedMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;v := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519VerifySignature&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;ephemeralPublicKeyList[Sender]&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId || encryptedMessage&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Assert&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;) or '''return''' Reject&lt;br /&gt;
   &amp;lt;math&amp;gt;message, keyShareMessage :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''AES CTR Decrypt&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;encryptedMessage&amp;lt;/math&amp;gt;){}&lt;br /&gt;
   &amp;lt;math&amp;gt;isMetaMessage = &amp;lt;/math&amp;gt;&amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''UpdateNewKeyStatus&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;keyShareMessage&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Verify Digests&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionDiges&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''return'''{&amp;lt;math&amp;gt;isMetaMessage, message&amp;lt;/math&amp;gt;}  # isMetaMessage is true if the message is purely meta message and there is nothing to display&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
=== Common functions ===&lt;br /&gt;
&lt;br /&gt;
====Common functions used by other procedures in different stages====&lt;br /&gt;
&amp;lt;!--alg_comm--&amp;gt;&lt;br /&gt;
{{algorithm-begin|name=Generate Initial Paramters}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;signaturePrivateKey := &amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''RandomBits&amp;lt;/span&amp;gt;'''(256)&lt;br /&gt;
   &amp;lt;math&amp;gt;x_{myId} :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Ed25519 Scalar&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;signaturePrivateKey&amp;lt;/math&amp;gt;)) #{This is both Diffie-Hellman secret and ephemeral signature private key}&lt;br /&gt;
   &amp;lt;math&amp;gt;y_{myId} := x_{myId}P&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;math&amp;gt;x,y&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Verify Key Confirmation and Signatures}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;keyConfirmationList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;participant \in participantList&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
     '''if''' &amp;lt;math&amp;gt;keyConfirmationList[participant][myId] \neq Hash(k_{myId,participant} , U_{myId} )&amp;lt;/math&amp;gt;''', then'''&lt;br /&gt;
       &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Halt&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
     '''else''' '''if''' &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519VerifySignature&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;ephemeralPublicKeyList[particicpant]&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId | keyShares[myId]&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;) = Fail ''', then'''&lt;br /&gt;
       &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Halt&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Compute Session Id}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;participantList&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;ephemeralPublicPointList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;math&amp;gt;Hash(roomName, zip(participantList, ephemeralPublicPointList))&amp;lt;/math&amp;gt;  # &amp;lt;math&amp;gt;zip([a,b],[c,d]):=[(a,c),(b,d)]&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Verify Signatures}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;longPublicList&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;schnorrRandomPointList&amp;lt;/math&amp;gt;, &lt;br /&gt;
 # standard signature verification&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Sign and Send Key Confirmation and Share}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;schnorrRandomPointList&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;participant \in participantList&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
     &amp;lt;math&amp;gt;k_{myId, participant} := Hash(x_{myId}LP_{participant} |lp_{myId}y_{participant} | x_{myId}y_{participant})&amp;lt;/math&amp;gt;  # Triple DH&lt;br /&gt;
     &amp;lt;math&amp;gt;kc_{myId} := kc_{myId} | Hash(k_{myId,participant}, U_{participant})&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId -1, myId} := Hash(k_{myId,myId-1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''global''' &amp;lt;math&amp;gt;z_{myId, myId+1} := Hash(k_{myId,myId+1}, sessionId)&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;keyShare_{myId} := z_{myId -1, myId} \oplus z_{myId, myId+1}&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;originAuthSignature :=&amp;lt;/math&amp;gt; &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''ED25519Sign&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;SignatureKey&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;sessionId&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;z_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3KeyConfirmationAndShare:3&amp;quot;, &amp;lt;math&amp;gt;myId&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;keyShare_{myId}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;originAuthSignature&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;kc_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Update Session Key}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;i := myId&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;{j \in [i,...,i+n-1]}&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
      &amp;lt;math&amp;gt;z_{j,j+1} := z_{j-1,j} \oplus keyShareListe[j+1]&amp;lt;/math&amp;gt;&lt;br /&gt;
     # recovered &amp;lt;math&amp;gt;z_{i-1,i}&amp;lt;/math&amp;gt; should be equal to its original value&lt;br /&gt;
    '''global''' &amp;lt;math&amp;gt;sessionKey := Hash(z_{j,j+1} | j \in [1...n])&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Sign Params Update Session Key}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;toBeSigned&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;signatureList&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;keyShareList&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Update Session Key&amp;lt;/span&amp;gt;'''()&lt;br /&gt;
   &amp;lt;math&amp;gt;toBeSigned := Hash(sessionId, ||Hash(verifierList, ephemeralPublicPointList, keyShareList)))&amp;lt;/math&amp;gt;&lt;br /&gt;
   &amp;lt;math&amp;gt;signature_{myId} := &amp;lt;/math&amp;gt;&amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Sign Session and Send&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;toBeSigned&amp;lt;/math&amp;gt;)&lt;br /&gt;
   &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''Broadcast&amp;lt;/span&amp;gt;'''(&amp;quot;:3mpCAT:3SignedSessionParameters:3&amp;quot;,&amp;lt;math&amp;gt;signature_{myId}&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=ComputeSessionDigest}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;lastMessage&amp;lt;/math&amp;gt;&lt;br /&gt;
   '''for each''' &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt; in Messages Received from &amp;lt;math&amp;gt;lastDigestedMessage&amp;lt;/math&amp;gt;+1 till &amp;lt;math&amp;gt;lastMessage&amp;lt;/math&amp;gt;, '''do'''&lt;br /&gt;
      &amp;lt;math&amp;gt;sesionDigest := Hass(sessionDigest, message)&amp;lt;/math&amp;gt; &lt;br /&gt;
      &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''LRU Cache Store Digest&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;)&lt;br /&gt;
   '''return''' &amp;lt;math&amp;gt;sessionDigest&amp;lt;/math&amp;gt;,&amp;lt;math&amp;gt;lastMessageId&amp;lt;/math&amp;gt;&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=NewKeyShareMessage}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;metaMessage&amp;lt;/math&amp;gt;&lt;br /&gt;
 # Based on metaMessage Determines what type of keyshare needs to be send (Ephemeral point or Group key share) and returen it.&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=UpdateNewKeyStatus}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;keyShareMessage&amp;lt;/math&amp;gt;&lt;br /&gt;
 # Update the table of which participant has sent its new ephemeral point or its new group key share&lt;br /&gt;
{{algorithm-end}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{algorithm-begin|name=Hash}}&lt;br /&gt;
 Input: &amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;&lt;br /&gt;
    '''return''' &amp;lt;span style=&amp;quot;font-family: serif; font-size: larger; font-variant:small-caps;&amp;quot;&amp;gt;'''SHA-512&amp;lt;/span&amp;gt;'''(&amp;lt;math&amp;gt;message&amp;lt;/math&amp;gt;)&lt;br /&gt;
{{algorithm-end}}&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-17T18:45:28Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Consistency */ expand discussion of farewell case&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
To summarise: we assume the central server reliably delivers messages to everyone, including the original sender, in the same order. (Discussion of potential failures and recovery will be covered elsewhere.)&lt;br /&gt;
&lt;br /&gt;
Each message has an implicit server-sequence-number (&amp;quot;seqnum&amp;quot;), a receive-parent (&amp;quot;recv-parent&amp;quot; or &amp;quot;parent&amp;quot;) and a sender-sequence-number (&amp;quot;own-seqnum&amp;quot;). Semantics of these is covered elsewhere.&lt;br /&gt;
&lt;br /&gt;
Once a message m is received from the server (including own messages sent), a &amp;quot;transcript-hash&amp;quot; may be calculated for it, that commits to that message and all previous messages in the server-dictated order. This consists of:&lt;br /&gt;
&lt;br /&gt;
* all messages seen by the sender when they sent m, namely:&lt;br /&gt;
** &amp;quot;recv-parent&amp;quot; p and messages with seqnum earlier than p&lt;br /&gt;
** all messages sent by the same sender (messages with own-seqnum earlier than m)&lt;br /&gt;
* ''as well as'' all messages inserted by the server, into the server-ordering between p and m&lt;br /&gt;
&lt;br /&gt;
When a new message is sent, the transcript-hash of its recv-parent is included with it.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
Once ''m'' is fully-acked, ''u'' knows that everyone else has seen ''m'' and all messages before it. We'll call the process of gaining that knowledge, &amp;quot;reaching consistency for ''m''&amp;quot; (given context, ''m'' might be implicit). We don't have another mechanism for it, so henceforth we'll use &amp;quot;reach consistency&amp;quot; interchangeably with &amp;quot;reach full-ack&amp;quot;, though strictly the former is a security property and the latter is a mechanism for achieving it.&lt;br /&gt;
&lt;br /&gt;
An '''explicit-ack''' is a message with no user content, that is sent solely for the purpose of declaring (via recv-parent) what the sender has seen. We'll make use of these to ensure consistency is reached in a timely manner, even if no-one wants to send a normal message (that contains user-level contents, and which is an '''implicit-ack''').&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
We consider two cases: (a) reaching consistency for arbitrary messages during the course of a conversation, and (b) reaching consistency when a user ''u'' leaves. Case (b) may be viewed as a special instance of case (a) plus the additional premise that ''u'' must reach consistency as soon as possible (because they want to leave), and that they don't care about reaching consistency for any subsequent messages that they might receive after their final &amp;quot;farewell&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
Case '''(a)''': when a member ''u'' accepts a non-explicit-ack message ''m'' at time ''t'':&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
Case '''(b)''': when a member ''u'' wants to part, they send a &amp;quot;farewell&amp;quot; message ''m'':&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack ''m'' as soon as they receive it from the server.&lt;br /&gt;
** This ack may also bundle any cryptographic material needed for other members to agree on a key or keys that exclude ''u''. For example, in the SenderKeys scenario, this would contain the next sender-key, encrypted to everyone except ''u''.&lt;br /&gt;
* When ''m'' is fully-acked, ''u'' reaches consistency for all previous messages up to ''m'', and may leave.&lt;br /&gt;
* Messages that others send to ''u'' that are echoed back after ''m'', will not be acked by ''u''.&lt;br /&gt;
** ''u'' won't have a chance to reach consistency for these messages, even if ''u'' receives them.&lt;br /&gt;
** Others won't have a chance to check that ''u'' read them, though they may be able to check that everyone else did. But ''u'' may still read them in theory, since they were encrypted to ''u''.&lt;br /&gt;
** In either case, communicating this meaning to the user, should be already covered by the same UI as for case (a). In the first case, ''u'' may shortcut the timeout and just issue the warning straight away, or alternatively not display those messages to the user at all.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-17T18:36:37Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Definitions */ make more precise, in the section below explicit-acks might bundle extra crypto material&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
To summarise: we assume the central server reliably delivers messages to everyone, including the original sender, in the same order. (Discussion of potential failures and recovery will be covered elsewhere.)&lt;br /&gt;
&lt;br /&gt;
Each message has an implicit server-sequence-number (&amp;quot;seqnum&amp;quot;), a receive-parent (&amp;quot;recv-parent&amp;quot; or &amp;quot;parent&amp;quot;) and a sender-sequence-number (&amp;quot;own-seqnum&amp;quot;). Semantics of these is covered elsewhere.&lt;br /&gt;
&lt;br /&gt;
Once a message m is received from the server (including own messages sent), a &amp;quot;transcript-hash&amp;quot; may be calculated for it, that commits to that message and all previous messages in the server-dictated order. This consists of:&lt;br /&gt;
&lt;br /&gt;
* all messages seen by the sender when they sent m, namely:&lt;br /&gt;
** &amp;quot;recv-parent&amp;quot; p and messages with seqnum earlier than p&lt;br /&gt;
** all messages sent by the same sender (messages with own-seqnum earlier than m)&lt;br /&gt;
* ''as well as'' all messages inserted by the server, into the server-ordering between p and m&lt;br /&gt;
&lt;br /&gt;
When a new message is sent, the transcript-hash of its recv-parent is included with it.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
Once ''m'' is fully-acked, ''u'' knows that everyone else has seen ''m'' and all messages before it. We'll call the process of gaining that knowledge, &amp;quot;reaching consistency for ''m''&amp;quot; (given context, ''m'' might be implicit). We don't have another mechanism for it, so henceforth we'll use &amp;quot;reach consistency&amp;quot; interchangeably with &amp;quot;reach full-ack&amp;quot;, though strictly the former is a security property and the latter is a mechanism for achieving it.&lt;br /&gt;
&lt;br /&gt;
An '''explicit-ack''' is a message with no user content, that is sent solely for the purpose of declaring (via recv-parent) what the sender has seen. We'll make use of these to ensure consistency is reached in a timely manner, even if no-one wants to send a normal message (that contains user-level contents, and which is an '''implicit-ack''').&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
We consider two cases: (a) reaching consistency for arbitrary messages during the course of a conversation, and (b) reaching consistency when a user ''u'' leaves. Case (b) may be viewed as a special instance of case (a) plus the additional premise that ''u'' must reach consistency as soon as possible (because they want to leave), and that they don't care about reaching consistency for any subsequent messages that they might receive after their final &amp;quot;farewell&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
Case '''(a)''': when a member ''u'' accepts a non-explicit-ack message ''m'' at time ''t'':&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
Case '''(b)''': when a member ''u'' wants to part, they send a &amp;quot;farewell&amp;quot; message ''m'':&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
Messages that others send to ''u'' that are echoed back after &amp;quot;farewell&amp;quot; will not be acked by ''u'', therefore should not be shown as &amp;quot;seen/acked by u&amp;quot;. However, ''u'' may still read them in theory, since they were encrypted to ''u''. Communicating this meaning should be already covered by the same thing as for case (a), though.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-17T18:24:30Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Definitions */ define an explicit-ack&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
To summarise: we assume the central server reliably delivers messages to everyone, including the original sender, in the same order. (Discussion of potential failures and recovery will be covered elsewhere.)&lt;br /&gt;
&lt;br /&gt;
Each message has an implicit server-sequence-number (&amp;quot;seqnum&amp;quot;), a receive-parent (&amp;quot;recv-parent&amp;quot; or &amp;quot;parent&amp;quot;) and a sender-sequence-number (&amp;quot;own-seqnum&amp;quot;). Semantics of these is covered elsewhere.&lt;br /&gt;
&lt;br /&gt;
Once a message m is received from the server (including own messages sent), a &amp;quot;transcript-hash&amp;quot; may be calculated for it, that commits to that message and all previous messages in the server-dictated order. This consists of:&lt;br /&gt;
&lt;br /&gt;
* all messages seen by the sender when they sent m, namely:&lt;br /&gt;
** &amp;quot;recv-parent&amp;quot; p and messages with seqnum earlier than p&lt;br /&gt;
** all messages sent by the same sender (messages with own-seqnum earlier than m)&lt;br /&gt;
* ''as well as'' all messages inserted by the server, into the server-ordering between p and m&lt;br /&gt;
&lt;br /&gt;
When a new message is sent, the transcript-hash of its recv-parent is included with it.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
Once ''m'' is fully-acked, ''u'' knows that everyone else has seen ''m'' and all messages before it. We'll call the process of gaining that knowledge, &amp;quot;reaching consistency for ''m''&amp;quot; (given context, ''m'' might be implicit). We don't have another mechanism for it, so henceforth we'll use &amp;quot;reach consistency&amp;quot; interchangeably with &amp;quot;reach full-ack&amp;quot;, though strictly the former is a security property and the latter is a mechanism for achieving it.&lt;br /&gt;
&lt;br /&gt;
An '''explicit-ack''' is a message with no other content, that is sent solely for the purpose of declaring (via recv-parent) what the sender has seen. We'll make use of these to ensure consistency is reached in a timely manner, even if no-one wants to send a normal message (that contains user-level contents, and which is an '''implicit-ack''').&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
We consider two cases: (a) reaching consistency for arbitrary messages during the course of a conversation, and (b) reaching consistency when a user ''u'' leaves. Case (b) may be viewed as a special instance of case (a) plus the additional premise that ''u'' must reach consistency as soon as possible (because they want to leave), and that they don't care about reaching consistency for any subsequent messages that they might receive after their final &amp;quot;farewell&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
Case '''(a)''': when a member ''u'' accepts a non-explicit-ack message ''m'' at time ''t'':&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
Case '''(b)''': when a member ''u'' wants to part, they send a &amp;quot;farewell&amp;quot; message ''m'':&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
Messages that others send to ''u'' that are echoed back after &amp;quot;farewell&amp;quot; will not be acked by ''u'', therefore should not be shown as &amp;quot;seen/acked by u&amp;quot;. However, ''u'' may still read them in theory, since they were encrypted to ''u''. Communicating this meaning should be already covered by the same thing as for case (a), though.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-17T17:56:34Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Consistency */ give a summary of the overall consistency strategy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
To summarise: we assume the central server reliably delivers messages to everyone, including the original sender, in the same order. (Discussion of potential failures and recovery will be covered elsewhere.)&lt;br /&gt;
&lt;br /&gt;
Each message has an implicit server-sequence-number (&amp;quot;seqnum&amp;quot;), a receive-parent (&amp;quot;recv-parent&amp;quot; or &amp;quot;parent&amp;quot;) and a sender-sequence-number (&amp;quot;own-seqnum&amp;quot;). Semantics of these is covered elsewhere.&lt;br /&gt;
&lt;br /&gt;
Once a message m is received from the server (including own messages sent), a &amp;quot;transcript-hash&amp;quot; may be calculated for it, that commits to that message and all previous messages in the server-dictated order. This consists of:&lt;br /&gt;
&lt;br /&gt;
* all messages seen by the sender when they sent m, namely:&lt;br /&gt;
** &amp;quot;recv-parent&amp;quot; p and messages with seqnum earlier than p&lt;br /&gt;
** all messages sent by the same sender (messages with own-seqnum earlier than m)&lt;br /&gt;
* ''as well as'' all messages inserted by the server, into the server-ordering between p and m&lt;br /&gt;
&lt;br /&gt;
When a new message is sent, the transcript-hash of its recv-parent is included with it.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
Once ''m'' is fully-acked, ''u'' knows that everyone else has seen ''m'' and all messages before it. We'll call the process of gaining that knowledge, &amp;quot;reaching consistency for ''m''&amp;quot; (given context, ''m'' might be implicit). We don't have another mechanism for it, so henceforth we'll use &amp;quot;reach consistency&amp;quot; interchangeably with &amp;quot;reach full-ack&amp;quot;, though strictly the former is a security property and the latter is a mechanism for achieving it.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
We consider two cases: (a) reaching consistency for arbitrary messages during the course of a conversation, and (b) reaching consistency when a user ''u'' leaves. Case (b) may be viewed as a special instance of case (a) plus the additional premise that ''u'' must reach consistency as soon as possible (because they want to leave), and that they don't care about reaching consistency for any subsequent messages that they might receive after their final &amp;quot;farewell&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
Case '''(a)''': when a member ''u'' accepts a non-explicit-ack message ''m'' at time ''t'':&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
Case '''(b)''': when a member ''u'' wants to part, they send a &amp;quot;farewell&amp;quot; message ''m'':&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
Messages that others send to ''u'' that are echoed back after &amp;quot;farewell&amp;quot; will not be acked by ''u'', therefore should not be shown as &amp;quot;seen/acked by u&amp;quot;. However, ''u'' may still read them in theory, since they were encrypted to ''u''. Communicating this meaning should be already covered by the same thing as for case (a), though.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-17T17:37:07Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Definitions */ more precise definition with explicit qualifier&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
To summarise: we assume the central server reliably delivers messages to everyone, including the original sender, in the same order. (Discussion of potential failures and recovery will be covered elsewhere.)&lt;br /&gt;
&lt;br /&gt;
Each message has an implicit server-sequence-number (&amp;quot;seqnum&amp;quot;), a receive-parent (&amp;quot;recv-parent&amp;quot; or &amp;quot;parent&amp;quot;) and a sender-sequence-number (&amp;quot;own-seqnum&amp;quot;). Semantics of these is covered elsewhere.&lt;br /&gt;
&lt;br /&gt;
Once a message m is received from the server (including own messages sent), a &amp;quot;transcript-hash&amp;quot; may be calculated for it, that commits to that message and all previous messages in the server-dictated order. This consists of:&lt;br /&gt;
&lt;br /&gt;
* all messages seen by the sender when they sent m, namely:&lt;br /&gt;
** &amp;quot;recv-parent&amp;quot; p and messages with seqnum earlier than p&lt;br /&gt;
** all messages sent by the same sender (messages with own-seqnum earlier than m)&lt;br /&gt;
* ''as well as'' all messages inserted by the server, into the server-ordering between p and m&lt;br /&gt;
&lt;br /&gt;
When a new message is sent, the transcript-hash of its recv-parent is included with it.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
Once ''m'' is fully-acked, ''u'' knows that everyone else has seen ''m'' and all messages before it. We'll call the process of gaining that knowledge, &amp;quot;reaching consistency for ''m''&amp;quot; (given context, ''m'' might be implicit). We don't have another mechanism for it, so henceforth we'll use &amp;quot;reach consistency&amp;quot; interchangeably with &amp;quot;reach full-ack&amp;quot;, though strictly the former is a security property and the latter is a mechanism for achieving it.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t:&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-17T17:04:08Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Definitions */ add a background section for context, and extend definitions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
To summarise: we assume the central server reliably delivers messages to everyone, including the original sender, in the same order. (Discussion of potential failures and recovery will be covered elsewhere.)&lt;br /&gt;
&lt;br /&gt;
Each message has an implicit server-sequence-number (&amp;quot;seqnum&amp;quot;), a receive-parent (&amp;quot;recv-parent&amp;quot; or &amp;quot;parent&amp;quot;) and a sender-sequence-number (&amp;quot;own-seqnum&amp;quot;). Semantics of these is covered elsewhere.&lt;br /&gt;
&lt;br /&gt;
Once a message m is received from the server (including own messages sent), a &amp;quot;transcript-hash&amp;quot; may be calculated for it, that commits to that message and all previous messages in the server-dictated order. This consists of:&lt;br /&gt;
&lt;br /&gt;
* all messages seen by the sender when they sent m, namely:&lt;br /&gt;
** &amp;quot;recv-parent&amp;quot; p and messages with seqnum earlier than p&lt;br /&gt;
** all messages sent by the same sender (messages with own-seqnum earlier than m)&lt;br /&gt;
* ''as well as'' all messages inserted by the server, into the server-ordering between p and m&lt;br /&gt;
&lt;br /&gt;
When a new message is sent, the transcript-hash of its recv-parent is included with it.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
Once ''m'' is fully-acked, ''u'' knows that everyone else has seen ''m'' and all messages before it. We'll call the process of gaining that knowledge, &amp;quot;reaching consistency&amp;quot;. We don't have another mechanism for it, so henceforth we'll use &amp;quot;reach consistency&amp;quot; interchangeably with &amp;quot;reach full-ack&amp;quot;, though strictly the former is a security property and the latter is a mechanism for achieving it.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t:&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/incremental_consistency/Using_blockchain_for_ack/reply</id>
		<title>Thread:Talk:MpOTR/incremental consistency/Using blockchain for ack/reply</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/incremental_consistency/Using_blockchain_for_ack/reply"/>
				<updated>2014-09-12T13:11:45Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Reply to Using blockchain for ack&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;How does this relate to what is written on either this page or the SenderKeys page?&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/incremental_consistency/Sequence_number_to_float_decimal/reply</id>
		<title>Thread:Talk:MpOTR/incremental consistency/Sequence number to float decimal/reply</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/incremental_consistency/Sequence_number_to_float_decimal/reply"/>
				<updated>2014-09-12T13:10:58Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Reply to Sequence number to float decimal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Which sequence number are you referring to?&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-08T19:08:18Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Relative ordering */ tone down the terminology, &amp;quot;unsynced&amp;quot; sounds too severe&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t:&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''badly ordered'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-08T19:03:34Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: explain overhead reduction in more detail&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* Everyone should explicit-ack this message ASAP&lt;br /&gt;
** This message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. This ensures old members can't read new messages even if they eavesdrop.&lt;br /&gt;
** (We could probably do something similar for group keys.)&lt;br /&gt;
* When this message is fully-acked, u gains consistency for all previous messages up to m, and may leave.&lt;br /&gt;
** Other messages should be probably be discarded - u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t:&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
The above checks should be applied for every single message. This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, and works even if people don't manually send messages.&lt;br /&gt;
&lt;br /&gt;
If we set ACK_GRACE_INTERVAL high enough to match the typical interval between a user's messages, then (in theory) the overhead is only incurred once everyone stops talking and we automatically send off one extra round of acks. While the lull in activity continues, there will be no extra messages, since we don't require explicit-acks to be fully-acked themselves. (Preliminary experiments on some code I wrote shows this to be effective.)&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''unsynced'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-08T18:54:21Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: greater-than-or-equals is correct&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;ge; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* everyone should explicit-ack this message ASAP&lt;br /&gt;
** this message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. (Hopefully this addresses the concern Joe brought up.)&lt;br /&gt;
** could probably do something similar for group keys&lt;br /&gt;
* when this message is fully-acked, u gains consistency for all previous messages up to m, and may leave&lt;br /&gt;
** other messages should be probably be discarded, u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, ensuring timeliness.&lt;br /&gt;
&lt;br /&gt;
In terms of overhead, effectively a user will send a message at least every ACK_GRACE_INTERVAL time period, whilst the session has other people talking. When there is a lull in the conversation, there should be no further messages.&lt;br /&gt;
&lt;br /&gt;
I'm confident we can tweak the parameters so servers don't see too much extra load, but have not tried to model this precisely.&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''unsynced'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-08T18:53:27Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: simplify; k is unnessary, the parameters are already generous&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;gt; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* everyone should explicit-ack this message ASAP&lt;br /&gt;
** this message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. (Hopefully this addresses the concern Joe brought up.)&lt;br /&gt;
** could probably do something similar for group keys&lt;br /&gt;
* when this message is fully-acked, u gains consistency for all previous messages up to m, and may leave&lt;br /&gt;
** other messages should be probably be discarded, u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+ACK_GRACE_INTERVAL, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*BROADCAST_LATENCY)+ACK_GRACE_INTERVAL then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* BROADCAST_LATENCY should be based on the transport.&lt;br /&gt;
* ACK_GRACE_INTERVAL should be based on expected user communication rate.&lt;br /&gt;
&lt;br /&gt;
Both of these should be defined to cover common cases (e.g. 95th-percentile) rather than being mean values.&lt;br /&gt;
&lt;br /&gt;
This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, ensuring timeliness.&lt;br /&gt;
&lt;br /&gt;
In terms of overhead, effectively a user will send a message at least every ACK_GRACE_INTERVAL time period, whilst the session has other people talking. When there is a lull in the conversation, there should be no further messages.&lt;br /&gt;
&lt;br /&gt;
I'm confident we can tweak the parameters so servers don't see too much extra load, but have not tried to model this precisely.&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''unsynced'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T18:48:09Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Transcript hashes */ explain the nuance wrt message-ID (&amp;quot;commit ID&amp;quot;) here&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  We assume that the server is unaware of sequence numbers (e.g. XMPP MUC); clients must allocate them implicitly when receiving messages.&lt;br /&gt;
&lt;br /&gt;
This version of the spec does ''not'' support servers that give explicit sequence numbers to messages; this would force us to handle the case where messages are received with explicitly out-of-order sequence numbers. For now, we rely on transcript consistency to detect out-of-order messages for the ''implicit'' sequence number case.&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server. This is because the server may validly insert messages between parent(A) and A, in which case parent(B) being A would contradict the semantics we just stated.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the sending client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;amp;hArr; seqnum(A) &amp;amp;le; seqnum(B) &amp;amp;hArr; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
Note that we defined H(parent) rather than H(message). This is because a hash may only be calculated once the subject is actually received back from the server (i.e. gets a sequence number). This differs from some other concepts of &amp;quot;message ID&amp;quot; that may be calculated locally.&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-08T18:46:15Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: use more concise notation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' where seqnum(parent(r)) &amp;amp;gt; seqnum(m).&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all causally-previous messages must already be accepted&lt;br /&gt;
** we assume a server-dictated ordering, so accepting a message at seqnum i means we have already accepted all messages j &amp;amp;le; i.&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* everyone should explicit-ack this message ASAP&lt;br /&gt;
** this message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. (Hopefully this addresses the concern Joe brought up.)&lt;br /&gt;
** could probably do something similar for group keys&lt;br /&gt;
* when this message is fully-acked, u gains consistency for all previous messages up to m, and may leave&lt;br /&gt;
** other messages should be probably be discarded, u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+MAX_GRACE, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*MAX_RTT)+(k*MAX_GRACE) (k slightly &amp;gt; 1) then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT should be based on the transport&lt;br /&gt;
* MAX_GRACE should be based on expected user communication rate&lt;br /&gt;
&lt;br /&gt;
This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, ensuring timeliness.&lt;br /&gt;
&lt;br /&gt;
In terms of overhead, effectively a user will send a message at least every MAX_GRACE time period, whilst the session has other people talking. When there is a lull in the conversation, there should be no further messages.&lt;br /&gt;
&lt;br /&gt;
I'm confident we can tweak the parameters so servers don't see too much extra load, but have not tried to model this precisely.&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''unsynced'' if seqnum(parent(m)) &amp;lt; seqnum(m) - MAX_UNSYNC_COUNT&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages; the user should just be informed that they refer to older context that may be surprising.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T18:21:19Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Causal order */ explain why we can't just set parent(B) == A&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  We assume that the server is unaware of sequence numbers (e.g. XMPP MUC); clients must allocate them implicitly when receiving messages.&lt;br /&gt;
&lt;br /&gt;
This version of the spec does ''not'' support servers that give explicit sequence numbers to messages; this would force us to handle the case where messages are received with explicitly out-of-order sequence numbers. For now, we rely on transcript consistency to detect out-of-order messages for the ''implicit'' sequence number case.&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server. This is because the server may validly insert messages between parent(A) and A, in which case parent(B) being A would contradict the semantics we just stated.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the sending client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;amp;hArr; seqnum(A) &amp;amp;le; seqnum(B) &amp;amp;hArr; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T18:12:04Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Causal order */ clarify who controls ownseqnum&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  We assume that the server is unaware of sequence numbers (e.g. XMPP MUC); clients must allocate them implicitly when receiving messages.&lt;br /&gt;
&lt;br /&gt;
This version of the spec does ''not'' support servers that give explicit sequence numbers to messages; this would force us to handle the case where messages are received with explicitly out-of-order sequence numbers. For now, we rely on transcript consistency to detect out-of-order messages for the ''implicit'' sequence number case.&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the sending client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;amp;hArr; seqnum(A) &amp;amp;le; seqnum(B) &amp;amp;hArr; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:SenderKeys/Transcript_consistency</id>
		<title>Thread:Talk:SenderKeys/Transcript consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:SenderKeys/Transcript_consistency"/>
				<updated>2014-09-08T18:10:12Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: New thread: Transcript consistency&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The stuff about sequence numbers, parent pointers, hashes, should be moved to a separate page, specifically for consistency.&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T18:09:21Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Server order */ clarify implicit sequence numbers&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  We assume that the server is unaware of sequence numbers (e.g. XMPP MUC); clients must allocate them implicitly when receiving messages.&lt;br /&gt;
&lt;br /&gt;
This version of the spec does ''not'' support servers that give explicit sequence numbers to messages; this would force us to handle the case where messages are received with explicitly out-of-order sequence numbers. For now, we rely on transcript consistency to detect out-of-order messages for the ''implicit'' sequence number case.&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;amp;hArr; seqnum(A) &amp;amp;le; seqnum(B) &amp;amp;hArr; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T18:04:08Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Causal order */ fix equiv symbol&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  Sequence numbers are implicit, as the server may not be aware of them (e.g. XMPP MUC).&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;amp;hArr; seqnum(A) &amp;amp;le; seqnum(B) &amp;amp;hArr; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T17:59:37Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Causal order */ fix equiv symbol&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  Sequence numbers are implicit, as the server may not be aware of them (e.g. XMPP MUC).&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;amp;equiv; seqnum(A) &amp;amp;le; seqnum(B) &amp;amp;equiv; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/SenderKeys</id>
		<title>Np1sec/SenderKeys</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/SenderKeys"/>
				<updated>2014-09-08T17:58:47Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: /* Causal order */ a single parent is not enough; add an explicit per-member sequence number and explain why&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Security Goals =&lt;br /&gt;
&lt;br /&gt;
== Transcript consistency ==&lt;br /&gt;
* Recipients are informed of the correct causal order of messages&lt;br /&gt;
* Excessively delayed messages are detected&lt;br /&gt;
&lt;br /&gt;
== Nonblocking join ==&lt;br /&gt;
* Join and leave are treated as messages, so transcript consistency applies (causal order, delays are detected).&lt;br /&gt;
* New users have to &amp;quot;confirm&amp;quot; to existing users to join.&lt;br /&gt;
* Existing users have to &amp;quot;confirm&amp;quot; to the new user shortly after the new user joins (e.g. 1 minute).&lt;br /&gt;
&lt;br /&gt;
= General concepts = &lt;br /&gt;
&lt;br /&gt;
== Room membership ==&lt;br /&gt;
Users can enter and leave the room, as signalled by presence messages from the server (USER_ENTERED, USER_LEFT).&lt;br /&gt;
&lt;br /&gt;
Users can join the room's conversation by sending a JOIN message.&lt;br /&gt;
&lt;br /&gt;
Users can only leave the conversation if the server says they left the room.&lt;br /&gt;
&lt;br /&gt;
== Sender keys and Signing keys ==&lt;br /&gt;
When a new user joins, she generates a new AES256 key (her &amp;quot;sender key&amp;quot;) and Ed25519 key (her &amp;quot;signing key&amp;quot;).  She then sends these keys to existing members, encrypted under the &amp;quot;pairwise keys&amp;quot; from pairwise key agreements.  This allows subsequent messages to be encrypted-and-signed once, instead of N times with pairwise keys.&lt;br /&gt;
&lt;br /&gt;
Every time a message is encrypted or decrypted with a sender key, the key is afterwards updated to provide forward secrecy:&lt;br /&gt;
&lt;br /&gt;
sender_key = HMAC-SHA256(prev_sender_key, &amp;quot;0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
== Server order ==&lt;br /&gt;
All clients see the same message order from the server.  All messages are sent to all users.  Aside from the presence messages sent by the server, messages are sent by users.&lt;br /&gt;
&lt;br /&gt;
All messages in a room have a unique sequence number (0, 1, ...).  Sequence numbers are implicit, as the server may not be aware of them (e.g. XMPP MUC).&lt;br /&gt;
&lt;br /&gt;
A new user synchronizes his view of sequence numbers via the QUERY / MEMBER_LIST messages (see below).&lt;br /&gt;
&lt;br /&gt;
== Causal order ==&lt;br /&gt;
Some (all?) user-sent messages specify a &amp;quot;parent&amp;quot; sequence number which is the last message the user received before sending it.  Note:&lt;br /&gt;
&lt;br /&gt;
* If Alice sends messages (A,B) in a row, A will not be B's parent unless Alice waits till A is received back from the server.&lt;br /&gt;
* The parent of a message is different from the &amp;quot;previous&amp;quot; message in the server's ordering, e.g. in a &amp;quot;simultaneous send&amp;quot; case two messages will have the same parent.&lt;br /&gt;
&lt;br /&gt;
To prevent the server re-ordering (A, B) when they have the same parent, each message also includes an explicit own-sequence-number, incremented by the client themselves.&lt;br /&gt;
&lt;br /&gt;
We must enforce a few invariants. For every pair of messages A, B:&lt;br /&gt;
&lt;br /&gt;
* ownseqnum(A) &amp;amp;le; ownseqnum(B) &amp;lt;=&amp;gt; seqnum(A) &amp;amp;le; seqnum(B) &amp;lt;=&amp;gt; seqnum(parent(A)) &amp;amp;le; seqnum(parent(B)&lt;br /&gt;
&lt;br /&gt;
In practice, and because currently we implicitly allocate seqnums, for each incoming message m we only need to check:&lt;br /&gt;
&lt;br /&gt;
* let p be the latest message received from the same sender (of m). then, check that:&lt;br /&gt;
** ownseqnum(p) == ownseqnum(m) + 1&lt;br /&gt;
** seqnum(parent(p)) &amp;amp;le; seqnum(parent(m))&lt;br /&gt;
* if p doesn't exist, then instead check that ownseqnum(m) == 0&lt;br /&gt;
&lt;br /&gt;
Due to server ordering, the sender of message i must have seen all messages with seqnum between 0...parent(i), as well as all messages m with seqnum between parent(i)...i where ownseqnum(m) &amp;amp;le; ownseqnum(i). Thus, every user-sent message i has a membership set, determined by the JOIN / USER_LEFT messages from 0...i's parent.&lt;br /&gt;
&lt;br /&gt;
== Transcript hashes ==&lt;br /&gt;
Encrypted messages include a &amp;quot;transcript hash&amp;quot; of their parent and all prior messages as &amp;quot;additional authenticated data&amp;quot;.  &lt;br /&gt;
&lt;br /&gt;
The hash also covers the sender_key for DATA messages (set to zeros for all other messages):&lt;br /&gt;
&lt;br /&gt;
H(parent) = SHA256(sender_key[parent] || msg[parent] || H(parent-1))&lt;br /&gt;
&lt;br /&gt;
== Timing ==&lt;br /&gt;
Timing rules can trigger errors based on some assumed constants:&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT - this is the maximum time it should take for a sent message to arrive at all parties.  If you send a message and haven't received it back within MAX_RTT, something is wrong.&lt;br /&gt;
&lt;br /&gt;
* MAX_RTD - this is the maximum difference in time when a message arrives at all parties.  If you receive a message that's not a successor of a message (X) you received more than MAX_RTD + MAX_RTT time ago, something is wrong.  (This is because message X might have arrived at the other party more than MAX_RTD after you saw it, and the other party's message might have taken MAX_RTT to reach you.  But after MAX_RTD + MAX_RTT, there's no excuse for the other party not to have seen X).&lt;br /&gt;
&lt;br /&gt;
* MAX_CONFIRM - this is the maximum time an existing member may spend after receiving a new user's JOIN message before sending a CONFIRM message in response.  If the new user hasn't received CONFIRM messages from existing membership within 2*MAX_RTT + MAX_CONFIRM, something is wrong.&lt;br /&gt;
&lt;br /&gt;
= Messages = &lt;br /&gt;
&lt;br /&gt;
== Generic structures ==&lt;br /&gt;
&lt;br /&gt;
=== Certificate ===&lt;br /&gt;
* The user's Curve25519 identity public key&lt;br /&gt;
* The user's Curve25519 ephemeral public key&lt;br /&gt;
* An Ed25519 signature from the identity key over the ephemeral key&lt;br /&gt;
   (Ed25519 signatures can be produced from Curve25519 keys)&lt;br /&gt;
&lt;br /&gt;
== Server messages ==&lt;br /&gt;
&lt;br /&gt;
=== USER_ENTERED, USER_LEFT ===&lt;br /&gt;
* &amp;quot;Presence&amp;quot; messages sent in clear by the server to indicate a user has entered or left the room&lt;br /&gt;
&lt;br /&gt;
== User messages ==&lt;br /&gt;
&lt;br /&gt;
=== QUERY ===&lt;br /&gt;
* Contains a nonce&lt;br /&gt;
* Requests a MEMBER_LIST&lt;br /&gt;
&lt;br /&gt;
=== MEMBER_LIST ===&lt;br /&gt;
* Contains the sequence number and nonce of the QUERY it's responding to&lt;br /&gt;
* Contains the transcript hash for the QUERY&lt;br /&gt;
* Contains a certificate for each member as of the QUERY&lt;br /&gt;
&lt;br /&gt;
=== JOIN ===&lt;br /&gt;
* Contains a certificate for the new member&lt;br /&gt;
* Contains the sequence number of the MEMBER_LIST it's responding to&lt;br /&gt;
&lt;br /&gt;
=== CONFIRM ===&lt;br /&gt;
* Encrypts-and-confirms an AES256 &amp;quot;sender key&amp;quot; and Ed25519 &amp;quot;signing key&amp;quot; from one member to another&lt;br /&gt;
* Uses pairwise TripleDH between sender and recipient keys, i.e.&lt;br /&gt;
   HASH( DH(A_id, B_eph) || DH(A_eph, B_id) || DH(A_eph, B_eph) )&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== DATA === &lt;br /&gt;
* Encrypted under the sender's &amp;quot;sender key&amp;quot;&lt;br /&gt;
* Ed25519 signature from the sender's signing key&lt;br /&gt;
* Contains the sequence number for its parent&lt;br /&gt;
* The transcript hash and membership of its parent is included as &amp;quot;additional authenticated data&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Algorithms = &lt;br /&gt;
&lt;br /&gt;
== Blocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If two users try to join simultaneously, the second QUERY will not be responded to until the first user has finished joining.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing a new sender key.&lt;br /&gt;
&lt;br /&gt;
Until the new user has finished joining, existing members continue exchanging DATA with their old sender keys.  Once the last confirmation has been received, existing users switch to their new sender keys.&lt;br /&gt;
&lt;br /&gt;
Once the new user has received all CONFIRM messages from the existing membership, she is successfully joined.  If other users sent a QUERY in the meantime, the next one will be responded to with a MEMBER_LIST.&lt;br /&gt;
&lt;br /&gt;
== Nonblocking Join ==&lt;br /&gt;
On entering a room, a user sends a QUERY.  Someone will respond with a MEMBER_LIST.  If multiple users try to join simultaneously, they will all be responded to immediately.&lt;br /&gt;
&lt;br /&gt;
On receiving a MEMBER_LIST, the new user learns the membership, transcript hash, and sequence number for the QUERY message.  To finish joining, the new user sends a JOIN, including a CONFIRM for each existing member.  Each member will respond to her JOIN message with a CONFIRM, containing their current sender key.&lt;br /&gt;
&lt;br /&gt;
The new user is part of the group once her JOIN message is received.  This means that DATA can be sent between group members who have not yet confirmed each other.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Np1sec/incremental_consistency</id>
		<title>Np1sec/incremental consistency</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Np1sec/incremental_consistency"/>
				<updated>2014-09-08T17:31:18Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This builds on the server-dictated ordered transcript hashes currently mentioned in [[SenderKeys]].&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
A message m is '''fully-acked''' (from the POV of a given member ''u'') iff, for all recipients ''r'', ''u'' has accepted a message by ''r'' whose sender-parent is &amp;amp;ge; m's seqnum.&lt;br /&gt;
&lt;br /&gt;
* ''recipients'' possibly includes u, but certainly excludes m's sender&lt;br /&gt;
* ''accepted'' means delivered locally, i.e. received, then decrypted-verified including parent hash checks; all previous messages must already be accepted&lt;br /&gt;
&lt;br /&gt;
== Consistency ==&lt;br /&gt;
&lt;br /&gt;
When a member u wants to part, they send a &amp;quot;farewell&amp;quot; message m:&lt;br /&gt;
&lt;br /&gt;
* everyone should explicit-ack this message ASAP&lt;br /&gt;
** this message should contain the next-sender-key, to be used after u leaves, encrypted to everyone except u. (Hopefully this addresses the concern Joe brought up.)&lt;br /&gt;
** could probably do something similar for group keys&lt;br /&gt;
* when this message is fully-acked, u gains consistency for all previous messages up to m, and may leave&lt;br /&gt;
** other messages should be probably be discarded, u won't have a chance to verify their consistency.&lt;br /&gt;
* TBD: need to think about simultaneous parts&lt;br /&gt;
&lt;br /&gt;
When a member u accepts a non-explicit-ack message m at time t&lt;br /&gt;
&lt;br /&gt;
* if u did not send m, and they have not acked m by t+MAX_GRACE, they should send an explicit-ack&lt;br /&gt;
* if m is not fully-acked (from their POV) by t+(2*MAX_RTT)+(k*MAX_GRACE) (k slightly &amp;gt; 1) then issue a local UI warning. Cancel the warning if/when full-ack is reached later.&lt;br /&gt;
&lt;br /&gt;
=== Parameters and properties ===&lt;br /&gt;
&lt;br /&gt;
* MAX_RTT should be based on the transport&lt;br /&gt;
* MAX_GRACE should be based on expected user communication rate&lt;br /&gt;
&lt;br /&gt;
This guarantees that a warning shows up if we don't reach consistency within the timeout defined above, ensuring timeliness.&lt;br /&gt;
&lt;br /&gt;
In terms of overhead, effectively a user will send a message at least every MAX_GRACE time period, whilst the session has other people talking. When there is a lull in the conversation, there should be no further messages.&lt;br /&gt;
&lt;br /&gt;
I'm confident we can tweak the parameters so servers don't see too much extra load, but have not tried to model this precisely.&lt;br /&gt;
&lt;br /&gt;
We are still vulnerable to a &amp;quot;drop everything&amp;quot; attack, but that can't be helped unless we have unconditionally-periodic heartbeats. Not sure if we want to put these in the upcoming spec.&lt;br /&gt;
&lt;br /&gt;
(The above is basically my msg-notes stuff, except assuming reliable transport, without recovery or flow control, without heartbeats, and adapted to a server-dictated ordering.)&lt;br /&gt;
&lt;br /&gt;
== Relative ordering ==&lt;br /&gt;
&lt;br /&gt;
Ensure that messages received out-of-order are highly visible to the user.&lt;br /&gt;
&lt;br /&gt;
A message m is ''out-of-order'' if its sender-parent's seqnum is &amp;lt; (m's seqnum - MAX_UNSYNC_COUNT)&lt;br /&gt;
&lt;br /&gt;
* MAX_UNSYNC_COUNT may either be constant, or a linear function of the number of members, TBD.&lt;br /&gt;
&lt;br /&gt;
These messages should be highlighted in some way in the UI that is not too severe. They are still valid messages, the user should just be informed that they refer to older context.&lt;br /&gt;
&lt;br /&gt;
This definition is globally consistent (or else transcript consistency breaks) so it's easier to reason about, and the warning is simpler to explain than MAX_RTD.&lt;br /&gt;
&lt;br /&gt;
[[Category: mpOTR]]&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Main_Page</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Main_Page"/>
				<updated>2014-08-29T14:08:49Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Undo revision 739 by WileyToney (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''eQualit.ie's whitepapers, documentation and training guides. Free to use and share'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Curricula|a Digital Security Trainer's Curricula]]&lt;br /&gt;
* Online manual on [http://equalit.ie/esecman/index.html Digital Security for Human Rights Defenders]&lt;br /&gt;
* [[Secure hosting guide]]&lt;br /&gt;
* [[Online Learning|Digital Security lessons]]&lt;br /&gt;
* [[mpOTR|mpOTR: multi-party OTR protocol]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Consult the [//meta.wikimedia.org/wiki/Help:Contents User's Guide] for information on using the wiki software.&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Transport_reliability/reply</id>
		<title>Thread:Talk:MpOTR/Transport reliability/reply</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Transport_reliability/reply"/>
				<updated>2014-08-04T15:58:41Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Reply to Transport reliability&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''&amp;gt; In my opinion mpCAT should be like SSL and IPSEC, the messaging transport control protocol (MTCP) should act like TCP... ''&lt;br /&gt;
&lt;br /&gt;
We are working on end-to-end security principles, which applies for reliability too. TCP reliability is on the transport layer, not end-to-end between clients working on separate TCP connections. XMPP MUC reliability helps, but is not general enough: as I noted in the other thread, typically public services do not have the incentive, and cannot afford (due to threat of DoS) to offer ''unconditional'' reliability - they can only offer ''limited'' reliability, i.e. finite-time buffer or finite-message buffer, as experienced on real-world MUC servers.&lt;br /&gt;
&lt;br /&gt;
As I explain in msg-notes, consistency is closely related to reliability; therefore it's best done ''within'' the end-to-end reliability layer. For example, your proposed scheme ''fails badly'' in the general case where the server cannot provide end-to-end reliability.&lt;br /&gt;
&lt;br /&gt;
I agree that deniable authenticity and forward-secure confidentiality is best done in a separate layer, though. The idea of separation is good, but I disagree with how you're choosing to separate things, based on my research into the consistency problem.&lt;br /&gt;
&lt;br /&gt;
''&amp;gt; I think assuming extra ordinary config/storage/abilities for the server, defeat the purpose of end-to-endness. If some participants are malicious...''&lt;br /&gt;
&lt;br /&gt;
Context for others: this is for a server-dictated order that supports end-to-end reliability.&lt;br /&gt;
&lt;br /&gt;
Participants might innocently drop for longer periods than the server is willing to buffer (due to potential maliciousness). However, you as the end client implicitly trusts your friend, so you are happy to buffer your own messages for them. ''Large public servers cannot make this assumption for all their users.''&lt;br /&gt;
&lt;br /&gt;
The server adding a sequence number, is zero-cost and (not considering migration costs) should be easy and reasonable to implement. It will ''enable'' end-to-end reliability, not guarantee it - the actual recovery behaviour would be implemented on the clients.&lt;br /&gt;
&lt;br /&gt;
''&amp;gt; .. we are restarting consistency check so you all are consistence after message y.&amp;quot;. (an easily implementable compromise is to reset consistency digest at each group key exchange, I'll add that if nobody objects).''&lt;br /&gt;
&lt;br /&gt;
I think it would be better to just automatically re-run the GKE when inconsistency is detected. Why wait until the next group key exchange?&lt;br /&gt;
&lt;br /&gt;
But I think this sort of solution is not ideal, and results much greater overal complexity; consistency and reliability should be done as part of the same layer, because it is simpler and more natural that way.&lt;br /&gt;
&lt;br /&gt;
''&amp;gt; .. Again, in my opinion the MTCP should run in a lower layer than mpCat like TCP, that is how we can be transport-agnostic. However, I think there is a general consensus that async is off the table for now.''&lt;br /&gt;
&lt;br /&gt;
To explain why this viewpoint is naive and narrow: your layer mpCAT, makes assumptions that ''do not apply'' in the more general case. The way you calculate consistency, assumes global-totally-ordered (linear) reliable delivery; it ''cannot work'' in a less strict scenario such as serverless broadcast, even though theoretically we can achieve consistency in those scenarios (e.g. via causal ordering). So, general (i.e. transport-agnostic) reliability systems ''do not try'' to achieve this property, so you will not be able to &amp;quot;layer&amp;quot; mpCat on top of it.&lt;br /&gt;
&lt;br /&gt;
The only way a reliability layer can achieve this property (i.e. to ensure your assumption holds), is to ''require'' the server changes I mentioned (global explicit sequence numbers) ''and'' implement end-to-end recovery in the clients based on this information. '''This is a fine path to go down''', but '''no reasonable person should call this &amp;quot;transport-agnostic&amp;quot;''', since it requires server changes which other protocols may not want to adopt (if the protocol even has servers).&lt;br /&gt;
&lt;br /&gt;
TL;DR: the currently-proposed protocol is '''not transport-agnostic''' due to an assumption that is fundamentally transport-specific (global total-ordering). No &amp;quot;layering&amp;quot; strategy will enable the protocol to be transport-agnostic; only changes to the protocol itself that ''don't make this assumption'' will enable it to achieve this.&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Rename_%22broadcast_scheme%22</id>
		<title>Thread:Talk:MpOTR/Rename &quot;broadcast scheme&quot;</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Rename_%22broadcast_scheme%22"/>
				<updated>2014-08-02T15:53:01Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;By &amp;quot;broadcast scheme&amp;quot;, this refers collectively to the peer-to-peer pairwise broadcast, or the &amp;quot;sender keys&amp;quot; optimisation on top of it. I think &amp;quot;broadcast scheme&amp;quot; is too generic and confusing. How about &amp;quot;p2p-broadcast&amp;quot;, &amp;quot;full-broadcast&amp;quot;, &amp;quot;sender-broadcast&amp;quot;, or &amp;quot;member-broadcast&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
I also disagree with ''&amp;quot;Each participant will have its own different $plist_i$ which is able to broadcast too.&amp;quot;''. In all schemes, every member should eventually reach the same plist as everyone else. In all schemes, there will be a period where different members have different plists - e.g. even in the GKE case, some members will receive the final round of the GKE earlier than others, so switch to the new plist earlier than those others.&lt;br /&gt;
&lt;br /&gt;
The key difference is that in the p2p-broadcast case, (optionally) members are able to *provisionally send* to the new plist earlier than some other members do, without receiving a key confirmation (and with a forward secrecy penalty if there was an active attack).&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Rename_%22broadcast_scheme%22</id>
		<title>Thread:Talk:MpOTR/Rename &quot;broadcast scheme&quot;</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Rename_%22broadcast_scheme%22"/>
				<updated>2014-08-02T15:50:19Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: New thread: Rename &amp;quot;broadcast scheme&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;By &amp;quot;broadcast scheme&amp;quot;, this refers collectively to the peer-to-peer pairwise broadcast, or the &amp;quot;sender keys&amp;quot; optimisation on top of it. I think &amp;quot;broadcast scheme&amp;quot; is too generic and confusing. How about &amp;quot;p2p-broadcast&amp;quot;, &amp;quot;full-broadcast&amp;quot;, &amp;quot;sender-broadcast&amp;quot;, or &amp;quot;member-broadcast&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
I also disagree with ''&amp;quot;Each participant will have its own different $plist_i$ which is able to broadcast too.&amp;quot;''. In all schemes, every member should eventually reach the same plist as everyone else. In all schemes, there will be a period where different members have different plists - e.g. even in the GKE case, some members will receive the final round of the GKE earlier than others, so switch to the new plist earlier than those others.&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	<entry>
		<id>https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Protocol_name/reply</id>
		<title>Thread:Talk:MpOTR/Protocol name/reply</title>
		<link rel="alternate" type="text/html" href="https://learn.equalit.ie/wiki/Thread:Talk:MpOTR/Protocol_name/reply"/>
				<updated>2014-08-02T15:42:44Z</updated>
		
		<summary type="html">&lt;p&gt;Infinity0: Reply to Protocol name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I'm hesitant about &amp;quot;mpOTR&amp;quot;. 2-party OTR works well on IRC, even though messages may be dropped. But in the group setting, in order to ensure transcript consistency, you basically require reliability which IRC does not do. So the current proposal can only work for XMPP.&lt;/div&gt;</summary>
		<author><name>Infinity0</name></author>	</entry>

	</feed>