---
# System prepended metadata

title: Group Messaging with Encryption

---

# Group Messaging with Encryption

### Libraries and Functions
#### random
- used to generate the encrypting/decrypting key
```rust
try_from_random
```
#### x_salsa20_poly1305
##### box (symmetric encryption)
- used for encrypting/decrypting messages
```rust
x_salsa20_poly1305_encrypt
x_salsa20_poly1305_decrypt
```
##### secretbox (assymetric encryption)
- used for encrypting group encryption keys
```rust
create_x25519_keypair
x_25519_x_salsa20_poly1305_encrypt
x_25519_x_salsa20_poly1305_decrypt
```

### Structures
```rust
pub struct IdentityKey {
    agent: AgentPubKey,
    key: X25519PubKey,
}

pub struct MessageEntry {
    author: AgentPubKey,
    receiver: Vec<AgentPubKey>,
    group_uuid: String,
    payload: String,
    time_sent: Timestamp,
    time_received: Option<Timestamp>
}

pub struct EncryptedMessageEntry {
    session_id: u32,
    data: XSalsa20Poly1305EncryptedData
}

pub struct GroupKey {
    session_id: u32,
    key: XSalsa20Poly1305KeyRef
}

pub struct EncryptedGroupKey {
    session_id: u32,
    key: XSalsa20Poly1305EncryptedData
}
```
- **session_id**
    - determines changes in members which necessitates the change of the group encryption key

### Stages
1. Key creation
    - uses the TryFromRandom function to generate a series of bytes for the KeyRef
        - needs to be shifted to LAIR according to the docs
    - done during init()
    - done when a new key is needed when a member joins or leaves the group

