diff --git a/vac/raw/decentralized-messaging-ethereum.md b/vac/raw/decentralized-messaging-ethereum.md
index 0a433ebb..a5b2af88 100644
--- a/vac/raw/decentralized-messaging-ethereum.md
+++ b/vac/raw/decentralized-messaging-ethereum.md
@@ -19,28 +19,29 @@ the multi-device setting.
## Motivation
The need for secure communications has become paramount.
-Traditional centralized messaging protocols are susceptible to various security threats,
-including unauthorized access, data breaches, and single points of failure.
-Therefore a decentralized approach to secure communication becomes increasingly relevant,
-offering a robust solution to address these challenges.
+Traditional centralized messaging protocols are susceptible to various security
+threats, including unauthorized access, data breaches, and single points of
+failure.
+Therefore a decentralized approach to secure communication becomes increasingly
+relevant, offering a robust solution to address these challenges.
Secure messaging protocols used should have the following key features:
-1. **Asynchronous Messaging:** Users can send messages even if
-the recipients are not online at the moment.
+1. **Asynchronous Messaging:** Users can send messages even if the recipients
+are not online at the moment.
+
2. **Resilience to Compromise:** If a user's security is compromised,
-the protocol ensures that previous messages remain secure
-through forward secrecy (FS).
-This means that messages sent before the compromise cannot be decrypted by adversaries.
-Additionally, the protocol maintains post-compromise security (PCS)
-by regularly updating keys,
-making it difficult for adversaries to decrypt future communication.
-3. **Dynamic Group Management:** Users can easily add or
-remove group members at any time,
-reflecting the flexible nature of communication within the app.
-
-In this field, there exists a *trilemma*, similar to what one observes in blockchain,
-involving three key aspects:
+the protocol ensures that previous messages remain secure through forward
+secrecy (FS). This means that messages sent before the compromise cannot be
+decrypted by adversaries. Additionally, the protocol maintains post-compromise
+security (PCS) by regularly updating keys, making it difficult for adversaries
+to decrypt future communication.
+
+3. **Dynamic Group Management:** Users can easily add or remove group members
+at any time, reflecting the flexible nature of communication within the app.
+
+In this field, there exists a *trilemma*, similar to what one observes in
+blockchain, involving three key aspects:
1. security,
2. scalability, and
@@ -141,30 +142,29 @@ Two messages `m_1` and `m_2` are causally ordered, or
processed by `U` before sending `m_2`.
3. There exists `m_3` such that `m_1 < m_3` and `m_3 < m_2`.
-Causal broadcast requires that before processing `m`,
-a group member must process all preceding messages `{m' | m' < m}`.
+Causal broadcast requires that before processing `m`, a group member must
+process all preceding messages `{m' | m' < m}`.
-The causal broadcast module used in this protocol
-authenticates the sender of each message,
-as well as its causal ordering metadata,
-using a digital signature under the sender’s identity key.
-This prevents a passive adversary from impersonating users or
-affecting causally ordered delivery.
+The causal broadcast module used in this protocol authenticates the sender of
+each message, as well as its causal ordering metadata, using a digital
+signature under the sender’s identity key.
+This prevents a passive adversary from impersonating users or affecting
+causally ordered delivery.
#### Decentralized group membership
-This protocol assumes the existence of a decentralized group membership function
-(denoted as DGM) that takes a set of membership change messages and
-their causal order relantionships,
-and returns the current set of group members’ IDs.
-It needs to be deterministic and depend only on causal order, and not exact order.
+This protocol assumes the existence of a decentralized group membership
+function (denoted as DGM) that takes a set of membership change messages and
+their causal order relantionships, and returns the current set of group
+members’ IDs. It needs to be deterministic and depend only on causal order, and
+not exact order.
#### 2-party secure messaging (2SM)
This protocol makes use of bidirectional 2-party secure messaging schemes,
which consist of 3 algorithms: `2SM-Init`, `2SM-Send` and `2SM-Receive`.
-##### 2SM-Init
+##### Function 2SM-Init
This function takes two IDs as inputs:
`ID1` representing the local user and `ID2` representing the other party.
@@ -175,53 +175,56 @@ In practice, the PKI should incorporate ephemeral prekeys.
This allows users to send messages to a new group member,
even if that member is currently offline.
-##### 2SM-Send
+##### Function 2SM-Send
-This function takes a state `sigma` and a plaintext `m` as inputs, and
-returns a new state `sigma’` and a ciphertext `c`.
+This function takes a state `sigma` and a plaintext `m` as inputs, and returns
+a new state `sigma’` and a ciphertext `c`.
-##### 2SM-Receive
+##### Function 2SM-Receive
This function takes a state `sigma` and a ciphertext `c`, and
returns a new state `sigma’` and a plaintext `m`.
-#### 2SM Syntax
+This function takes a state `sigma` and a ciphertext `c`, and returns a new
+state `sigma’` and a plaintext `m`.
+
+#### Function 2SM Syntax
The variable `sigma` denotes the state consisting in the variables below:
-```rust
+```text
sigma.mySks[0] = sk
sigma.nextIndex = 1
sigma.receivedSk = empty_string
sigma.otherPk = pk`
sigma.otherPksender = “other”
sigma.otherPkIndex = 0
+
```
-#### The 2SM-Init
+#### 2SM-Init
On input a key pair `(sk, pk)`, this functions otuputs a state `sigma`.
-#### The 2SM-Send
+#### 2SM-Send
-This function encrypts the message `m` using `sigma.otherPk`,
-which represents the other party’s current public key.
-This key is determined based on the last public key generated
-for the other party or the last public key received from the other party,
-whichever is more recent.
-`sigma.otherPkSender` is set to `me` in the former case and
-`other` in the latter case.
+This function encrypts the message `m` using `sigma.otherPk`, which represents
+the other party’s current public key.
+This key is determined based on the last public key generated for the other
+party or the last public key received from the other party,
+whichever is more recent. `sigma.otherPkSender` is set to `me` in the former
+case and `other` in the latter case.
-Metadata including `otherPkSender` and
-`otherPkIndex` are included in the message to indicate
-which of the recipient’s public keys is being utilized.
+Metadata including `otherPkSender` and `otherPkIndex` are included in the
+message to indicate which of the recipient’s public keys is being utilized.
Additionally, this function generates a new key pair for the local user,
storing the secret key in `sigma.mySks` and sending the public key.
Similarly, it generates a new key pair for the other party,
-sending the secret key (encrypted) and storing the public key in `sigma.otherPk`.
+sending the secret key (encrypted) and storing the public key in
+`sigma.otherPk`.
-```go
+```text
sigma.mySks[sigma.nextIndex], myNewPk) = PKE-Gen()
(otherNewSk, otherNewPk) = PKE-Gen()
plaintext = (m, otherNewSk, sigma`.nextIndex, myNewPk)
@@ -229,19 +232,20 @@ msg = (PKE-Enc(sigma.otherPk, plaintext), sigma.otherPkSender, sigma.otherPkInde
sigma.nextIndex++
(sigma.otherPk, sigma.otherPkSender, sigma.otherPkIndex) = (otherNewPk, "me", empty_string)
return (sigma`, msg)
+
```
-#### The 2SM-Receive
+#### 2SM-Receive
-This function utilizes the metadata of the message `c`
-to determine which secret key to utilize for decryption,
-assigning it to `sk`.
+This function utilizes the metadata of the message `c` to determine which
+secret key to utilize for decryption, assigning it to `sk`.
If the secret key corresponds to one generated by ourselves,
that secret key along with all keys with lower index are deleted.
This deletion is indicated by `sigma.mySks[≤ keyIndex] = empty_string`.
-Subsequently, the new public and secret keys contained in the message are stored.
+Subsequently, the new public and secret keys contained in the message are
+stored.
-```go
+```text
(ciphertext, keySender, keyIndex) = c
if keySender = "other" then
sk = sigma.mySks[keyIndex]
@@ -250,6 +254,7 @@ else sk = sigma.receivedSk
(m, sigma.receivedSk, sigma.otherPkIndex, sigma.otherPk) = PKE-Dec(sk, ciphertext)
sigma.otherPkSender = "other"
return (sigma, m)
+
```
### PKE Syntax
@@ -260,33 +265,36 @@ The required PKE that MUST be used is ElGamal with a 2048-bit modulus `p`.
The following parameters must be used:
-```go
+```text
p = 308920927247127345254346920820166145569
g = 2
+
```
#### PKE-KGen
Each user `u` MUST do the following:
-```go
+```text
PKE-KGen():
a = randint(2, p-2)
pk = (p, g, g^a)
sk = a
return (pk, sk)
+
```
#### PKE-Enc
A user `v` encrypting a message `m` for `u` MUST follow these steps:
-```go
+```text
PKE-Enc(pk):
k = randint(2, p-2)
eta = g^k % p
delta = m * (g^a)^k % p
return ((eta, delta))
+
```
#### PKE-Dec
@@ -294,25 +302,26 @@ return ((eta, delta))
The user `u` recovers a message `m` from a ciphertext `c`
by performing the following operations:
-```go
+```text
PKE-Dec(sk):
mu = eta^(p-1-sk) % p
return ((mu * delta) % p)
+
```
### DCGKA Syntax
#### Auxiliary functions
-There exist 6 functions that are auxiliary for the rest of components of the protocol,
-namely:
+There exist 6 functions that are auxiliary for the rest of components of the
+protocol, namely:
#### init
This function takes an `ID` as input and returns its associated initial state,
denoted by `gamma`:
-```go
+```text
gamma.myId = ID
gamma.mySeq = 0
gamma.history = empty
@@ -321,47 +330,53 @@ gamma.2sm[·] = empty_string
gamma.memberSecret[·, ·, ·] = empty_string
gamma.ratchet[·] = empty_string
return (gamma)
+
```
#### encrypt-to
-Upon reception of the recipient’s `ID` and a plaintext,
-it encrypts a direct message for another group member.
+Upon reception of the recipient’s `ID` and a plaintext, it encrypts a direct
+message for another group member.
Should it be the first message for a particular `ID`,
-then the `2SM` protocol state is initialized and stored in `gamma.2sm[recipient.ID]`.
-One then uses `2SM_Send` to encrypt the message and
-store the updated protocol in `gamma`.
+then the `2SM` protocol state is initialized and stored in
+`gamma.2sm[recipient.ID]`.
+One then uses `2SM_Send` to encrypt the message and store the updated protocol
+in `gamma`.
-```go
+```text
if gamma.2sm[recipient_ID] = empty_string then
gamma.2sm[recipient_ID] = 2SM_Init(gamma.myID, recipient_ID)
(gamma.2sm[recipient_ID], ciphertext) = 2SM_Send(gamma.2sm[recipient_ID], plaintext)
return (gamma, ciphertext)
+
```
#### decrypt-from
-After receiving the sender’s `ID` and a ciphertext,
-it behaves as the reverse function of `encrypt-to` and has a similar initialization:
+After receiving the sender’s `ID` and a ciphertext, it behaves as the reverse
+function of `encrypt-to` and has a similar initialization:
-```go
+```text
if gamma.2sm[sender_ID] = empty_string then
gamma.2sm[sender_ID] = 2SM_Init(gamma.myID, sender_ID)
(gamma.2sm[sender_ID], plaintext) = 2SM_Receive(gamma.2sm[sender_ID], ciphertext)
return (gamma, plaintext)
+
```
#### update-ratchet
-This function generates the next update secret `I_update` for the group member `ID`.
+This function generates the next update secret `I_update` for the group member
+`ID`.
The ratchet state is stored in `gamma.ratchet[ID]`.
-It is required to use a HMAC-based key derivation function HKDF
-to combine the ratchet state with an input,
-returning an update secret and a new ratchet state.
+It is required to use a HMAC-based key derivation function HKDF to combine the
+ratchet state with an input, returning an update secret and a new ratchet
+state.
-```go
+```text
(updateSecret, gamma.ratchet[ID]) = HKDF(gamma.ratchet[ID], input)
return (gamma, updateSecret)
+
```
#### member-view
@@ -372,9 +387,10 @@ It filters the group membership operations
to include only those observed by the specified `ID`, and
then invokes the DGM function to generate the group membership.
-```go
+```text
ops = {m in gamma.history st. m was sent or acknowledged by ID}
return DGM(ops)
+
```
#### generate-seed
@@ -384,132 +400,143 @@ sends it encrypted to each member of the group using the `2SM` mechanism.
It returns the updated protocol state and
the set of direct messages (denoted as `dmsgs`) to send.
-```go
+```text
gamma.nextSeed = random.randbytes()
dmsgs = empty
for each ID in recipients:
(gamma, msg) = encrypt-to(gamma, ID, gamma.nextSeed)
dmsgs = dmsgs + (ID, msg)
return (gamma, dmsgs)
+
```
### Creation of a group
A group is generated in a 3 steps procedure:
-1. A user calls the `create` function and broadcasts a control message of type *create*.
-2. Each receiver of the message processes the message and
-broadcasts an *ack* control message.
+1. A user calls the `create` function and broadcasts a control message of type
+*create*.
+2. Each receiver of the message processes the message and broadcasts an *ack*
+control message.
3. Each member processes the *ack* message received.
#### create
-This function generates a *create* control message and
-calls `generate-seed` to define the set of direct messages that need to be sent.
+This function generates a *create* control message and calls `generate-seed` to
+define the set of direct messages that need to be sent.
Then it calls `process-create` to process the control message for this user.
-The function `process-create` returns a tuple including an updated state gamma and
-an update secret `I`.
+The function `process-create` returns a tuple including an updated state gamma
+and an update secret `I`.
-```go
+```text
control = (“create”, gamma.mySeq, IDs)
(gamma, dmsgs) = generate-seed(gamma, IDs)
(gamma, _, _, I, _) = process-create(gamma, gamma.myId, gamma.mySeq, IDs, empty_string)
return (gamma, control, dmsgs, I)
+
```
#### process-seed
-This function initially employs `member-view` to
-identify the users who were part of the group when the control message was dispatched.
+This function initially employs `member-view` to identify the users who were
+part of the group when the control message was dispatched.
Then, it attempts to acquire the seed secret through the following steps:
-1. If the control message was dispatched by the local user,
-it uses the most recent invocation of `generate-seed` stored the seed secret in `gamma.nextSeed`.
-2. If the `control` message was dispatched by another user, and
-the local user is among its recipients,
-the function utilizes `decrypt-from` to decrypt the direct message
-that includes the seed secret.
+1. If the control message was dispatched by the local user, it uses the most
+recent invocation of `generate-seed` stored the seed secret in
+`gamma.nextSeed`.
+2. If the `control` message was dispatched by another user, and the local user
+is among its recipients, the function utilizes `decrypt-from` to decrypt the
+direct message that includes the seed secret.
3. Otherwise, it returns an `ack` message without deriving an update secret.
-Afterwards, `process-seed` generates separate member secrets
-for each group member from the seed secret by combining the seed secret and
+Afterwards, `process-seed` generates separate member secrets for each group
+member from the seed secret by combining the seed secret and
each user ID using HKDF.
-The secret for the sender of the message is stored in `senderSecret`,
-while those for the other group members are stored in `gamma.memberSecret`.
-The sender's member secret is immediately utilized to update their KDF ratchet and
-compute their update secret `I_sender` using `update-ratchet`.
-If the local user is the sender of the control message,
-the process is completed, and the update secret is returned.
-However, if the seed secret is received from another user,
-an `ack` control message is constructed for broadcast,
-including the sender ID and sequence number of the message being acknowledged.
-
-The final step computes an update secret `I_me`
-for the local user invoking the `process-ack` function.
-
-```go
+The secret for the sender of the message is stored in `senderSecret`, while
+those for the other group members are stored in `gamma.memberSecret`.
+The sender's member secret is immediately utilized to update their KDF ratchet
+and compute their update secret `I_sender` using `update-ratchet`.
+If the local user is the sender of the control message, the process is
+completed, and the update secret is returned.
+However, if the seed secret is received from another user, an `ack` control
+message is constructed for broadcast, including the sender ID and sequence
+number of the message being acknowledged.
+
+The final step computes an update secret `I_me` for the local user invoking the
+`process-ack` function.
+
+```text
recipients = member-view(gamma, sender) - {sender}
-if sender = gamma.myId then seed = gamma.nextSeed; gamma.nextSeed = empty_string
-else if gamma.myId in recipients then (gamma, seed) = decrypt-from(gamma, sender, dmsg)
+if sender = gamma.myId then seed = gamma.nextSeed; gamma.nextSeed =
+empty_string
+else if gamma.myId in recipients then (gamma, seed) = decrypt-from(gamma,
+sender, dmsg)
else
-return (gamma, (ack, ++gamma.mySeq, (sender, seq)), empty_string , empty_string , empty_string)
+return (gamma, (ack, ++gamma.mySeq, (sender, seq)), empty_string ,
+empty_string , empty_string)
for ID in recipients do gamma.memberSecret[sender, seq, ID] = HKDF(seed, ID)
-
senderSecret = HKDF(seed, sender)
(gamma, I_sender) = update-ratchet(gamma, sender, senderSecret)
-if sender = gamma.myId then return (gamma, empty_string , empty_string , I_sender, empty_string)
+if sender = gamma.myId then return (gamma, empty_string , empty_string ,
+I_sender, empty_string)
control = (ack, ++gamma.mySeq, (sender, seq))
members = member-view(gamma, gamma.myId)
forward = empty
for ID in {members - (recipients + {sender})}
- s = gamma.memberSecret[sender, seq, gamma.myId]
- (gamma, msg) = encrypt-to(gamma, ID, s)
- forward = forward + {(ID, msg)}
+ s = gamma.memberSecret[sender, seq, gamma.myId]
+ (gamma, msg) = encrypt-to(gamma, ID, s)
+ forward = forward + {(ID, msg)}
+ (gamma, _, _, I_me, _) = process-ack(gamma, gamma.myId, gamma.mySeq,
+ (sender, seq), empty_string)
+ return (gamma, control, forward, I_sender, I_me)
-(gamma, _, _, I_me, _) = process-ack(gamma, gamma.myId, gamma.mySeq, (sender, seq), empty_string)
-return (gamma, control, forward, I_sender, I_me)
```
#### process-create
-This function is called by the sender and
-each of the receivers of the `create` control message.
-First, it records the information from the create message
-in the `gamma.history+ {op}`, which is used to track group membership changes.
-Then, it proceeds to call `process-seed`.
+This function is called by the sender and each of the receivers of the `create`
+control message.
+First, it records the information from the create message in the
+`gamma.history+ {op}`, which is used to track group membership changes. Then,
+it proceeds to call `process-seed`.
-```go
+```text
op = (”create”, sender, seq, IDs)
gamma.history = gamma.history + {op}
return (process-seed(gamma, sender, seq, dmsg))
+
```
#### process-ack
-This function is called by those group members once they receive an ack message.
-In `process-ack`, `ackID` and `ackSeq` are the sender and
-sequence number of the acknowledged message.
-Firstly, if the acknowledged message is a group membership operation,
-it records the acknowledgement in `gamma.history`.
+This function is called by those group members once they receive an ack
+message.
+In `process-ack`, `ackID` and `ackSeq` are the sender and sequence number of
+the acknowledged message.
+Firstly, if the acknowledged message is a group membership operation, it
+records the acknowledgement in `gamma.history`.
-Following this, the function retrieves the relevant member secret from `gamma.memberSecret`,
-which was previously obtained from the seed secret
+Following this, the function retrieves the relevant member secret from
+`gamma.memberSecret`, which was previously obtained from the seed secret
contained in the acknowledged message.
-Finally, it updates the ratchet for the sender of the `ack` and
-returns the resulting update secret.
+Finally, it updates the ratchet for the sender of the `ack` and returns the
+resulting update secret.
-```go
+```text
if (ackID, ackSeq) was a create / add / remove then
op = ("ack", sender, seq, ackID, ackSeq)
gamma.history = gamma.history + {op}`
s = gamma.memberSecret[ackID, ackSeq, sender]
gamma.memberSecret[ackID, ackSeq, sender] = empty_string
-if (s = empty_string) & (dmsg = empty_string) then return (gamma, empty_string, empty_string, empty_string, empty_string)
+if (s = empty_string) & (dmsg = empty_string) then return (gamma, empty_string,
+empty_string, empty_string, empty_string)
if (s = empty_string) then (gamma, s) = decrypt-from(gamma, sender, dmsg)
(gamma, I) = update-ratchet(gamma, sender, s)
return (gamma, empty_string, empty_string, I, empty_string)
+
```
The HKDF function MUST follow RFC 5869 using the hash function SHA256.
@@ -517,13 +544,14 @@ The HKDF function MUST follow RFC 5869 using the hash function SHA256.
### Post-compromise security updates and group member removal
The functions `update` and `remove` share similarities with `create`:
-they both call the function `generate-seed`
-to encrypt a new seed secret for each group member.
-The distinction lies in the determination of the group members using `member-view`.
-In the case of `remove`,
-the user being removed is excluded from the recipients of the seed secret.
-Additionally, the control message they construct is designated with type `update`
- or `remove` respectively.
+they both call the function `generate-seed` to encrypt a new seed secret for
+each group member.
+The distinction lies in the determination of the group members using `member
+view`.
+In the case of `remove`, the user being removed is excluded from the recipients
+of the seed secret.
+Additionally, the control message they construct is designated with type
+`update` or `remove` respectively.
Likewise, `process-update` and `process-remove` are akin to `process-create`.
The function `process-update` skips the update of `gamma.history`,
@@ -531,22 +559,26 @@ whereas `process-remove` includes a removal operation in the history.
#### update
-```go
+```text
control = ("update", ++gamma.mySeq, empty_string)
recipients = member-view(gamma, gamma.myId) - {gamma.myId}
(gamma, dmsgs) = generate-seed(gamma, recipients)
-(gamma, _, _, I , _) = process-update(gamma, gamma.myId, gamma.mySeq, empty_string, empty_string)
+(gamma, _, _, I , _) = process-update(gamma, gamma.myId, gamma.mySeq,
+empty_string, empty_string)
return (gamma, control, dmsgs, I)
+
```
#### remove
-```go
+```text
control = ("remove", ++gamma.mySeq, empty)
recipients = member-view(gamma, gamma.myId) - {ID, gamma.myId}
(gamma, dmsgs) = generate-seed(gamma, recipients)
-(gamma, _, _, I , _) = process-update(gamma, gamma.myId, gamma.mySeq, ID, empty_string)
+(gamma, _, _, I , _) = process-update(gamma, gamma.myId, gamma.mySeq, ID,
+empty_string)
return (gamma, control, dmsgs, I)
+
```
#### process-update
@@ -555,184 +587,184 @@ return (gamma, control, dmsgs, I)
#### process-remove
-```go
+```text
op = ("remove", sender, seq, removed)
gamma.history = gamma.history + {op}
return process-seed(gamma, sender, seq, dmsg)
+
```
### Group member addition
#### add
-When adding a new group member,
-an existing member initiates the process by invoking the `add` function and
-providing the ID of the user to be added.
-This function prepares a control message marked as `add` for broadcast to the group.
-Simultaneously, it creates a welcome message intended for the new member
+When adding a new group member, an existing member initiates the process by
+invoking the `add` function and providing the ID of the user to be added.
+This function prepares a control message marked as `add` for broadcast to the
+group. Simultaneously, it creates a welcome message intended for the new member
as a direct message.
This `welcome` message includes the current state of the sender's KDF ratchet,
-encrypted using `2SM`,
-along with the history of group membership operations conducted so far.
+encrypted using `2SM`, along with the history of group membership operations
+conducted so far.
-```go
+```text
control = ("add", ++gamma.mySeq, ID)
(gamma, c) = encrypt-to(gamma, ID, gamma.ratchet[gamma.myId])
op = ("add", gamma.myId, gamma.mySeq, ID)
welcome = (gamma.history + {op}, c)
(gamma, _, _, I, _) = process-add(gamma, gamma.myId, gamma.mySeq, ID, empty_string)
return (gamma, control, (ID, welcome), I)
+
```
#### process-add
-This function is invoked by both the sender and
-each recipient of an `add` message, which includes the new group member.
-If the local user is the newly added member,
-the function proceeds to call `process-welcome` and then exits.
+This function is invoked by both the sender and each recipient of an `add`
+message, which includes the new group member. If the local user is the newly
+added member, the function proceeds to call `process-welcome` and then exits.
Otherwise, it extends `gamma.history` with the `add` operation.
-Line 5 determines whether the local user was already a group member
-at the time the `add` message was sent;
-this condition is typically true but may be false if multiple users were added concurrently.
-
-On lines 6 to 8, the ratchet for the sender of the *add* message is updated twice.
-In both calls to `update-ratchet`,
-a constant string is used as the ratchet input instead of a random seed secret.
-
-The value returned by the first ratchet update is stored in `gamma.memberSecret`
-as the added user’s initial member secret.
-The result of the second ratchet update becomes `I_sender`,
-the update secret for the sender of the `add` message.
-On line 10, if the local user is the sender, the update secret is returned.
-
-If the local user is not the sender, an acknowledgment for the `add` message is required.
-Therefore, on line 11, a control message of type `add-ack` is constructed for broadcast.
-Subsequently, in line 12 the current ratchet state is encrypted using `2SM`
-to generate a direct message intended for the added user,
-allowing them to decrypt subsequent messages sent by the sender.
-Finally, in lines 13 to 15,
-`process-add-ack` is called to calculate the local user’s update secret (`I_me`),
-which is then returned along with `I_sender`.
-
-```go
+Line 5 determines whether the local user was already a group member at the time
+the `add` message was sent; this condition is typically true but may be false
+if multiple users were added concurrently.
+
+On lines 6 to 8, the ratchet for the sender of the *add* message is updated
+twice. In both calls to `update-ratchet`, a constant string is used as the
+ratchet input instead of a random seed secret.
+
+The value returned by the first ratchet update is stored in
+`gamma.memberSecret` as the added user’s initial member secret. The result of
+the second ratchet update becomes `I_sender`, the update secret for the sender
+of the `add` message. On line 10, if the local user is the sender, the update
+secret is returned.
+
+If the local user is not the sender, an acknowledgment for the `add` message is
+required.
+Therefore, on line 11, a control message of type `add-ack` is constructed for
+broadcast.
+Subsequently, in line 12 the current ratchet state is encrypted using `2SM` to
+generate a direct message intended for the added user, allowing them to decrypt
+subsequent messages sent by the sender.
+Finally, in lines 13 to 15, `process-add-ack` is called to calculate the local
+user’s update secret (`I_me`), which is then returned along with `I_sender`.
+
+```text
if added = gamma.myId then return process-welcome(gamma, sender, seq, dmsg)
op = ("add", sender, seq, added)
gamma.history = gamma.history + {op}
if gamma.myId in member-view(gamma, sender) then
- (gamma, s) = update-ratchet(gamma, sender, "welcome")
- gamma.memberSecret[sender, seq, added] = s
- (gamma, I_sender) = update-ratchet(gamma, sender, "add")
-else I_sender = empty_string
-if sender = gamma.myId then return (gamma, empty_string, empty_string, I_sender, empty_string)
-control = ("add-ack", ++gamma.mySeq, (sender, seq))
-(gamma, c) = encrypt-to(gamma, added, ratchet[gamma.myId])
-(gamma, _, _, I_me, _) = process-add-ack(gamma, gamma.myId, gamma.mySeq, (sender, seq), empty_string)
-return (gamma, control, {(added, c)}, I_sender, I_me)
+ (gamma, s) = update-ratchet(gamma, sender, "welcome")
+ gamma.memberSecret[sender, seq, added] = s
+ (gamma, I_sender) = update-ratchet(gamma, sender, "add")
+ else I_sender = empty_string
+ if sender = gamma.myId then return (gamma, empty_string, empty_string,
+ I_sender, empty_string)
+ control = ("add-ack", ++gamma.mySeq, (sender, seq))
+ (gamma, c) = encrypt-to(gamma, added, ratchet[gamma.myId])
+ (gamma, _, _, I_me, _) = process-add-ack(gamma, gamma.myId, gamma.mySeq,
+ (sender, seq), empty_string)
+ return (gamma, control, {(added, c)}, I_sender, I_me)
+
```
#### process-add-ack
-This function is invoked by both the sender and each recipient of an `add-ack` message,
-including the new group member.
-Upon lines 1–2, the acknowledgment is added to `gamma.history`,
-mirroring the process in `process-ack`.
-If the current user is the new group member,
-the `add-ack` message includes the direct message constructed in `process-add`;
-this direct message contains the encrypted ratchet state of the sender of the `add-ack`,
-then it is decrypted on lines 3–5.
-
-Upon line 6,
-a check is performed to check if the local user
-was already a group member at the time the `add-ack` was sent.
-If affirmative, a new update secret `I` for the sender of the `add-ack`
-is computed on line 7 by invoking `update-ratchet` with the constant string `add`.
-
-In the scenario involving the new member,
-the ratchet state was recently initialized on line 5.
-This ratchet update facilitates all group members, including the new addition,
-to derive each member’s update by obtaining any update secret from before their inclusion.
-
-```go
+This function is invoked by both the sender and each recipient of an `add-ack`
+message, including the new group member. Upon lines 1–2, the acknowledgment is
+added to `gamma.history`, mirroring the process in `process-ack`.
+If the current user is the new group member, the `add-ack` message includes the
+direct message constructed in `process-add`; this direct message contains the
+encrypted ratchet state of the sender of the `add-ack`, then it is decrypted on
+lines 3–5.
+
+Upon line 6, a check is performed to check if the local user was already a
+group member at the time the `add-ack` was sent. If affirmative, a new update
+secret `I` for the sender of the `add-ack` is computed on line 7 by invoking
+`update-ratchet` with the constant string `add`.
+
+In the scenario involving the new member, the ratchet state was recently
+initialized on line 5. This ratchet update facilitates all group members,
+including the new addition, to derive each member’s update by obtaining any
+update secret from before their inclusion.
+
+```text
op = ("ack", sender, seq, ackID, ackSeq)
gamma$.history = gamma.history + {op}
if dmsg != empty_string then
- (gamma, s) = decrypt-from(gamma, sender, dmsg)
- gamma.ratchet[sender] = s
+ (gamma, s) = decrypt-from(gamma, sender, dmsg)
+ gamma.ratchet[sender] = s
if gamma.myId in member-view(gamma, sender) then
- (gamma, I) = update-ratchet(gamma, sender, "add")
- return (gamma, empty_string, empty_string, I, empty_string)
+ (gamma, I) = update-ratchet(gamma, sender, "add")
+ return (gamma, empty_string, empty_string, I, empty_string)
else return (gamma, empty_string, empty_string, empty_string, empty_string)
+
```
#### process-welcome
This function serves as the second step called by a newly added group member.
-In this context, `adderHistory` represents the adding user’s copy of `gamma.history`
-sent in their welcome message,
-which is utilized to initialize the added user’s history.
-Here, `c` denotes the ciphertext of the adding user’s ratchet state,
-which is decrypted on line 2 using `decrypt-from`.
-
-Once `gamma.ratchet[sender]` is initialized,
-`update-ratchet` is invoked twice on lines 3 to 5 with the constant strings `welcome`
-and `add` respectively.
-These operations mirror the ratchet operations
-performed by every other group member in `process-add`.
-The outcome of the first `update-ratchet` call
-becomes the first member secret for the added user,
-while the second call returns `I_sender`,
-the update secret for the sender of the add operation.
-
-Subsequently, the new group member constructs an *ack* control message
-to broadcast on line 6 and
-calls `process-ack` to compute their initial update secret I_me.
-The function `process-ack` reads from `gamma.memberSecret` and
-passes it to `update-ratchet`.
-The previous ratchet state for the new member is the empty string `empty`,
-as established by `init`,
-thereby initializing the new member’s ratchet.
-Upon receiving the new member’s `ack`,
-every other group member initializes their copy of the new member’s ratchet
-in a similar manner.
-
-By the conclusion of `process-welcome`,
-the new group member has acquired update secrets for themselves and
-the user who added them.
+In this context, `adderHistory` represents the adding user’s copy of
+`gamma.history` sent in their welcome message, which is utilized to initialize
+the added user’s history.
+Here, `c` denotes the ciphertext of the adding user’s ratchet state, which is
+decrypted on line 2 using `decrypt-from`.
+
+Once `gamma.ratchet[sender]` is initialized, `update-ratchet` is invoked twice
+on lines 3 to 5 with the constant strings `welcome` and `add` respectively.
+These operations mirror the ratchet operations performed by every other group
+member in `process-add`.
+The outcome of the first `update-ratchet` call becomes the first member secret
+for the added user,
+while the second call returns `I_sender`, the update secret for the sender of
+the add operation.
+
+Subsequently, the new group member constructs an *ack* control message to
+broadcast on line 6 and calls `process-ack` to compute their initial update
+secret I_me. The function `process-ack` reads from `gamma.memberSecret` and
+passes it to `update-ratchet`. The previous ratchet state for the new member is
+the empty string `empty`, as established by `init`, thereby initializing the
+new member’s ratchet.
+Upon receiving the new member’s `ack`, every other group member initializes
+their copy of the new member’s ratchet in a similar manner.
+
+By the conclusion of `process-welcome`, the new group member has acquired
+update secrets for themselves and the user who added them.
The ratchets for other group members are initialized by `process-add-ack`.
-```go
+```text
gamma.history = adderHistory
(gamma, gamma.ratchet[sender]) = decrypt-from(gamma, sender, c)
(gamma, s) = update-ratchet(gamma, sender, "welcome")
gamma.memberSecret[sender, seq, gamma.myId] = s
(gamma, I_sender) = update-ratchet(gamma, sender, "add")
control = ("ack", ++gamma.mySeq, (sender, seq))
-(gamma, _, _, I_me, _) = process-ack(gamma, gamma.myId, gamma.mySeq, (sender, seq), empty_string)
+(gamma, _, _, I_me, _) = process-ack(gamma, gamma.myId, gamma.mySeq, (sender,
+seq), empty_string)
return (gamma, control, empty_string , I_sender, I_me)
+
```
## Privacy Considerations
### Dependency on PKI
-The [DCGKA](https://eprint.iacr.org/2020/1281)
-proposal presents some limitations highlighted by the authors.
-Among these limitations one finds the requirement of a PKI
-(or a key server) mapping IDs to public keys.
+The [DCGKA](https://eprint.iacr.org/2020/1281) proposal presents some
+limitations highlighted by the authors.
+Among these limitations one finds the requirement of a PKI (or a key server)
+mapping IDs to public keys.
-One method to overcome this limitation is adapting the protocol SIWE
-(Sign in with Ethereum) so a user `u_1` who wants to start a communication
-with a user `u_2` can interact with latter’s wallet to request a public key
-using an Ethereum address as `ID`.
+One method to overcome this limitation is adapting the protocol SIWE (Sign in
+with Ethereum) so a user `u_1` who wants to start a communication with a user
+`u_2` can interact with latter’s wallet to request a public key using an
+Ethereum address as `ID`.
#### SIWE
-The [SIWE](https://docs.login.xyz/general-information/siwe-overview)
-(Sign In With Ethereum) proposal was a suggested standard for leveraging Ethereum
-to authenticate and authorize users on web3 applications.
-Its goal is to establish a standardized method for users
-to sign in to web3 applications using their Ethereum address and private key,
+The [SIWE](https://docs.login.xyz/general-information/siwe-overview) (Sign In
+With Ethereum) proposal was a suggested standard for leveraging Ethereum to
+authenticate and authorize users on web3 applications.
+Its goal is to establish a standardized method for users to sign in to web3
+applications using their Ethereum address and private key,
mirroring the process by which users currently sign in to web2 applications
using their email and password.
Below follows the required steps:
@@ -742,108 +774,107 @@ Below follows the required steps:
3. The user is presented with a distinctive message that includes the Nonce and
details about the website.
4. The user authenticates their identity by signing in with their wallet.
-5. Upon successful authentication, the user's identity is confirmed or approved.
+5. Upon successful authentication, the user's identity is confirmed or
+approved.
6. The website grants access to data specific to the authenticated user.
#### Our approach
-The idea in the [DCGKA](https://eprint.iacr.org/2020/1281)
-setting closely resembles the procedure outlined in SIWE. Here:
+The idea in the [DCGKA](https://eprint.iacr.org/2020/1281) setting closely
+resembles the procedure outlined in SIWE. Here:
-1. The server corresponds to user D1,
-who initiates a request (instead of generating a nonce)
-to obtain the public key of user D2.
+1. The server corresponds to user D1,who initiates a request (instead of
+generating a nonce) to obtain the public key of user D2.
2. Upon receiving the request, the wallet of D2 send the request to the user,
-3. User D2 receives the request from the wallet, and decides whether accepts or rejects.
+3. User D2 receives the request from the wallet, and decides whether accepts or
+rejects.
4. The wallet and responds with a message containing the requested public key
in case of acceptance by D2.
-This message may be signed,
-allowing D1 to verify that the owner of the received public key is indeed D2.
+This message may be signed, allowing D1 to verify that the owner of the
+received public key is indeed D2.
### Multi-device setting
-One may see the set of devices as a group and create a group key for internal communications.
-One may use treeKEM for instance,
-since it provides interesting properties like forward secrecy and
-post-compromise security.
-All devices share the same `ID`,
-which is held by one of them, and from other user’s point of view,
-they would look as a single user.
-
-Using servers,
-like in the paper [Multi-Device for Signal](https://eprint.iacr.org/2019/1363),
-should be avoided; but this would imply using a particular device as receiver and
+One may see the set of devices as a group and create a group key for internal
+communications.
+One may use treeKEM for instance, since it provides interesting properties like
+forward secrecy and post-compromise security.
+All devices share the same `ID`, which is held by one of them, and from other
+user’s point of view, they would look as a single user.
+
+Using servers, like in the paper
+[Multi-Device for Signal](https://eprint.iacr.org/2019/1363), should be
+avoided; but this would imply using a particular device as receiver and
broadcaster within the group.
-There is an obvious drawback which is having a single device working as a “server”.
-Should this device be attacked or without connection,
-there should be a mechanism for its revocation and replacement.
+There is an obvious drawback which is having a single device working as a
+“server”. Should this device be attacked or without connection, there should be
+a mechanism for its revocation and replacement.
-Another approach for communications between devices
-could be using the keypair of each device.
-This could open the door to use UPKE, since keypairs should be regenerated frequently.
+Another approach for communications between devices could be using the keypair
+of each device. This could open the door to use UPKE, since keypairs should be
+regenerated frequently.
-Each time a device sends a message, either an internal message or an external message,
-it needs to replicate and broadcast it to all devices in the group.
+Each time a device sends a message, either an internal message or an external
+message, it needs to replicate and broadcast it to all devices in the group.
The mechanism for the substitution of misbehaving leader devices follows:
-1. Each device within a group knows the details of other leader devices.
-This information may come from metadata in received messages, and
-is replicated by the leader device.
-2. To replace a leader,
-the user should select any other device within its group and
-use it to send a signed message to all other users.
-3. To get the ability to sign messages,
-this new leader should request the keypair associated to the ID to the wallet.
-4. Once the leader has been changed,
-it revocates access from DCGKA to the former leader using the DCGKA protocol.
+1. Each device within a group knows the details of other leader devices. This
+information may come from metadata in received messages, and is replicated by
+the leader device.
+2. To replace a leader, the user should select any other device within its
+group and use it to send a signed message to all other users.
+3. To get the ability to sign messages, this new leader should request the
+keypair associated to the ID to the wallet.
+4. Once the leader has been changed, it revocates access from DCGKA to the
+former leader using the DCGKA protocol.
5. The new leader starts a key update in DCGKA.
-Not all devices in a group should be able to send messages to other users.
-Only the leader device should be in charge of sending and receiving messages.
-To prevent other devices from sending messages outside their group,
-a requirement should be signing each message.
-The keys associated to the `ID` should only be in control of the leader device.
+Not all devices in a group should be able to send messages to other users. Only
+the leader device should be in charge of sending and receiving messages.
+To prevent other devices from sending messages outside their group, a
+requirement should be signing each message. The keys associated to the `ID`
+should only be in control of the leader device.
-The leader device is in charge of setting the keys involved in the DCGKA.
-This information must be replicated within the group to make sure it is updated.
+The leader device is in charge of setting the keys involved in the DCGKA. This
+information must be replicated within the group to make sure it is updated.
-To detect missing messages or potential misbehavior, messages must include a counter.
+To detect missing messages or potential misbehavior, messages must include a
+counter.
### Using UPKE
-Managing the group of devices of a user can be done either
-using a group key protocol such as treeKEM or
-using the keypair of each device.
-Setting a common key for a group of devices
-under the control of the same actor might be excessive,
-furthermore it may imply some of the problems one can find
+Managing the group of devices of a user can be done either using a group key
+protocol such as treeKEM or using the keypair of each device.
+Setting a common key for a group of devices under the control of the same actor
+might be excessive, furthermore it may imply some of the problems one can find
in the usual setting of a group of different users;
-for example: one of the devices may not participate in the required updating processes,
-representing a threat for the group.
+for example: one of the devices may not participate in the required updating
+processes, representing a threat for the group.
-The other approach to managing the group of devices is using each device’s keypair,
-but it would require each device updating these materia frequently,
+The other approach to managing the group of devices is using each device’s
+keypair, but it would require each device updating these materia frequently,
something that may not happens.
[UPKE](https://eprint.iacr.org/2022/068) is a form of asymetric cryptography
-where any user can update any other user’s key pair
-by running an update algorithm with (high-entropy) private coins.
-Any sender can initiate a *key update* by sending a special update ciphertext.
-This ciphertext updates the receiver’s public key and also,
-once processed by the receiver, will update their secret key.
-
-To the best of my knowledge,
-there exists several efficient constructions both [UPKE from ElGamal](https://eprint.iacr.org/2019/1189)
-(based in the DH assumption) and
-[UPKE from Lattices]((https://eprint.iacr.org/2023/1400)) (based in lattices).
-None of them have been implemented in a secure messaging protocol, and
-this opens the door to some novel research.
+where any user can update any other user’s key pair by running an update
+algorithm with (high-entropy) private coins. Any sender can initiate a *key
+update* by sending a special update ciphertext.
+This ciphertext updates the receiver’s public key and also, once processed by
+the receiver, will update their secret key.
+
+To the best of my knowledge, there exists several efficient constructions both
+[UPKE from ElGamal](https://eprint.iacr.org/2019/1189) (based in the DH
+assumption) and [UPKE from Lattices]((https://eprint.iacr.org/2023/1400))
+(based in lattices).
+None of them have been implemented in a secure messaging protocol, and this
+opens the door to some novel research.
## Copyright
-Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
+Copyright and related rights waived via
+[CC0](https://creativecommons.org/publicdomain/zero/1.0/).
## References
diff --git a/vac/raw/eth-demls.md b/vac/raw/eth-demls.md
new file mode 100644
index 00000000..cd3e9c1f
--- /dev/null
+++ b/vac/raw/eth-demls.md
@@ -0,0 +1,1034 @@
+---
+title: ETH-DEMLS
+name: Secure channel setup using decentralized MLS and Ethereum accounts
+status: raw
+category: Standards Track
+tags:
+editor: Ramses Fernandez
+contributors: Aaryamann Challani , Ekaterina Broslavskaya , Ugur Sen , Ksr
+---
+
+## Motivation
+
+The need for secure communications has become paramount.
+Traditional centralized messaging protocols are susceptible to various security threats,
+including unauthorized access, data breaches, and single points of failure.
+Therefore a decentralized approach to secure communication becomes increasingly relevant,
+offering a robust solution to address these challenges.
+
+This document specifies a private messaging service using the
+Ethereum blockchain as authentication service.
+Rooted in the existing [model](../../waku/standards/application/20/toy-eth-pm.md),
+this proposal addresses the deficiencies related
+to forward privacy and authentication inherent
+in the current framework.
+The specification is divided into the following sections:
+
+- Private group messaging protocol, based on the
+[MLS protocol](https://datatracker.ietf.org/doc/rfc9420/).
+- Specification of an Ethereum-based authentication protocol, based on
+[SIWE](https://eips.ethereum.org/EIPS/eip-4361).
+
+## Protocol flow
+
+The following steps outline the flow of the protocol.
+
+### Account Registration and Key Generation
+
+Each user starts by registering their Ethereum account.
+It is used as the authentication service.
+Upon registration, the user generates a ``KeyPackage``
+that contains a public key
+and supporting metadata required for the MLS group.
+
+### Group Initialization and Member Management
+
+When a new group is created, the initiating client generates a new ``GroupContext``.
+It contains a unique group ID and an initial epoch.
+
+To add members, the initiator sends an ``Add`` request,
+which includes the new member’s KeyPackage.
+
+Existing members can update their identity in the group using the ``Update`` proposal,
+which replaces the sender’s LeafNode in the group’s ratchet tree.
+
+Members can be removed from the group via a ``Remove`` proposal,
+which specifies the index of the member to be removed from the tree.
+Upon processing this proposal,
+the group generates a new group key to ensure that removed members
+no longer have access to future communications.
+
+### Commit and Authentication
+
+After receiving a valid list of proposals (``Add``, ``Update``, ``Remove``),
+a client initiates a ``Commit`` message,
+processing the pending proposals and updates the group’s state.
+The ``Commit`` message includes the updated ``GroupContext``
+and a ``FramedContentAuthData``,
+which ensures that all group members are aware of the changes.
+Each member verifies the ``FramedContentAuthData`` to ensure the changes are consistent
+with the current epoch of the ``GroupContext``.
+
+### Message Exchange
+
+Once the group is established and all members have processed the latest ``Commit``,
+messages can be securely exchanged using
+the session keyderived from the group's ratchet tree.
+Each message is encapsulated within a ``FramedContent`` structure
+and authenticated using the ``FramedContentAuthData``,
+ensuring message integrity.
+Group members use the current ``GroupContext`` to validate incoming messages
+and ensure they are consistent with the current group state.
+
+### Use of smart contracts
+
+This protocol accomplishes decentralization
+through the use of smart contracts for managing groups.
+They are used to register users in a group and keep the state of the group updated.
+Smart contracts MUST include an ACL to keep the state of the group.
+
+## Private group messaging protocol
+
+### Background
+
+The [Messaging Layer Security](https://datatracker.ietf.org/doc/rfc9420/) (MLS)
+protocol aims at providing a group of users with
+end-to-end encryption in an authenticated and asynchronous way.
+The main security characteristics of the protocol are:
+Message confidentiality and authentication, sender authentication,
+membership agreement, post-remove
+and post-update security, and forward secrecy and
+post-compromise security.
+The MLS protocol achieves: low-complexity, group integrity,
+synchronization and extensibility.
+
+This document describes how the structure and methods of the
+[MLS](https://datatracker.ietf.org/doc/rfc9420/) protocol
+are extended for their application in decentralized environments.
+The approach described in this document makes use of smart contracts.
+It makes use of a smart contract to manage each group chat.
+Furthermore, this document describes how to use the Sign-in With Ethereum protocol
+as authentication method.
+
+### Structure
+
+Each MLS session uses a single cipher suite that specifies the
+primitives to be used in group key computations. The cipher suite MUST
+use:
+
+- `X488` as Diffie-Hellman function.
+- `SHA256` as KDF.
+- `AES256-GCM` as AEAD algorithm.
+- `SHA512` as hash function.
+- `XEd448` for digital signatures.
+
+Formats for public keys, signatures and public-key encryption MUST
+follow Section 5.1 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Hash-based identifiers
+
+Some MLS messages refer to other MLS objects by hash.
+These identifiers MUST be computed according to Section 5.2 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Credentials
+
+Each member of a group presents a credential that provides one or more
+identities for the
+member and associates them with the member's signing key.
+The identities and signing key are verified by the Authentication
+Service in use for a group.
+
+Credentials MUST follow the specifications of section 5.3 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+Below follows the flow diagram for the generation of credentials.
+Users MUST generate key pairs by themselves.
+![figure1](./images/eth-secpm_credential.png)
+
+### Message framing
+
+Handshake and application messages use a common framing structure
+providing encryption to ensure confidentiality within the group,
+and signing to authenticate the sender.
+
+The structure is:
+
+- `PublicMessage`: represents a message that is only signed,
+and not encrypted.
+The definition and the encoding/decoding of a `PublicMessage`
+MUST follow the specification in section 6.2 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+- `PrivateMessage`: represents a signed and encrypted message,
+with protections for both the content of the message and related metadata.
+
+The definition, and the encoding/decoding of a `PrivateMessage`
+MUST follow the specification in section 6.3 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+Applications MUST use `PrivateMessage` to encrypt application messages.
+
+Applications SHOULD use `PrivateMessage` to encode handshake messages.
+
+Each encrypted MLS message carries a "generation" number which
+is a per-sender incrementing counter.
+If a group member observes a gap in the generation sequence
+for a sender, then they know that they have missed
+a message from that sender.
+
+### Nodes contents
+
+> This section makes use of sections 4 and 7 of
+[RFC9420](https://datatracker.ietf.org/docrfc9420/).
+
+The nodes of a ratchet tree
+(Section 4 in [RFC9420](https://datatracker.ietf.org/docrfc9420/))
+contain several types of data:
+
+- Leaf nodes describe individual members.
+- Parent nodes describe subgroups.
+
+Contents of each kind of node, and its structure MUST follow
+the indications described in sections 7.1 and 7.2 of
+[RFC9420](https://datatracker.ietf.org/docrfc9420/).
+
+### Leaf node validation
+
+`KeyPackage` objects describe the client's capabilities and
+provides keys that can be used to add the client to a group.
+
+The validity of a leaf node needs to be verified
+at the following stages:
+
+- When a leaf node is downloaded in a `KeyPackage`,
+before it is used to add the client to the group.
+- When a leaf node is received by a group member in an
+Add, Update, or Commit message.
+- When a client validates a ratchet tree.
+
+A client MUST verify the validity of a leaf node following the
+instructions of section 7.3 in
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Ratchet tree evolution
+
+Whenever a member initiates an epoch change, they MAY need to refresh
+the key pairs of their leaf and of the nodes on their direct path.
+This is done to keep forward secrecy and post-compromise security.
+The member initiating the epoch change MUST follow this procedure.
+A member updates the nodes along its direct path as follows:
+
+- Blank all the nodes on the direct path from the leaf to the root.
+- Generate a fresh HPKE key pair for the leaf.
+- Generate a sequence of path secrets, one for each node on the leaf's
+filtered direct path.
+
+It MUST follow the procedure described in section 7.4 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+- Compute the sequence of HPKE key pairs `(node_priv,node_pub)`,
+one for each node on the leaf's direct path.
+
+It MUST follow the procedure described in section 7.4 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Views of the tree synchronization
+
+After generating fresh key material and applying it to update
+their local tree state, the generator broadcasts this update
+to other members of the group.
+This operation MUST be done according to section 7.5 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Leaf synchronization
+
+Changes to group memberships MUST be represented by
+adding and removing leaves of the tree.
+This corresponds to increasing or decreasing the depth of the tree,
+resulting in the number of leaves being doubled or halved.
+These operations MUST be done as described in section 7.7 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Tree and parent hashing
+
+Group members can agree on the cryptographic state of the group by
+generating a hash value that represents the contents of the group
+ratchet tree and the member’s credentials.
+The hash of the tree is the hash of its root node,
+defined recursively from the leaves.
+Tree hashes summarize the state of a tree at point in time.
+The hash of a leaf is the hash of the `LeafNodeHashInput` object.
+At the same time the hash of a parent node, including the root,
+is the hash of a `ParentNodeHashInput` object.
+Parent hashes capture information about
+how keys in the tree were populated.
+
+Tree and parent hashing MUST follow the directions
+in Sections 7.8 and 7.9 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Key schedule
+
+Group keys are derived using the `Extract` and `Expand` functions from
+the KDF for the group's cipher suite,
+as well as the functions defined below:
+
+```text
+ExpandWithLabel(Secret, Label, Context, Length) = KDF.Expand(Secret, KDFLabel, Length)
+DeriveSecret(Secret, Label) = ExpandWithLabel(Secret, Label, "", KDF.Nh)
+
+```
+
+`KDFLabel` MUST be specified as:
+
+```text
+struct {
+ uint16 length;
+ opaque label;
+ opaque context;
+} KDFLabel;
+```
+
+The fields of `KDFLabel` MUST be:
+
+```text
+length = Length;
+label = "MLS 1.0 " + Label;
+context = Context;
+
+```
+
+Each member of the group MUST maintaint a `GroupContext` object
+summarizing the state of the group.
+
+The sturcture of such object MUST be:
+
+```text
+struct {
+ ProtocolVersion version = mls10;
+ CipherSuite cipher_suite;
+ opaque group_id;
+ uint64 epoch;
+ opaque tree_hash;
+ opaque confirmed_trasncript_hash;
+ Extension extension;
+} GroupContext;
+```
+
+The use of key scheduling MUST follow the indications
+in sections 8.1 - 8.7 in
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Secret trees
+
+For the generation of encryption keys and nonces, the key schedule
+begins with the `encryption_secret` at the root and derives a tree of
+secrets with the same structure as the group's ratchet tree.
+Each leaf in the secret tree is associated with the same group member
+as the corresponding leaf in the ratchet tree.
+
+If `N` is a parent node in the secret tree, the secrets of the children
+of `N` MUST be defined following section 9 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+#### Encryption keys
+
+MLS encrypts three different types of information:
+
+- Metadata (sender information).
+- Handshake messages (Proposal and Commit).
+- Application messages.
+
+For handshake and application messages, a sequence of keys is derived
+via a sender ratchet.
+Each sender has their own sender ratchet, and each step along the
+ratchet is called a generation. These procedures MUST follow
+section 9.1 of [RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+#### Deletion schedule
+
+All security-sensitive values MUST be deleted
+as soon as they are consumed.
+
+A sensitive value S is consumed if:
+
+- S was used to encrypt or (successfully) decrypt a message.
+- A key, nonce, or secret derived from S has been consumed.
+
+The deletion procedure MUST follow the instruction described in
+section 9.2 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Key packages
+
+KeyPackage objects are used to ease the addition of clients
+to a group asynchronously.
+
+A KeyPackage object specifies:
+
+- Protocol version and cipher suite supported by the client.
+- Public keys that can be used to encrypt Welcome messages.
+Welcome messages provide new members with
+the information to initialize their state
+for the epoch in which they were added
+or in which they want to
+add themselves to the group
+- The content of the leaf node that should be added to the tree to
+represent this client.
+
+KeyPackages are intended to be used only once and SHOULD NOT be reused.
+
+Clients MAY generate and publish multiple KeyPackages to support
+multiple cipher suites.
+
+The structure of the object MUST be:
+
+```text
+struct {
+ ProtocolVersion version;
+ CipherSuite cipher_suite;
+ HPKEPublicKey init_key;
+ LeafNode leaf_node;
+ Extension extensions;
+ /* SignWithLabel(., "KeyPackageTBS", KeyPackageTBS) */
+ opaque signature;
+}
+```
+
+```text
+struct {
+ ProtocolVersion version;
+ CipheSuite cipher_suite;
+ HPKEPublicKey init_key;
+ LeafNode leaf_node;
+ Extension extensions;
+}
+```
+
+`KeyPackage` object MUST be verified when:
+
+- A `KeyPackage` is downloaded by a group member, before it is used to
+add the client to the group.
+- When a `KeyPackage` is received by a group member in an `Add`
+message.
+
+Verification MUST be done as follows:
+
+- Verify that the cipher suite and protocol version of the `KeyPackage`
+match those in the `GroupContext`.
+- Verify that the `leaf_node` of the `KeyPackage` is valid for a
+`KeyPackage`.
+- Verify that the signature on the `KeyPackage` is valid.
+- Verify that the value of `leaf_node.encryption_key` is different from
+the value of the `init_key field`.
+
+HPKE public keys are opaque values in a format defined by Section 4 of
+[RFC9180](https://datatracker.ietf.org/doc/rfc9180/).
+
+Signature public keys are represented as opaque values in a format
+defined by the cipher suite's signature scheme.
+
+### Group creation
+
+A group is always created with a single member.
+Other members are then added to the group using the usual
+Add/Commit mechanism.
+The creator of a group MUST set:
+
+- the group ID.
+- cipher suite.
+- initial extensions for the group.
+
+If the creator intends to add other members at the time of creation,
+then it SHOULD fetch `KeyPackages` for those members, and select a
+cipher suite and extensions according to their capabilities.
+
+The creator MUST use the capabilities information in these
+`KeyPackages` to verify that the chosen version and cipher suite is the
+best option supported by all members.
+
+Group IDs SHOULD be constructed so they are unique with
+high probability.
+
+To initialize a group, the creator of the group MUST initialize a one
+member group with the following initial values:
+
+- Ratchet tree: A tree with a single node, a leaf node containing an
+HPKE public key and credential for the creator.
+- Group ID: A value set by the creator.
+- Epoch: `0`.
+- Tree hash: The root hash of the above ratchet tree.
+- Confirmed transcript hash: The zero-length octet string.
+- Epoch secret: A fresh random value of size `KDF.Nh`.
+- Extensions: Any values of the creator's choosing.
+
+The creator MUST also calculate the interim transcript hash:
+
+- Derive the `confirmation_key` for the epoch according to Section 8 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+- Compute a `confirmation_tag` over the empty
+`confirmed_transcript_hash` using the `confirmation_key` as described
+in Section 8.1 of [RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+- Compute the updated `interim_transcript_hash` from the
+`confirmed_transcript_hash` and the `confirmation_tag` as described in
+Section 8.2 [RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+All members of a group MUST support the cipher suite and protocol
+version in use. Additional requirements MAY be imposed by including a
+`required_capabilities` extension in the `GroupContext`.
+
+```text
+struct {
+ ExtensionType extension_types;
+ ProposalType proposal_types;
+ CredentialType credential_types;
+}
+```
+
+The flow diagram shows the procedure to fetch key material
+from other users:
+
+![figure2](./images/eth-secpm_fetching.png)
+
+Below follows the flow diagram for the creation of a group:
+
+![figure3](./images/eth-secpm_creation.png)
+
+### Group evolution
+
+Group membership can change, and existing members can change their keys
+in order to achieve post-compromise security.
+In MLS, each such change is accomplished by a two-step process:
+
+- A proposal to make the change is broadcast to the group in a
+Proposal message.
+- A member of the group or a new member broadcasts a Commit message
+that causes one or more proposed changes to enter into effect.
+
+The group evolves from one cryptographic state to another each time a
+Commit message is sent and processed.
+These states are called epochs and are uniquely identified among states
+of the group by eight-octet epoch values.
+
+Proposals are included in a `FramedContent` by way of a `Proposal`
+structure that indicates their type:
+
+```text
+struct {
+ ProposalType proposal_type;
+ select (Proposal.proposal_type) {
+ case add: Add:
+ case update: Update;
+ case remove: Remove;
+ case psk: PreSharedKey;
+ case reinit: ReInit;
+ case external_init: ExternalInit;
+ case group_context_extensions: GroupContextExtensions;
+ }
+}
+```
+
+On receiving a `FramedContent` containing a `Proposal`, a client MUST
+verify the signature inside `FramedContentAuthData` and that the epoch
+field of the enclosing FramedContent is equal to the epoch field of the
+current GroupContext object.
+If the verification is successful, then the Proposal SHOULD be cached
+in such a way that it can be retrieved by hash in a later Commit
+message.
+
+Proposals are organized as follows:
+
+- `Add`: requests that a client with a specified KeyPackage be added to
+the group.
+- `Update`: similar to Add, it replaces the sender's LeafNode in the
+tree instead of adding a new leaf to the tree.
+- `Remove`: requests that the member with the leaf index removed be
+removed from the group.
+- `ReInit`: requests to reinitialize the group with different
+parameters.
+- `ExternalInit`: used by new members that want to join a group by
+using an external commit.
+- `GroupContentExtensions`: it is used to update the list of extensions
+in the GroupContext for the group.
+
+Proposals structure and semantics MUST follow sections 12.1.1 - 12.1.7
+of [RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+Any list of commited proposals MUST be validated either by a the group
+member who created the commit, or any group member processing
+such commit.
+The validation MUST be done according to one of the procedures
+described in Section 12.2 of
+[RFC9420](https://datatracker.ietf.orgdoc/rfc9420/).
+
+When creating or processing a Commit, a client applies a list of
+proposals to the ratchet tree and `GroupContext`.
+The client MUST apply the proposals in the list in the order described
+in Section 12.3 of [RFC9420](https://datatracker.ietf.org/docrfc9420/).
+
+Below follows the flow diagram for the addition of a member to a group:
+
+![figure4](./images/eth-secpm_add.png)
+
+The diagram below shows the procedure to remove a group member:
+
+![figure5](./images/eth-secpm_remove.png)
+
+The flow diagram below shows an update procedure:
+
+![figure6](./images/eth-secpm_update.png)
+
+### Commit messages
+
+Commit messages initiate new group epochs.
+It informs group members to update their representation of the state of
+the group by applying the proposals and advancing the key schedule.
+
+Each proposal covered by the Commit is included by a
+`ProposalOrRef` value.
+`ProposalOrRef` identify the proposal to be applied by value
+or by reference.
+Commits that refer to new Proposals from the committer
+can be included by value.
+Commits for previously sent proposals from anyone can be sent
+by reference.
+Proposals sent by reference are specified by including the hash of the
+`AuthenticatedContent`.
+
+Group members that have observed one or more valid proposals within an
+epoch MUST send a Commit message before sending application data.
+A sender and a receiver of a Commit MUST verify that the committed list
+of proposals is valid.
+The sender of a Commit SHOULD include all valid proposals received
+during the current epoch.
+
+Functioning of commits MUST follow the instructions of Section 12.4 of
+[RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+### Application messages
+
+Handshake messages provide an authenticated group key exchange
+to clients.
+To protect application messages sent among the members of a group, the
+`encryption_secret` provided by the key schedule is used to derive a
+sequence of nonces and keys for message encryption.
+
+Each client MUST maintain their local copy of the key schedule for each
+epoch during which they are a group member.
+They derive new keys, nonces, and secrets as needed. This data MUST be
+deleted as soon as they have been used.
+
+Group members MUST use the AEAD algorithm associated with the
+negotiated MLS ciphersuite to encrypt and decrypt Application messages
+according to the Message Framing section.
+The group identifier and epoch allow a device to know which group
+secrets should be used and from which Epoch secret to start computing
+other secrets and keys.
+Application messages SHOULD be padded to provide resistance against
+traffic analysis techniques.
+This avoids additional information to be provided to an attacker in
+order to guess the length of the encrypted message.
+Padding SHOULD be used on messages with zero-valued bytes before
+AEAD encryption.
+
+Functioning of application messages MUST follow the instructions of
+Section 15 of [RFC9420](https://datatracker.ietf.org/doc/rfc9420/).
+
+## Implementation of the onchain component of the protocol
+
+### Assumptions
+
+- Users have set a secure 1-1 communication channel.
+- Each group is managed by a separate smart contract.
+
+### Addition of members to a group
+
+1. On-chain: Alice creates a Smart Contract with ACL.
+2. Off-chain: Alice sends the contract address
+and an invitation message to Bob over the secure channel.
+3. Off-chain: Bob sends a signed response
+confirming his Ethereum address and agreement to join.
+4. Off-chain: Alice verifies the signature using the public key of Bob.
+5. On-chain: Alice adds Bob’s address to the ACL.
+6. Off-chain: Alice sends a welcome message to Bob.
+7. Off-chain: Alice sends a broadcast message to all group members,
+notifying them the addition of Bob.
+
+![figure8](./images/eth-secpm_onchain-register-2.png)
+
+### Updates in groups
+
+Removal requests and update requests are considered the same operation.
+One assumes Alice is the creator of the contract.
+They MUST be processed as follows:
+
+1. Off-chain: Bob creates a new update request.
+2. Off-chain: Bob sends the update request to Alice.
+3. Off-chain: Alice verifies the request.
+4. On-chain: If the verification is successfull,
+Alice sends it to the smart contract for registration.
+5. Off-chain: Alice sends a broadcast message
+communicating the update to all users.
+
+![figure9](./images/eth-secpm_onchain-update.png)
+
+## Ethereum-based authentication protocol
+
+### Introduction
+
+Sign-in with Ethereum describes how Ethereum accounts authenticate with
+off-chain services by signing a standard message format
+parameterized by scope, session details, and security mechanisms.
+Sign-in with Ethereum (SIWE), which is described in the
+[EIP 4361](https://eips.ethereum.org/EIPS/eip-4361),
+MUST be the authentication method required.
+
+### Pattern
+
+#### Message format (ABNF)
+
+A SIWE Message MUST conform with the following Augmented Backus–Naur
+Form ([RFC 5234](https://datatracker.ietf.org/doc/html/rfc5234))
+expression.
+
+```text
+sign-in-with-ethereum =
+ [ scheme "://" ] domain %s" wants you to sign in with your
+ Ethereum account:" LF address LF
+ LF
+ [ statement LF ]
+ LF
+ %s"URI: " uri LF
+ %s"Version: " version LF
+ %s"Chain ID: " chain-id LF
+ %s"Nonce: " nonce LF
+ %s"Issued At: " issued-at
+ [ LF %s"Expiration Time: " expiration-time ]
+ [ LF %s"Not Before: " not-before ]
+ [ LF %s"Request ID: " request-id ]
+ [ LF %s"Resources:"
+ resources ]
+
+scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ ; See RFC 3986 for the fully contextualized
+ ; definition of "scheme".
+
+domain = authority
+ ; From RFC 3986:
+ ; authority = [ userinfo "@" ] host [ ":" port ]
+ ; See RFC 3986 for the fully contextualized
+ ; definition of "authority".
+
+address = "0x" 40*40HEXDIG
+ ; Must also conform to captilization
+ ; checksum encoding specified in EIP-55
+ ; where applicable (EOAs).
+
+statement = *( reserved / unreserved / " " )
+ ; See RFC 3986 for the definition
+ ; of "reserved" and "unreserved".
+ ; The purpose is to exclude LF (line break).
+
+uri = URI
+ ; See RFC 3986 for the definition of "URI".
+
+version = "1"
+
+chain-id = 1*DIGIT
+ ; See EIP-155 for valid CHAIN_IDs.
+
+nonce = 8*( ALPHA / DIGIT )
+ ; See RFC 5234 for the definition
+ ; of "ALPHA" and "DIGIT".
+
+issued-at = date-time
+expiration-time = date-time
+not-before = date-time
+ ; See RFC 3339 (ISO 8601) for the
+ ; definition of "date-time".
+
+request-id = *pchar
+ ; See RFC 3986 for the definition of "pchar".
+
+resources = *( LF resource )
+
+resource = "- " URI
+```
+
+This specification defines the following SIWE Message fields that can
+be parsed from a SIWE Message by following the rules in
+ABNF Message Format.
+This section follows the section _ABNF message format_
+in [EIP 4361](https://eips.ethereum.org/EIPS/eip-4361).
+
+- `scheme` OPTIONAL. The URI scheme of the origin of the request.
+Its value MUST be a
+[RFC 3986](https://datatracker.ietf.org/doc/htmlrfc3986)
+URI scheme.
+
+- `domain` REQUIRED.
+The domain that is requesting the signing.
+Its value MUST be a [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)
+authority. The authority includes an OPTIONAL port.
+If the port is not specified, the default
+port for the provided scheme is assumed.
+
+If scheme is not specified, HTTPS is assumed by default.
+
+- `address` REQUIRED. The Ethereum address performing the signing.
+Its value SHOULD be conformant to mixed-case checksum address encoding
+specified in ERC-55 where applicable.
+
+- `statement` OPTIONAL. A human-readable ASCII assertion that the user
+will sign which MUST NOT include '\n' (the byte 0x0a).
+- `uri` REQUIRED. An
+[RFC 3986](https://datatracker.ietf.org/doc/htmlrfc3986)
+URI referring to the resource that is the subject of the
+signing.
+
+- `version` REQUIRED. The current version of the SIWE Message, which
+MUST be 1 for this specification.
+
+- `chain-id` REQUIRED. The EIP-155 Chain ID to which the session is
+bound, and the network where Contract Accounts MUST be resolved.
+
+- `nonce` REQUIRED. A random string (minimum 8 alphanumeric characters)
+chosen by the relying party and used to prevent replay attacks.
+
+- `issued-at` REQUIRED. The time when the message was generated,
+typically the current time.
+
+Its value MUST be an ISO 8601 datetime string.
+
+- `expiration-time` OPTIONAL. The time when the signed authentication
+message is no longer valid.
+
+Its value MUST be an ISO 8601 datetime string.
+
+- `not-before` OPTIONAL. The time when the signed authentication
+message will become valid.
+
+Its value MUST be an ISO 8601 datetime string.
+
+- `request-id` OPTIONAL. An system-specific identifier that MAY be used
+to uniquely refer to the sign-in request.
+
+- `resources` OPTIONAL. A list of information or references to
+information the user wishes to have resolved as part of authentication
+by the relying party.
+
+Every resource MUST be a RFC 3986 URI separated by "\n- " where \n is
+the byte 0x0a.
+
+#### Signing and Verifying Messages with Ethereum Accounts
+
+- For Externally Owned Accounts, the verification method specified in
+[ERC-191](https://eips.ethereum.org/EIPS/eip-191)
+MUST be used.
+
+- For Contract Accounts,
+
+ - The verification method specified in
+[ERC-1271](https://eips.ethereum.org/EIPS/eip-1271)
+SHOULD be used.
+Otherwise, the implementer MUST clearly define the
+verification method to attain security and interoperability
+for both wallets and relying parties.
+
+ - When performing [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271)
+signature verification, the contract performing the verification MUST
+be resolved from the specified `chain-id`.
+
+ - Implementers SHOULD take into consideration that
+[ERC-1271](https://eips.ethereum.org/EIPS/eip-1271)
+implementations are not required to be pure functions.
+They can return different results for the same inputs depending
+on blockchain state.
+This can affect the security model and session validation rules.
+
+#### Resolving Ethereum Name Service (ENS) Data
+
+- The relying party or wallet MAY additionally perform resolution of
+ENS data, as this can improve the user experience by displaying human
+friendly information that is related to the `address`.
+Resolvable ENS data include:
+
+ - The primary ENS name.
+ - The ENS avatar.
+ - Any other resolvable resources specified in the ENS documentation.
+
+- If resolution of ENS data is performed, implementers SHOULD take
+precautions to preserve user privacy and consent.
+Their `address` could be forwarded to third party services as part of
+the resolution process.
+
+#### Implementer steps: specifying the request origin
+
+The `domain` and, if present, the `scheme`, in the SIWE Message MUST
+correspond to the origin from where the signing request was made.
+
+#### Implementer steps: verifying a signed message
+
+The SIWE Message MUST be checked for conformance to the ABNF Message
+Format and its signature MUST be checked as defined in Signing and
+Verifying Messages with Ethereum Accounts.
+
+#### Implementer steps: creating sessions
+
+Sessions MUST be bound to the address and not to further resolved
+resources that can change.
+
+#### Implementer steps: interpreting and resolving resources
+
+Implementers SHOULD ensure that that URIs in the listed resources are
+human-friendly when expressed in plaintext form.
+
+#### Wallet implementer steps: verifying the message format
+
+The full SIWE message MUST be checked for conformance to the ABNF
+defined in ABNF Message Format.
+
+Wallet implementers SHOULD warn users if the substring `"wants you to
+sign in with your Ethereum account"` appears anywhere in an
+[ERC-191](https://eips.ethereum.org/EIPS/eip-191)
+message signing request unless the message fully conforms to the format
+defined ABNF Message Format.
+
+#### Wallet implementer steps: verifying the request origin
+
+Wallet implementers MUST prevent phishing attacks by verifying the
+origin of the request against the `scheme` and `domain` fields in the
+SIWE Message.
+
+The origin SHOULD be read from a trusted data source such as the
+browser window or over WalletConnect
+[ERC-1328](https://eips.ethereum.org/EIPS/eip-1328) sessions for
+comparison against the signing message contents.
+
+Wallet implementers MAY warn instead of rejecting the verification if
+the origin is pointing to localhost.
+
+The following is a RECOMMENDED algorithm for Wallets to conform with
+the requirements on request origin verification defined by
+this specification.
+
+The algorithm takes the following input variables:
+
+- fields from the SIWE message.
+- `origin` of the signing request: the origin of the page which
+requested the signin via the provider.
+- `allowedSchemes`: a list of schemes allowed by the Wallet.
+- `defaultScheme`: a scheme to assume when none was provided. Wallet
+implementers in the browser SHOULD use https.
+- developer mode indication: a setting deciding if certain risks should
+be a warning instead of rejection. Can be manually configured or
+derived from `origin` being localhost.
+
+The algorithm is described as follows:
+
+- If `scheme` was not provided, then assign `defaultScheme` as scheme.
+- If `scheme` is not contained in `allowedSchemes`, then the `scheme`
+is not expected and the Wallet MUST reject the request.
+Wallet implementers in the browser SHOULD limit the list of
+allowedSchemes to just 'https' unless a developer mode is activated.
+- If `scheme` does not match the scheme of origin, the Wallet SHOULD
+reject the request.
+Wallet implementers MAY show a warning instead of rejecting the request
+if a developer mode is activated.
+In that case the Wallet continues processing the request.
+- If the `host` part of the `domain` and `origin` do not match, the
+Wallet MUST reject the request unless the Wallet is in developer mode.
+In developer mode the Wallet MAY show a warning instead and continues
+procesing the request.
+- If `domain` and `origin` have mismatching subdomains, the Wallet
+SHOULD reject the request unless the Wallet is in developer mode.
+In developer mode the Wallet MAY show a warning instead and continues
+procesing the request.
+- Let `port` be the port component of `domain`, and if no port is
+contained in domain, assign port the default port specified for the
+scheme.
+- If `port` is not empty, then the Wallet SHOULD show a warning if the
+`port` does not match the port of `origin`.
+- If `port` is empty, then the Wallet MAY show a warning if `origin`
+contains a specific port.
+- Return request origin verification completed.
+
+#### Wallet implementer steps: creating SIWE interfaces
+
+Wallet implementers MUST display to the user the following fields from
+the SIWE Message request by default and prior to signing, if they are
+present: `scheme`, `domain`, `address`, `statement`, and `resources`.
+Other present fields MUST also be made available to the user prior to
+signing either by default or through an extended interface.
+
+Wallet implementers displaying a plaintext SIWE Message to the user
+SHOULD require the user to scroll to the bottom of the text area
+prior to signing.
+
+Wallet implementers MAY construct a custom SIWE user interface by
+parsing the ABNF terms into data elements for use in the interface.
+The display rules above still apply to custom interfaces.
+
+#### Wallet implementer steps: supporting internationalization (i18n)
+
+After successfully parsing the message into ABNF terms, translation MAY
+happen at the UX level per human language.
+
+## Consideration to secure 1-to-1 channels
+
+There are situations where users need to set one-to-one communication
+channels in a secure way. One of these situations is when a user A
+wants to add a new user B to an existing group.
+In such situations communications between users MUST be done following
+the instructions in this
+[specification](https://github.com/vacp2p/rfc-index/blob/eth-secpm-splitted/vac/raw/eth-secure-channel.md)
+describing the use of X3DH in combination with the double ratchet mechanism.
+
+## Considerations with respect to decentralization
+
+The MLS protocol assumes the existence of a (central, untrusted)
+*delivery service*, whose responsabilites include:
+
+- Acting as a directory service providing the initial
+keying material for clients to use.
+- Routing MLS messages among clients.
+
+The central delivery service can be avoided in protocols using the
+publish/gossip approach, such as
+[gossipsub](https://github.com/libp2p/specs/tree/master/pubsub/gossipsub).
+
+Concerning keys, each node can generate and disseminate their
+encryption key among the other nodes, so they can create a local
+version of the tree that allows for the generation of the group key.
+
+Another important component is the _authentication service_, which is
+replaced with SIWE in this specification.
+
+## Privacy and Security Considerations
+
+- For the information retrieval, the algorithm MUST include a access
+control mechanisms to restrict who can call the set and get functions.
+- One SHOULD include event logs to track changes in public keys.
+- The curve vurve448 MUST be chosen due to its higher security level:
+224-bit security instead of the 128-bit security provided by X25519.
+- It is important that Bob MUST NOT reuse `SPK`.
+
+## Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
+
+## References
+
+- [Augmented BNF for Syntax Specifications](https://datatracker.ietf.org/doc/html/rfc5234)
+- [Gossipsub](https://github.com/libp2p/specs/tree/master/pubsub/gossipsub)
+- [HMAC-based Extract-and-Expand Key Derivation Function](https://www.ietf.org/rfc/rfc5869.txt)
+- [Hybrid Public Key Encryption](https://datatracker.ietf.org/doc/rfc9180/)
+- [Security Analysis and Improvements for the IETF MLS Standard for Group Messaging](https://eprint.iacr.org/2019/1189.pdf)
+- [Signed Data Standard](https://eips.ethereum.org/EIPS/eip-191)
+- [Sign-In with Ethereum](https://eips.ethereum.org/EIPS/eip-4361)
+- [Standard Signature Validation Method for Contracts](https://eips.ethereum.org/EIPS/eip-1271)
+- [The Messaging Layer Security Protocol](https://datatracker.ietf.org/doc/rfc9420/)
+- [Toy Ethereum Private Messaging Protocol](https://rfc.vac.dev/spec/20/)
+- [Uniform Resource Identifier](https://datatracker.ietf.org/doc/html/rfc3986)
+- [WalletConnect URI Format](https://eips.ethereum.org/EIPS/eip-1328)
diff --git a/vac/raw/eth-secure-channel.md b/vac/raw/eth-secure-channel.md
new file mode 100644
index 00000000..a6b78793
--- /dev/null
+++ b/vac/raw/eth-secure-channel.md
@@ -0,0 +1,345 @@
+---
+title: ETH-SECURE-CHANNEL
+name: Secure 1-to-1 channel setup using X3DH and the double ratchet
+status: raw
+category: Standards Track
+tags:
+editor: Ramses Fernandez
+contributors:
+---
+
+## Motivation
+
+The need for secure communications has become paramount.
+This specification outlines a protocol describing a
+secure 1-to-1 comunication channel between 2 users. The
+main components are the X3DH key establishment mechanism,
+combined with the double ratchet. The aim of this
+combination of schemes is providing a protocol with both
+forward secrecy and post-compromise security.
+
+## Theory
+
+The specification is based on the noise protocol framework.
+It corresponds to the double ratchet scheme combined with
+the X3DH algorithm, which will be used to initialize the former.
+We chose to express the protocol in noise to be be able to use
+the noise streamlined implementation and proving features.
+The X3DH algorithm provides both authentication and forward
+secrecy, as stated in the
+[X3DH specification](https://signal.org/docs/specifications/x3dh/).
+
+This protocol will consist of several stages:
+
+1. Key setting for X3DH: this step will produce
+prekey bundles for Bob which will be fed into X3DH.
+It will also allow Alice to generate the keys required
+to run the X3DH algorithm correctly.
+2. Execution of X3DH: This step will output
+a common secret key `SK` together with an additional
+data vector `AD`. Both will be used in the double
+ratchet algorithm initialization.
+3. Execution of the double ratchet algorithm
+for forward secure, authenticated communications,
+using the common secret key `SK`, obtained from X3DH, as a root key.
+
+The protocol assumes the following requirements:
+
+- Alice knows Bob’s Ethereum address.
+- Bob is willing to participate in the protocol,
+and publishes his public key.
+- Bob’s ownership of his public key is verifiable,
+- Alice wants to send message M to Bob.
+- An eavesdropper cannot read M’s content
+even if she is storing it or relaying it.
+
+## Syntax
+
+### Cryptographic suite
+
+The following cryptographic functions MUST be used:
+
+- `X488` as Diffie-Hellman function `DH`.
+- `SHA256` as KDF.
+- `AES256-GCM` as AEAD algorithm.
+- `SHA512` as hash function.
+- `XEd448` for digital signatures.
+
+### X3DH initialization
+
+This scheme MUST work on the curve curve448.
+The X3DH algorithm corresponds to the IX pattern in Noise.
+
+Bob and Alice MUST define personal key pairs
+`(ik_B, IK_B)` and `(ik_A, IK_A)` respectively where:
+
+- The key `ik` must be kept secret,
+- and the key `IK` is public.
+
+Bob MUST generate new keys using
+`(ik_B, IK_B) = GENERATE_KEYPAIR(curve = curve448)`.
+
+Bob MUST also generate a public key pair
+`(spk_B, SPK_B) = GENERATE_KEYPAIR(curve = curve448)`.
+
+`SPK` is a public key generated and stored at medium-term.
+Both signed prekey and the certificate MUST
+undergo periodic replacement.
+After replacing the key,
+Bob keeps the old private key of `SPK`
+for some interval, dependant on the implementation.
+This allows Bob to decrypt delayed messages.
+
+Bob MUST sign `SPK` for authentication:
+`SigSPK = XEd448(ik, Encode(SPK))`
+
+A final step requires the definition of
+`prekey_bundle = (IK, SPK, SigSPK, OPK_i)`
+
+One-time keys `OPK` MUST be generated as
+`(opk_B, OPK_B) = GENERATE_KEYPAIR(curve = curve448)`.
+
+Before sending an initial message to Bob,
+Alice MUST generate an AD: `AD = Encode(IK_A) || Encode(IK_B)`.
+
+Alice MUST generate ephemeral key pairs
+`(ek, EK) = GENERATE_KEYPAIR(curve = curve448)`.
+
+The function `Encode()` transforms a
+curve448 public key into a byte sequence.
+This is specified in the [RFC 7748](http://www.ietf.org/rfc/rfc7748.txt)
+on elliptic curves for security.
+
+One MUST consider `q = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885`
+for digital signatures with `(XEd448_sign, XEd448_verify)`:
+
+```text
+XEd448_sign((ik, IK), message):
+ Z = randbytes(64)
+ r = SHA512(2^456 - 2 || ik || message || Z )
+ R = (r * convert_mont(5)) % q
+ h = SHA512(R || IK || M)
+ s = (r + h * ik) % q
+ return (R || s)
+```
+
+```text
+XEd448_verify(u, message, (R || s)):
+ if (R.y >= 2^448) or (s >= 2^446): return FALSE
+ h = (SHA512(R || 156326 || message)) % q
+ R_check = s * convert_mont(5) - h * 156326
+ if R == R_check: return TRUE
+ return FALSE
+```
+
+```text
+convert_mont(u):
+ u_masked = u % mod 2^448
+ inv = ((1 - u_masked)^(2^448 - 2^224 - 3)) % (2^448 - 2^224 - 1)
+ P.y = ((1 + u_masked) * inv)) % (2^448 - 2^224 - 1)
+ P.s = 0
+ return P
+```
+
+### Use of X3DH
+
+This specification combines the double ratchet
+with X3DH using the following data as initialization for the former:
+
+- The `SK` output from X3DH becomes the `SK`
+input of the double ratchet. See section 3.3 of
+[Signal Specification](https://signal.org/docs/specifications/doubleratchet/)
+for a detailed description.
+- The `AD` output from X3DH becomes the `AD`
+input of the double ratchet. See sections 3.4 and 3.5 of
+[Signal Specification](https://signal.org/docs/specifications/doubleratchet/)
+for a detailed description.
+- Bob’s signed prekey `SigSPKB` from X3DH is used as Bob’s
+initial ratchet public key of the double ratchet.
+
+X3DH has three phases:
+
+1. Bob publishes his identity key and prekeys to a server,
+a network, or dedicated smart contract.
+2. Alice fetches a prekey bundle from the server,
+and uses it to send an initial message to Bob.
+3. Bob receives and processes Alice's initial message.
+
+Alice MUST perform the following computations:
+
+```text
+dh1 = DH(IK_A, SPK_B, curve = curve448)
+dh2 = DH(EK_A, IK_B, curve = curve448)
+dh3 = DH(EK_A, SPK_B)
+SK = KDF(dh1 || dh2 || dh3)
+```
+
+Alice MUST send to Bob a message containing:
+
+- `IK_A, EK_A`.
+- An identifier to Bob's prekeys used.
+- A message encrypted with AES256-GCM using `AD` and `SK`.
+
+Upon reception of the initial message, Bob MUST:
+
+1. Perform the same computations above with the `DH()` function.
+2. Derive `SK` and construct `AD`.
+3. Decrypt the initial message encrypted with `AES256-GCM`.
+4. If decryption fails, abort the protocol.
+
+### Initialization of the double datchet
+
+In this stage Bob and Alice have generated key pairs
+and agreed a shared secret `SK` using X3DH.
+
+Alice calls `RatchetInitAlice()` defined below:
+
+```text
+RatchetInitAlice(SK, IK_B):
+ state.DHs = GENERATE_KEYPAIR(curve = curve448)
+ state.DHr = IK_B
+ state.RK, state.CKs = HKDF(SK, DH(state.DHs, state.DHr))
+ state.CKr = None
+ state.Ns, state.Nr, state.PN = 0
+ state.MKSKIPPED = {}
+```
+
+The HKDF function MUST be the proposal by
+[Krawczyk and Eronen](http://www.ietf.org/rfc/rfc5869.txt).
+In this proposal `chaining_key` and `input_key_material`
+MUST be replaced with `SK` and the output of `DH` respectively.
+
+Similarly, Bob calls the function `RatchetInitBob()` defined below:
+
+```text
+RatchetInitBob(SK, (ik_B,IK_B)):
+ state.DHs = (ik_B, IK_B)
+ state.Dhr = None
+ state.RK = SK
+ state.CKs, state.CKr = None
+ state.Ns, state.Nr, state.PN = 0
+ state.MKSKIPPED = {}
+```
+
+### Encryption
+
+This function performs the symmetric key ratchet.
+
+```text
+RatchetEncrypt(state, plaintext, AD):
+ state.CKs, mk = HMAC-SHA256(state.CKs)
+ header = HEADER(state.DHs, state.PN, state.Ns)
+ state.Ns = state.Ns + 1
+ return header, AES256-GCM_Enc(mk, plaintext, AD || header)
+```
+
+The `HEADER` function creates a new message header
+containing the public key from the key pair output of the `DH`function.
+It outputs the previous chain length `pn`,
+and the message number `n`.
+The returned header object contains ratchet public key
+`dh` and integers `pn` and `n`.
+
+### Decryption
+
+The function `RatchetDecrypt()` decrypts incoming messages:
+
+```text
+RatchetDecrypt(state, header, ciphertext, AD):
+ plaintext = TrySkippedMessageKeys(state, header, ciphertext, AD)
+ if plaintext != None:
+ return plaintext
+ if header.dh != state.DHr:
+ SkipMessageKeys(state, header.pn)
+ DHRatchet(state, header)
+ SkipMessageKeys(state, header.n)
+ state.CKr, mk = HMAC-SHA256(state.CKr)
+ state.Nr = state.Nr + 1
+ return AES256-GCM_Dec(mk, ciphertext, AD || header)
+```
+
+Auxiliary functions follow:
+
+```text
+DHRatchet(state, header):
+ state.PN = state.Ns
+ state.Ns = state.Nr = 0
+ state.DHr = header.dh
+ state.RK, state.CKr = HKDF(state.RK, DH(state.DHs, state.DHr))
+ state.DHs = GENERATE_KEYPAIR(curve = curve448)
+ state.RK, state.CKs = HKDF(state.RK, DH(state.DHs, state.DHr))
+```
+
+```text
+SkipMessageKeys(state, until):
+ if state.NR + MAX_SKIP < until:
+ raise Error
+ if state.CKr != none:
+ while state.Nr < until:
+ state.CKr, mk = HMAC-SHA256(state.CKr)
+ state.MKSKIPPED[state.DHr, state.Nr] = mk
+ state.Nr = state.Nr + 1
+```
+
+```text
+TrySkippedMessageKey(state, header, ciphertext, AD):
+ if (header.dh, header.n) in state.MKSKIPPED:
+ mk = state.MKSKIPPED[header.dh, header.n]
+ delete state.MKSKIPPED[header.dh, header.n]
+ return AES256-GCM_Dec(mk, ciphertext, AD || header)
+ else: return None
+```
+
+## Information retrieval
+
+### Static data
+
+Some data, such as the key pairs `(ik, IK)` for Alice and Bob,
+MAY NOT be regenerated after a period of time.
+Therefore the prekey bundle MAY be stored in long-term
+storage solutions, such as a dedicated smart contract
+which outputs such a key pair when receiving an Ethereum wallet
+address.
+
+Storing static data is done using a dedicated
+smart contract `PublicKeyStorage` which associates
+the Ethereum wallet address of a user with his public key.
+This mapping is done by `PublicKeyStorage`
+using a `publicKeys` function, or a `setPublicKey` function.
+This mapping is done if the user passed an authorization process.
+A user who wants to retrieve a public key associated
+with a specific wallet address calls a function `getPublicKey`.
+The user provides the wallet address as the only
+input parameter for `getPublicKey`.
+The function outputs the associated public key
+from the smart contract.
+
+### Ephemeral data
+
+Storing ephemeral data on Ethereum MAY be done using
+a combination of on-chain and off-chain solutions.
+This approach provides an efficient solution to
+the problem of storing updatable data in Ethereum.
+
+1. Ethereum stores a reference or a hash
+that points to the off-chain data.
+2. Off-chain solutions can include systems like IPFS,
+traditional cloud storage solutions, or
+decentralized storage networks such as a
+[Swarm](https://www.ethswarm.org).
+
+In any case, the user stores the associated
+IPFS hash, URL or reference in Ethereum.
+
+The fact of a user not updating the ephemeral information
+can be understood as Bob not willing to participate in any
+communication.
+
+## Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
+
+## References
+
+- [The Double Ratchet Algorithm](https://signal.org/docs/specifications/doubleratchet/)
+- [The X3DH Key Agreement Protocol](https://signal.org/docs/specifications/x3dh/)
diff --git a/vac/raw/images/eth-secpm_onchain-update.png b/vac/raw/images/eth-secpm_onchain-update.png
index fe79f219..fac47a5f 100644
Binary files a/vac/raw/images/eth-secpm_onchain-update.png and b/vac/raw/images/eth-secpm_onchain-update.png differ