2. Key distribution
    - group encryption keys are encrypted using `box` encryption
        - sender: group moderator/creator
        - recipient: individual members
    - encrypted key entries are committed to the DHT and linked to individual member's AgentPubKeys
    - done when a member is added to the group
        - a new encrypted group key entry (using the new member's pubkey) is committed to the DHT
    - done when a member is removed from the group
        - a new key is generated
        - new encrypted group key entries to correspond to all members 
    - will be moved to an offchain ephemeral storage to minimize the encryption processing of keys per member
3. Encryption and Decryption
    - messages are encrypted/decrypted by the `secretbox` function
    - messages are matched to corresponding keys based on a session id

### Functions
#### init()
- run when cloning and initiating the group DNA
- creates an x25519 keypair (public and private) for the agent
- commits an `IdentityKey` entry in the DHT (public entry)
- links the `IdentityKey` entry to the agent's pubkey


```mermaid
sequenceDiagram

participant ACC as Alice_Conversation_Cell
participant DHT as DHT

ACC-->>ACC: call `init`
ACC-->>ACC: call create_x25519_keypair
ACC-->>DHT: create_entry IdentityKey containing the Public Encrypting Key
ACC-->>DHT: create_link from agent's AgentPubKey to IdentityKey
```

#### create_key() -> ExternResult\<()>
```rust=
pub struct create_key_input {
    session_id: u32,
    agent: Vec<AgentPubKey>
}
```
- creates a group encryption key using TryFromRandom
- creates a GroupKey structure
    - use 0 as the session_id for the initial group
    - add the generated group encryption key
- encrypts the GroupKey structure using own x25519 key

```mermaid
sequenceDiagram

participant ACC as Alice_Conversation_Cell
participant DHT as DHT

ACC-->>ACC: use TryFromRandom to generate encryption key
ACC-->>ACC: get_links for GroupKey with group as base and "latest_group_key" as tag
alt no link found
    ACC-->>ACC: use 0 as session_id
else link found
    ACC-->>ACC: get entry
    ACC-->>ACC: add 1 to latest session id
end
ACC-->>ACC: create a GroupKey structure
ACC-->>DHT: get member list
DHT-->>ACC: return member list
loop for member in list
ACC-->>ACC: encrypt entry using member's x25519 key
ACC-->>DHT: create EncryptedGroupKey entry in DHT
ACC-->>DHT: create link from each Agent PubKey to EncryptedGroupKey using their respective Agent PubKey as tags
end


ACC-->>ACC: encrypt entry using own x25519 key
ACC-->>DHT: create EntryptedGroupKey entry in DHT
ACC-->>DHT: delete link from previous latest key
ACC-->>DHT: create link with Group entry as base, previous EncryptedGroupKey as target, and session_id as tag
ACC-->>DHT: create link with Group entry as base, new EncryptedGroupKey as target, and "latest_group_key" as tag
```

#### add_member(agent: AgentPubKey) -> ExternResult\<()>
```mermaid
sequenceDiagram

participant ACC as Alice_Conversation_Cell
participant DHT as DHT
participant BCC as Bobby_Conversation_Cell

Note over ACC: through what mechanism?
ACC-->>BCC: ask new member to clone Group DNA
BCC-->>BCC: clone Group DNA
BCC-->>BCC: calls `init` to create x25519 key
Note over BCC: do we have return values? how can we signal creation success (either remote signal or call_remote)
BCC-->>ACC: return Ok
ACC-->>ACC: call `create_key`
```

#### remove_member(agent: AgentPubKey) -> ExternResult\<()>
```mermaid
sequenceDiagram

participant ACC as Alice_Conversation_Cell
participant DHT as DHT
participant BCC as Bobby_Conversation_Cell

ACC-->>ACC: call `remove_member` (updates member list)
ACC-->>ACC: call `create_key`
```

#### get_agent_key(agent: AgentPubKey) -> ExternResult\<IdentityKey>
```rust
pub struct IdentityKey {
    agent: AgentPubKey,
    key: X25519PubKey,
}
```
```mermaid
sequenceDiagram

participant fn as caller_fn
participant ACC as Alice_Conversation_Cell
participant DHT as DHT

fn-->>ACC: call `get_agent_key` with an agent's PubKey as input
ACC-->>DHT: get_links on AgentPubKey with tag "identity_key"
DHT-->>ACC: return links
ACC-->>DHT: get_details on link target
DHT-->>ACC: return details
ACC-->>ACC: convert details to IdentityKey entry
ACC-->>fn: return IdentityKey
```
    
#### encrypt_key(input: EncryptInput) -> ExternResult\<XSalsa20Poly1305EncryptedData>
```rust=
pub struct EncryptInput {
    recipient: AgentPubKey,
    data: XSalsa20Poly1305Data,
}
```
```mermaid
sequenceDiagram

participant fn as caller
participant ACC as Alice_Conversation_Cell
participant DHT as DHT

fn-->>ACC: call `encrypt_key`
ACC-->>DHT: call `get_agent_key` with the recipient AgentPubKey as input
DHT-->>ACC: return IdentityKey
note over ACC: can we do a query here instead?
ACC-->>DHT: call `get_agent_key` with the own AgentPubKey as input
DHT-->>ACC: return IdentityKey
ACC-->>ACC: call `x_25519_x_salsa20_poly1305_encrypt` with the returned X25519PubKeys
ACC-->>fn: return encrypted data
```


#### decrypt_key(input: DecryptInput) -> ExternResult\<XSalsa20Poly1305Data>
```rust=
pub struct EncryptInput {
    sender: AgentPubKey,
    data: XSalsa20Poly1305Data,
}
```
```mermaid
sequenceDiagram

participant fn as caller
participant ACC as Alice_Conversation_Cell
participant DHT as DHT

fn-->>ACC: call `decrypt`
ACC-->>DHT: call `get_agent_key` with the sender AgentPubKey as input
DHT-->>ACC: return IdentityKey
note over ACC: can we do a query here instead?
ACC-->>DHT: call `get_agent_key` with the own AgentPubKey as input
DHT-->>ACC: return IdentityKey
ACC-->>ACC: call `x_25519_x_salsa20_poly1305_decrypt` with the returned X25519PubKeys
ACC-->>fn: return decrypted data
```

#### send_message
```rust=
pub struct EncryptedMessageEntry {
    session_id: u32,
    data: XSalsa20Poly1305EncryptedData
}
```
```mermaid
sequenceDiagram

participant AUI as Alice_UI
participant ACC as Alice_Conversation_Cell
participant DHT as DHT

AUI-->>ACC: call `send_message`
ACC-->>ACC: construct Message Entry
ACC-->>ACC: get latest session_id
ACC-->>ACC: get latest encryption key
ACC-->>ACC: decrypt key using own x25519 key
ACC-->>ACC: call x_salsa20_poly1305_encrypt()
ACC-->>ACC: construct EncryptedMessage Entry adding the session_id
ACC-->>DHT: commit EncryptedMessage Entry to chain
ACC-->>AUI: return Message Entry
```

### get_messages (general)
```rust=
pub struct MessageEntry {
    author: AgentPubKey,
    receiver: Vec<AgentPubKey>,
    payload: Payload,
    time_sent: Timestamp,
    reply_to: Option<EntryHash>,
}

pub struct EncryptedMessageEntry {
    session_id: u32,
    data: XSalsa20Poly1305EncryptedData
}
```
```mermaid
sequenceDiagram

participant AUI as Alice_UI
participant ACC as Alice_Conversation_Cell
participant DHT as DHT

AUI-->>ACC: call `get_fn`
ACC-->>DHT: gets encrypted messages
DHT-->>ACC: return encrypted messages
ACC-->>DHT: get all encryption keys linked to own PubKey
loop for encryption_keys in get results
    ACC-->>ACC: decrypt key
    ACC-->>ACC: add key to a hashmap with session_id as keys
end
loop for encrypted_message in get results
    ACC-->>ACC: check for filtering conditions (author, receiver, hash)
    alt message should be returned
        ACC-->>ACC: get session_id from encrypted message entry
        ACC-->>ACC: get corresponding encryption key from hashmap
        ACC-->>ACC: call `decrypt()` on encrypted_message using key
    else message should not be returned
        ACC-->>ACC: continue with loop
    end
end



```

### Security Analysis and Comparison to the Signal Protocol
```mermaid
sequenceDiagram

participant UI as UI
participant WASM as WASM
participant Lair as Lair
participant Chain as Chain
participant WASM2 as WASM2
participant Chain2 as Chain2

UI-->>WASM: plaintext
WASM-->>Lair: plaintext
Lair-->>Lair: encrypt
Lair-->>WASM: encrypted
WASM-->>Chain: encrypted
WASM-->>WASM2: encrypted + encryption via `call_remote`
WASM2-->>Chain2: encryped
```
|           	|                                   	| Signal             	| Holochain          	| Comment                                        	|
|-----------	|-----------------------------------	|--------------------	|--------------------	|------------------------------------------------	|
|           	| Confidentiality                   	| :heavy_check_mark: 	| :heavy_check_mark: 	|                                                	|
|           	| Integrity                         	| :heavy_check_mark: 	| :x:                	| Need MACs or signatures.                       	|
|           	| Authentication                    	| :heavy_check_mark: 	| partial            	|                                                	|
|           	| Participant Consistency           	| :heavy_check_mark: 	| partial            	| Need MACs or signatures.                       	|
|           	| Destination Validation            	| :heavy_check_mark: 	| partial            	| Need MACs or signatures.                       	|
|           	| Forward Secrecy                   	| :heavy_check_mark: 	| :x:                	| Single encrypting key for all messages         	|
|           	| Backward Secrecy/Self-Healing/PCS 	| :heavy_check_mark: 	| :x:                	| Single encrypting key for all messages         	|
|           	| Anonymity Preserving              	|                    	| :x:                	| Encryption PubKeys are linked to AgentPubKeys  	|
|           	| Speaker Consistency               	| :heavy_check_mark: 	|                    	|                                                	|
|           	| Causality Preserving              	| :heavy_check_mark: 	|                    	|                                                	|
|           	| Global Transcript                 	|                    	|                    	|                                                	|
|           	| Message Unlinkability             	| :heavy_check_mark: 	| :x:                	| Author and recipient agent keys are plaintext. 	|
|           	| Message Repudiation               	| :heavy_check_mark: 	| :x:                	| Author and recipient agent keys are plaintext. 	|
|           	| Participant Repudiation           	| :heavy_check_mark: 	| :x:                	| Author and recipient agent keys are plaintext. 	|
| Usability 	| Out-of-Order Resilient            	| :heavy_check_mark: 	| :heavy_check_mark: 	| Single encrypting key for all messages         	|
| Usability 	| Dropped Message Resilient         	| :heavy_check_mark: 	| :heavy_check_mark: 	| Single encrypting key for all messages         	|
| Usability 	| Asynchronicity                    	| :heavy_check_mark: 	| partial            	|                                                	|
| Usability 	| Multi-Device Support              	| partial            	| partial            	|                                                	|
| Usability 	| No Additional Service             	|                    	| TBD                	| No need for a key server aside from DHT.       	|
| Group     	| Computational Equality            	| :heavy_check_mark: 	| NA                 	|                                                	|
| Group     	| Trust Equality                    	| :heavy_check_mark: 	| NA                 	|                                                	|
| Group     	| Subgroup Messaging                	| :heavy_check_mark: 	| NA                 	|                                                	|
| Group     	| Contractable                      	| :heavy_check_mark: 	| NA                 	|                                                	|
| Group     	| Expandable                        	| :heavy_check_mark: 	| NA                 	|                                                	|

### Things to keep in mind
- security is multi-layered
    - validation rules
    - capability grants
    - membrane proof
    - encryption via call_remote
### Issues
- single point of failure (encrypting keys)
