Files
rfc-index/vac/raw/decentralized-messaging-ethereum.html
2025-12-22 13:04:47 +00:00

959 lines
69 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE HTML>
<html lang="en" class="ayu" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Decentralized Messaging Ethereum - Vac RFC</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../../highlight.css">
<link rel="stylesheet" href="../../tomorrow-night.css">
<link rel="stylesheet" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../custom.css">
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "ayu";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('ayu')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../../index.html">Introduction</a></li><li class="chapter-item expanded "><a href="../../vac/index.html"><strong aria-hidden="true">1.</strong> Vac</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../vac/1/coss.html"><strong aria-hidden="true">1.1.</strong> 1/COSS</a></li><li class="chapter-item expanded "><a href="../../vac/2/mvds.html"><strong aria-hidden="true">1.2.</strong> 2/MVDS</a></li><li class="chapter-item expanded "><a href="../../vac/3/remote-log.html"><strong aria-hidden="true">1.3.</strong> 3/Remote Log</a></li><li class="chapter-item expanded "><a href="../../vac/4/mvds-meta.html"><strong aria-hidden="true">1.4.</strong> 4/MVDS Meta</a></li><li class="chapter-item expanded "><a href="../../vac/25/libp2p-dns-discovery.html"><strong aria-hidden="true">1.5.</strong> 25/Libp2p DNS Discovery</a></li><li class="chapter-item expanded "><a href="../../vac/32/rln-v1.html"><strong aria-hidden="true">1.6.</strong> 32/RLN-V1</a></li><li class="chapter-item expanded "><a href="../../vac/raw/index.html"><strong aria-hidden="true">1.7.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../vac/raw/consensus-hashgraphlike.html"><strong aria-hidden="true">1.7.1.</strong> Consensus Hashgraphlike</a></li><li class="chapter-item expanded "><a href="../../vac/raw/decentralized-messaging-ethereum.html" class="active"><strong aria-hidden="true">1.7.2.</strong> Decentralized Messaging Ethereum</a></li><li class="chapter-item expanded "><a href="../../vac/raw/eth-mls-offchain.html"><strong aria-hidden="true">1.7.3.</strong> ETH MLS Offchain</a></li><li class="chapter-item expanded "><a href="../../vac/raw/eth-mls-onchain.html"><strong aria-hidden="true">1.7.4.</strong> ETH MLS Onchain</a></li><li class="chapter-item expanded "><a href="../../vac/raw/deleted/eth-secpm.html"><strong aria-hidden="true">1.7.5.</strong> ETH SecPM</a></li><li class="chapter-item expanded "><a href="../../vac/raw/gossipsub-tor-push.html"><strong aria-hidden="true">1.7.6.</strong> Gossipsub Tor Push</a></li><li class="chapter-item expanded "><a href="../../vac/raw/logos-capability-discovery.html"><strong aria-hidden="true">1.7.7.</strong> Logos Capability Discovery</a></li><li class="chapter-item expanded "><a href="../../vac/raw/mix.html"><strong aria-hidden="true">1.7.8.</strong> Mix</a></li><li class="chapter-item expanded "><a href="../../vac/raw/noise-x3dh-double-ratchet.html"><strong aria-hidden="true">1.7.9.</strong> Noise X3DH Double Ratchet</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-interep-spec.html"><strong aria-hidden="true">1.7.10.</strong> RLN Interep Spec</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-stealth-commitments.html"><strong aria-hidden="true">1.7.11.</strong> RLN Stealth Commitments</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-v2.html"><strong aria-hidden="true">1.7.12.</strong> RLN-V2</a></li><li class="chapter-item expanded "><a href="../../vac/raw/sds.html"><strong aria-hidden="true">1.7.13.</strong> SDS</a></li></ol></li><li class="chapter-item expanded "><a href="../../vac/template.html"><strong aria-hidden="true">1.8.</strong> Template</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/index.html"><strong aria-hidden="true">2.</strong> Waku</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/core/index.html"><strong aria-hidden="true">2.1.</strong> Standards - Core</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/core/10/waku2.html"><strong aria-hidden="true">2.1.1.</strong> 10/Waku2</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/11/relay.html"><strong aria-hidden="true">2.1.2.</strong> 11/Relay</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/12/filter.html"><strong aria-hidden="true">2.1.3.</strong> 12/Filter</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/13/store.html"><strong aria-hidden="true">2.1.4.</strong> 13/Store</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/14/message.html"><strong aria-hidden="true">2.1.5.</strong> 14/Message</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/15/bridge.html"><strong aria-hidden="true">2.1.6.</strong> 15/Bridge</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/17/rln-relay.html"><strong aria-hidden="true">2.1.7.</strong> 17/RLN Relay</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/19/lightpush.html"><strong aria-hidden="true">2.1.8.</strong> 19/Lightpush</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/31/enr.html"><strong aria-hidden="true">2.1.9.</strong> 31/ENR</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/33/discv5.html"><strong aria-hidden="true">2.1.10.</strong> 33/Discv5</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/34/peer-exchange.html"><strong aria-hidden="true">2.1.11.</strong> 34/Peer Exchange</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/36/bindings-api.html"><strong aria-hidden="true">2.1.12.</strong> 36/Bindings API</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/64/network.html"><strong aria-hidden="true">2.1.13.</strong> 64/Network</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/66/metadata.html"><strong aria-hidden="true">2.1.14.</strong> 66/Metadata</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/standards/application/index.html"><strong aria-hidden="true">2.2.</strong> Standards - Application</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/application/20/toy-eth-pm.html"><strong aria-hidden="true">2.2.1.</strong> 20/Toy ETH PM</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/26/payload.html"><strong aria-hidden="true">2.2.2.</strong> 26/Payload</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/53/x3dh.html"><strong aria-hidden="true">2.2.3.</strong> 53/X3DH</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/54/x3dh-sessions.html"><strong aria-hidden="true">2.2.4.</strong> 54/X3DH Sessions</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/index.html"><strong aria-hidden="true">2.3.</strong> Standards - Legacy</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/legacy/6/waku1.html"><strong aria-hidden="true">2.3.1.</strong> 6/Waku1</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/7/data.html"><strong aria-hidden="true">2.3.2.</strong> 7/Data</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/8/mail.html"><strong aria-hidden="true">2.3.3.</strong> 8/Mail</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/9/rpc.html"><strong aria-hidden="true">2.3.4.</strong> 9/RPC</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/informational/index.html"><strong aria-hidden="true">2.4.</strong> Informational</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/informational/22/toy-chat.html"><strong aria-hidden="true">2.4.1.</strong> 22/Toy Chat</a></li><li class="chapter-item expanded "><a href="../../waku/informational/23/topics.html"><strong aria-hidden="true">2.4.2.</strong> 23/Topics</a></li><li class="chapter-item expanded "><a href="../../waku/informational/27/peers.html"><strong aria-hidden="true">2.4.3.</strong> 27/Peers</a></li><li class="chapter-item expanded "><a href="../../waku/informational/29/config.html"><strong aria-hidden="true">2.4.4.</strong> 29/Config</a></li><li class="chapter-item expanded "><a href="../../waku/informational/30/adaptive-nodes.html"><strong aria-hidden="true">2.4.5.</strong> 30/Adaptive Nodes</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/deprecated/index.html"><strong aria-hidden="true">2.5.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/deprecated/5/waku0.html"><strong aria-hidden="true">2.5.1.</strong> 5/Waku0</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/16/rpc.html"><strong aria-hidden="true">2.5.2.</strong> 16/RPC</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/18/swap.html"><strong aria-hidden="true">2.5.3.</strong> 18/Swap</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/fault-tolerant-store.html"><strong aria-hidden="true">2.5.4.</strong> Fault Tolerant Store</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../nomos/index.html"><strong aria-hidden="true">3.</strong> Nomos</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/raw/index.html"><strong aria-hidden="true">3.1.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/raw/nomosda-encoding.html"><strong aria-hidden="true">3.1.1.</strong> NomosDA Encoding</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/nomosda-network.html"><strong aria-hidden="true">3.1.2.</strong> NomosDA Network</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-hardware-requirements.html"><strong aria-hidden="true">3.1.3.</strong> P2P Hardware Requirements</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-nat-solution.html"><strong aria-hidden="true">3.1.4.</strong> P2P NAT Solution</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-network-bootstrapping.html"><strong aria-hidden="true">3.1.5.</strong> P2P Network Bootstrapping</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-network.html"><strong aria-hidden="true">3.1.6.</strong> P2P Network</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/sdp.html"><strong aria-hidden="true">3.1.7.</strong> SDP</a></li></ol></li><li class="chapter-item expanded "><a href="../../nomos/deprecated/index.html"><strong aria-hidden="true">3.2.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/deprecated/claro.html"><strong aria-hidden="true">3.2.1.</strong> Claro</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../codex/index.html"><strong aria-hidden="true">4.</strong> Codex</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../codex/raw/index.html"><strong aria-hidden="true">4.1.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../codex/raw/codex-block-exchange.html"><strong aria-hidden="true">4.1.1.</strong> Block Exchange</a></li><li class="chapter-item expanded "><a href="../../codex/raw/codex-marketplace.html"><strong aria-hidden="true">4.1.2.</strong> Marketplace</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../status/index.html"><strong aria-hidden="true">5.</strong> Status</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/24/curation.html"><strong aria-hidden="true">5.1.</strong> 24/Curation</a></li><li class="chapter-item expanded "><a href="../../status/28/featuring.html"><strong aria-hidden="true">5.2.</strong> 28/Featuring</a></li><li class="chapter-item expanded "><a href="../../status/55/1to1-chat.html"><strong aria-hidden="true">5.3.</strong> 55/1-to-1 Chat</a></li><li class="chapter-item expanded "><a href="../../status/56/communities.html"><strong aria-hidden="true">5.4.</strong> 56/Communities</a></li><li class="chapter-item expanded "><a href="../../status/61/community-history-service.html"><strong aria-hidden="true">5.5.</strong> 61/Community History Service</a></li><li class="chapter-item expanded "><a href="../../status/62/payloads.html"><strong aria-hidden="true">5.6.</strong> 62/Payloads</a></li><li class="chapter-item expanded "><a href="../../status/63/keycard-usage.html"><strong aria-hidden="true">5.7.</strong> 63/Keycard Usage</a></li><li class="chapter-item expanded "><a href="../../status/65/account-address.html"><strong aria-hidden="true">5.8.</strong> 65/Account Address</a></li><li class="chapter-item expanded "><a href="../../status/71/push-notification-server.html"><strong aria-hidden="true">5.9.</strong> 71/Push Notification Server</a></li><li class="chapter-item expanded "><a href="../../status/raw/index.html"><strong aria-hidden="true">5.10.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/raw/simple-scaling.html"><strong aria-hidden="true">5.10.1.</strong> Simple Scaling</a></li><li class="chapter-item expanded "><a href="../../status/raw/status-app-protocols.html"><strong aria-hidden="true">5.10.2.</strong> Status App Protocols</a></li><li class="chapter-item expanded "><a href="../../status/raw/status-mvds.html"><strong aria-hidden="true">5.10.3.</strong> Status MVDS</a></li><li class="chapter-item expanded "><a href="../../status/raw/url-data.html"><strong aria-hidden="true">5.10.4.</strong> URL Data</a></li><li class="chapter-item expanded "><a href="../../status/raw/url-scheme.html"><strong aria-hidden="true">5.10.5.</strong> URL Scheme</a></li></ol></li><li class="chapter-item expanded "><a href="../../status/deprecated/index.html"><strong aria-hidden="true">5.11.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/deprecated/3rd-party.html"><strong aria-hidden="true">5.11.1.</strong> 3rd Party</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/account.html"><strong aria-hidden="true">5.11.2.</strong> Account</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/client.html"><strong aria-hidden="true">5.11.3.</strong> Client</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/dapp-browser-API-usage.html"><strong aria-hidden="true">5.11.4.</strong> Dapp Browser API Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/eips.html"><strong aria-hidden="true">5.11.5.</strong> EIPs</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/ethereum-usage.html"><strong aria-hidden="true">5.11.6.</strong> Ethereum Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/group-chat.html"><strong aria-hidden="true">5.11.7.</strong> Group Chat</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/IPFS-gateway-for-sticker-Pack.html"><strong aria-hidden="true">5.11.8.</strong> IPFS Gateway for Sticker Pack</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/keycard-usage-for-wallet-and-chat-keys.html"><strong aria-hidden="true">5.11.9.</strong> Keycard Usage for Wallet and Chat Keys</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/notifications.html"><strong aria-hidden="true">5.11.10.</strong> Notifications</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/payloads.html"><strong aria-hidden="true">5.11.11.</strong> Payloads</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/push-notification-server.html"><strong aria-hidden="true">5.11.12.</strong> Push Notification Server</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/secure-transport.html"><strong aria-hidden="true">5.11.13.</strong> Secure Transport</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/waku-mailserver.html"><strong aria-hidden="true">5.11.14.</strong> Waku Mailserver</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/waku-usage.html"><strong aria-hidden="true">5.11.15.</strong> Waku Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/whisper-mailserver.html"><strong aria-hidden="true">5.11.16.</strong> Whisper Mailserver</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/whisper-usage.html"><strong aria-hidden="true">5.11.17.</strong> Whisper Usage</a></li></ol></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Vac RFC</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/vacp2p/rfc-index" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="eth-dcgka"><a class="header" href="#eth-dcgka">ETH-DCGKA</a></h1>
<div class="rfc-meta">
<table>
<tr><th>Name</th><td>Decentralized Key and Session Setup for Secure Messaging over Ethereum</td></tr>
<tr><th>Status</th><td>raw</td></tr>
<tr><th>Category</th><td>informational</td></tr>
<tr><th>Editor</th><td>Ramses Fernandez-Valencia &lt;ramses@status.im&gt;</td></tr>
</table>
</div>
<!-- timeline:start -->
<h2 id="timeline"><a class="header" href="#timeline">Timeline</a></h2>
<ul>
<li><strong>2025-12-22</strong><a href="https://github.com/vacp2p/rfc-index/blob/b1a578393edf8487ccc97a5f25b25af9bf41efb3/docs/vac/raw/decentralized-messaging-ethereum.md"><code>b1a5783</code></a> — Chore/mdbook updates (#237)</li>
<li><strong>2025-12-18</strong><a href="https://github.com/vacp2p/rfc-index/blob/d03e699084774ebecef9c6d4662498907c5e2080/docs/vac/raw/decentralized-messaging-ethereum.md"><code>d03e699</code></a> — ci: add mdBook configuration (#233)</li>
<li><strong>2025-04-04</strong><a href="https://github.com/vacp2p/rfc-index/blob/517b63984c875670e437d50359f2f67331104974/vac/raw/decentralized-messaging-ethereum.md"><code>517b639</code></a> — Update the RFCs: Vac Raw RFC (#143)</li>
<li><strong>2024-10-03</strong><a href="https://github.com/vacp2p/rfc-index/blob/c655980494a5943634c372009bbea71c13196a8f/vac/raw/decentralized-messaging-ethereum.md"><code>c655980</code></a> — Eth secpm splitted (#91)</li>
<li><strong>2024-09-13</strong><a href="https://github.com/vacp2p/rfc-index/blob/3ab314d87d4525ff1296bf3d9ec634d570777b91/vac/raw/decentralized-messaging-ethereum.md"><code>3ab314d</code></a> — Fix Files for Linting (#94)</li>
<li><strong>2024-05-27</strong><a href="https://github.com/vacp2p/rfc-index/blob/7e3a625812bd954696b7facc29a205053d1acc3c/vac/raw/decentralized-messaging-ethereum.md"><code>7e3a625</code></a> — ETH-SECPM-DEC (#28)</li>
</ul>
<!-- timeline:end -->
<h2 id="abstract"><a class="header" href="#abstract">Abstract</a></h2>
<p>This document introduces a decentralized group messaging protocol
using Ethereum adresses as identifiers.
It is based in the proposal
<a href="https://eprint.iacr.org/2020/1281">DCGKA</a> by Weidner et al.
It includes also approximations to overcome limitations related to using PKI and
the multi-device setting.</p>
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
<p>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.</p>
<p>Secure messaging protocols used should have the following key features:</p>
<ol>
<li>
<p><strong>Asynchronous Messaging:</strong> Users can send messages even if the recipients
are not online at the moment.</p>
</li>
<li>
<p><strong>Resilience to Compromise:</strong> 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.</p>
</li>
<li>
<p><strong>Dynamic Group Management:</strong> Users can easily add or remove group members
at any time, reflecting the flexible nature of communication within the app.</p>
</li>
</ol>
<p>In this field, there exists a <em>trilemma</em>, similar to what one observes in
blockchain, involving three key aspects:</p>
<ol>
<li>security,</li>
<li>scalability, and</li>
<li>decentralization.</li>
</ol>
<p>For instance, protocols like the <a href="https://messaginglayersecurity.rocks">MLS</a>
perform well in terms of scalability and security.
However, they falls short in decentralization.</p>
<p>Newer studies such as <a href="https://eprint.iacr.org/2022/251">CoCoa</a>
improve features related to security and scalability,
but they still rely on servers, which may not be fully trusted though they are necessary.</p>
<p>On the other hand,
older studies like <a href="https://mattweidner.com/assets/pdf/acs-dissertation.pdf">Causal TreeKEM</a>
exhibit decent scalability (logarithmic)
but lack forward secrecy and have weak post-compromise security (PCS).</p>
<p>The creators of <a href="https://eprint.iacr.org/2020/1281">DCGKA</a> introduce a decentralized,
asynchronous secure group messaging protocol that supports dynamic groups.
This protocol operates effectively on various underlying networks
without strict requirements on message ordering or latency.
It can be implemented in peer-to-peer or anonymity networks,
accommodating network partitions, high latency links, and
disconnected operation seamlessly.
Notably, the protocol doesn't rely on servers or
a consensus protocol for its functionality.</p>
<p>This proposal provides end-to-end encryption with forward secrecy and
post-compromise security,
even when multiple users concurrently modify the group state.</p>
<h2 id="theory"><a class="header" href="#theory">Theory</a></h2>
<h3 id="protocol-overview"><a class="header" href="#protocol-overview">Protocol overview</a></h3>
<p>This protocol makes use of ratchets to provide FS
by encrypting each message with a different key.</p>
<p>In the figure one can see the ratchet for encrypting a sequence of messages.
The sender requires an initial update secret <code>I_1</code>, which is introduced in a PRG.
The PRG will produce two outputs, namely a symmetric key for AEAD encryption, and
a seed for the next ratchet state.
The associated data needed in the AEAD encryption includes the message index <code>i</code>.
The ciphertext <code>c_i</code> associated to message <code>m_i</code>
is then broadcasted to all group members.
The next step requires deleting <code>I_1</code>, <code>k_i</code> and any old ratchet state.</p>
<p>After a period of time the sender may replace the ratchet state with new update secrets
<code>I_2</code>, <code>I_3</code>, and so on.</p>
<p>To start a post-compromise security update,
a user creates a new random value known as a seed secret and
shares it with every other group member through a secure two-party channel.
Upon receiving the seed secret,
each group member uses it to calculate an update secret for both the sender's ratchet
and their own.
Additionally, the recipient sends an unencrypted acknowledgment to the group
confirming the update.
Every member who receives the acknowledgment updates
not only the ratchet for the original sender but
also the ratchet for the sender of the acknowledgment.
Consequently, after sharing the seed secret through <code>n - 1</code> two-party messages and
confirming it with <code>n - 1</code> broadcast acknowledgments,
every group member has derived an update secret and updated their ratchet accordingly.</p>
<p>When removing a group member,
the user who initiates the removal conducts a post-compromise security update
by sending the update secret to all group members except the one being removed.
To add a new group member,
each existing group member shares the necessary state with the new user,
enabling them to derive their future update secrets.</p>
<p>Since group members may receive messages in various orders,
it's important to ensure that each sender's ratchet is updated consistently
with the same sequence of update secrets at each group member.</p>
<p>The network protocol used in this scheme ensures that messages from the same sender
are processed in the order they were sent.</p>
<h3 id="components-of-the-protocol"><a class="header" href="#components-of-the-protocol">Components of the protocol</a></h3>
<p>This protocol relies in 3 components:
authenticated causal broadcast (ACB),
decentralized group membership (DGM) and
2-party secure messaging (2SM).</p>
<h4 id="authenticated-causal-broadcast"><a class="header" href="#authenticated-causal-broadcast">Authenticated causal broadcast</a></h4>
<p>A causal order is a partial order relation <code>&lt;</code> on messages.
Two messages <code>m_1</code> and <code>m_2</code> are causally ordered, or
<code>m_1</code> causally precedes <code>m_2</code>
(denoted by <code>m_1 &lt; m_2</code>), if one of the following contiditions hold:</p>
<ol>
<li><code>m_1</code> and <code>m_2</code> were sent by the same group member, and
<code>m_1</code> was sent before <code>m_2</code>.</li>
<li><code>m_2</code> was sent by a group member U, and <code>m_1</code> was received and
processed by <code>U</code> before sending <code>m_2</code>.</li>
<li>There exists <code>m_3</code> such that <code>m_1 &lt; m_3</code> and <code>m_3 &lt; m_2</code>.</li>
</ol>
<p>Causal broadcast requires that before processing <code>m</code>, a group member must
process all preceding messages <code>{m' | m' &lt; m}</code>.</p>
<p>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 senders identity key.
This prevents a passive adversary from impersonating users or affecting
causally ordered delivery.</p>
<h4 id="decentralized-group-membership"><a class="header" href="#decentralized-group-membership">Decentralized group membership</a></h4>
<p>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.</p>
<h4 id="2-party-secure-messaging-2sm"><a class="header" href="#2-party-secure-messaging-2sm">2-party secure messaging (2SM)</a></h4>
<p>This protocol makes use of bidirectional 2-party secure messaging schemes,
which consist of 3 algorithms: <code>2SM-Init</code>, <code>2SM-Send</code> and <code>2SM-Receive</code>.</p>
<h5 id="function-2sm-init"><a class="header" href="#function-2sm-init">Function 2SM-Init</a></h5>
<p>This function takes two IDs as inputs:
<code>ID1</code> representing the local user and <code>ID2</code> representing the other party.
It returns an initial protocol state <code>sigma</code>.
The 2SM protocol relies on a Public Key Infrastructure (PKI) or
a key server to map these IDs to their corresponding public keys.
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.</p>
<h5 id="function-2sm-send"><a class="header" href="#function-2sm-send">Function 2SM-Send</a></h5>
<p>This function takes a state <code>sigma</code> and a plaintext <code>m</code> as inputs, and returns
a new state <code>sigma</code> and a ciphertext <code>c</code>.</p>
<h5 id="function-2sm-receive"><a class="header" href="#function-2sm-receive">Function 2SM-Receive</a></h5>
<p>This function takes a state <code>sigma</code> and a ciphertext <code>c</code>, and
returns a new state <code>sigma</code> and a plaintext <code>m</code>.</p>
<p>This function takes a state <code>sigma</code> and a ciphertext <code>c</code>, and returns a new
state <code>sigma</code> and a plaintext <code>m</code>.</p>
<h4 id="function-2sm-syntax"><a class="header" href="#function-2sm-syntax">Function 2SM Syntax</a></h4>
<p>The variable <code>sigma</code> denotes the state consisting in the variables below:</p>
<pre><code class="language-text">sigma.mySks[0] = sk
sigma.nextIndex = 1
sigma.receivedSk = empty_string
sigma.otherPk = pk`&lt;br&gt;
sigma.otherPksender = “other”
sigma.otherPkIndex = 0
</code></pre>
<h4 id="2sm-init"><a class="header" href="#2sm-init">2SM-Init</a></h4>
<p>On input a key pair <code>(sk, pk)</code>, this functions otuputs a state <code>sigma</code>.</p>
<h4 id="2sm-send"><a class="header" href="#2sm-send">2SM-Send</a></h4>
<p>This function encrypts the message <code>m</code> using <code>sigma.otherPk</code>, which represents
the other partys 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. <code>sigma.otherPkSender</code> is set to <code>me</code> in the former
case and <code>other</code> in the latter case.</p>
<p>Metadata including <code>otherPkSender</code> and <code>otherPkIndex</code> are included in the
message to indicate which of the recipients public keys is being utilized.</p>
<p>Additionally, this function generates a new key pair for the local user,
storing the secret key in <code>sigma.mySks</code> 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
<code>sigma.otherPk</code>.</p>
<pre><code class="language-text">sigma.mySks[sigma.nextIndex], myNewPk) = PKE-Gen()
(otherNewSk, otherNewPk) = PKE-Gen()
plaintext = (m, otherNewSk, sigma`.nextIndex, myNewPk)
msg = (PKE-Enc(sigma.otherPk, plaintext), sigma.otherPkSender, sigma.otherPkIndex)
sigma.nextIndex++
(sigma.otherPk, sigma.otherPkSender, sigma.otherPkIndex) = (otherNewPk, "me", empty_string)
return (sigma`, msg)
</code></pre>
<h4 id="2sm-receive"><a class="header" href="#2sm-receive">2SM-Receive</a></h4>
<p>This function utilizes the metadata of the message <code>c</code> to determine which
secret key to utilize for decryption, assigning it to <code>sk</code>.
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 <code>sigma.mySks[≤ keyIndex] = empty_string</code>.
Subsequently, the new public and secret keys contained in the message are
stored.</p>
<pre><code class="language-text">(ciphertext, keySender, keyIndex) = c
if keySender = "other" then
sk = sigma.mySks[keyIndex]
sigma.mySks[≤ keyIndex] = empty_string
else sk = sigma.receivedSk
(m, sigma.receivedSk, sigma.otherPkIndex, sigma.otherPk) = PKE-Dec(sk, ciphertext)
sigma.otherPkSender = "other"
return (sigma, m)
</code></pre>
<h3 id="pke-syntax"><a class="header" href="#pke-syntax">PKE Syntax</a></h3>
<p>The required PKE that MUST be used is ElGamal with a 2048-bit modulus <code>p</code>.</p>
<h4 id="parameters"><a class="header" href="#parameters">Parameters</a></h4>
<p>The following parameters must be used:</p>
<pre><code class="language-text">p = 308920927247127345254346920820166145569
g = 2
</code></pre>
<h4 id="pke-kgen"><a class="header" href="#pke-kgen">PKE-KGen</a></h4>
<p>Each user <code>u</code> MUST do the following:</p>
<pre><code class="language-text">PKE-KGen():
a = randint(2, p-2)
pk = (p, g, g^a)
sk = a
return (pk, sk)
</code></pre>
<h4 id="pke-enc"><a class="header" href="#pke-enc">PKE-Enc</a></h4>
<p>A user <code>v</code> encrypting a message <code>m</code> for <code>u</code> MUST follow these steps:</p>
<pre><code class="language-text">PKE-Enc(pk):
k = randint(2, p-2)
eta = g^k % p
delta = m * (g^a)^k % p
return ((eta, delta))
</code></pre>
<h4 id="pke-dec"><a class="header" href="#pke-dec">PKE-Dec</a></h4>
<p>The user <code>u</code> recovers a message <code>m</code> from a ciphertext <code>c</code>
by performing the following operations:</p>
<pre><code class="language-text">PKE-Dec(sk):
mu = eta^(p-1-sk) % p
return ((mu * delta) % p)
</code></pre>
<h3 id="dcgka-syntax"><a class="header" href="#dcgka-syntax">DCGKA Syntax</a></h3>
<h4 id="auxiliary-functions"><a class="header" href="#auxiliary-functions">Auxiliary functions</a></h4>
<p>There exist 6 functions that are auxiliary for the rest of components of the
protocol, namely:</p>
<h4 id="init"><a class="header" href="#init">init</a></h4>
<p>This function takes an <code>ID</code> as input and returns its associated initial state,
denoted by <code>gamma</code>:</p>
<pre><code class="language-text">gamma.myId = ID
gamma.mySeq = 0
gamma.history = empty
gamma.nextSeed = empty_string
gamma.2sm[·] = empty_string
gamma.memberSecret[·, ·, ·] = empty_string
gamma.ratchet[·] = empty_string
return (gamma)
</code></pre>
<h4 id="encrypt-to"><a class="header" href="#encrypt-to">encrypt-to</a></h4>
<p>Upon reception of the recipients <code>ID</code> and a plaintext, it encrypts a direct
message for another group member.
Should it be the first message for a particular <code>ID</code>,
then the <code>2SM</code> protocol state is initialized and stored in
<code>gamma.2sm[recipient.ID]</code>.
One then uses <code>2SM_Send</code> to encrypt the message and store the updated protocol
in <code>gamma</code>.</p>
<pre><code class="language-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)
</code></pre>
<h4 id="decrypt-from"><a class="header" href="#decrypt-from">decrypt-from</a></h4>
<p>After receiving the senders <code>ID</code> and a ciphertext, it behaves as the reverse
function of <code>encrypt-to</code> and has a similar initialization:</p>
<pre><code class="language-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)
</code></pre>
<h4 id="update-ratchet"><a class="header" href="#update-ratchet">update-ratchet</a></h4>
<p>This function generates the next update secret <code>I_update</code> for the group member
<code>ID</code>.
The ratchet state is stored in <code>gamma.ratchet[ID]</code>.
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.</p>
<pre><code class="language-text">(updateSecret, gamma.ratchet[ID]) = HKDF(gamma.ratchet[ID], input)
return (gamma, updateSecret)
</code></pre>
<h4 id="member-view"><a class="header" href="#member-view">member-view</a></h4>
<p>This function calculates the set of group members
based on the most recent control message sent by the specified user <code>ID</code>.
It filters the group membership operations
to include only those observed by the specified <code>ID</code>, and
then invokes the DGM function to generate the group membership.</p>
<pre><code class="language-text">ops = {m in gamma.history st. m was sent or acknowledged by ID}
return DGM(ops)
</code></pre>
<h4 id="generate-seed"><a class="header" href="#generate-seed">generate-seed</a></h4>
<p>This functions generates a random bit string and
sends it encrypted to each member of the group using the <code>2SM</code> mechanism.
It returns the updated protocol state and
the set of direct messages (denoted as <code>dmsgs</code>) to send.</p>
<pre><code class="language-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)
</code></pre>
<h3 id="creation-of-a-group"><a class="header" href="#creation-of-a-group">Creation of a group</a></h3>
<p>A group is generated in a 3 steps procedure:</p>
<ol>
<li>A user calls the <code>create</code> function and broadcasts a control message of type
<em>create</em>.</li>
<li>Each receiver of the message processes the message and broadcasts an <em>ack</em>
control message.</li>
<li>Each member processes the <em>ack</em> message received.</li>
</ol>
<h4 id="create"><a class="header" href="#create">create</a></h4>
<p>This function generates a <em>create</em> control message and calls <code>generate-seed</code> to
define the set of direct messages that need to be sent.
Then it calls <code>process-create</code> to process the control message for this user.
The function <code>process-create</code> returns a tuple including an updated state gamma
and an update secret <code>I</code>.</p>
<pre><code class="language-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)
</code></pre>
<h4 id="process-seed"><a class="header" href="#process-seed">process-seed</a></h4>
<p>This function initially employs <code>member-view</code> 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:</p>
<ol>
<li>If the control message was dispatched by the local user, it uses the most
recent invocation of <code>generate-seed</code> stored the seed secret in
<code>gamma.nextSeed</code>.</li>
<li>If the <code>control</code> message was dispatched by another user, and the local user
is among its recipients, the function utilizes <code>decrypt-from</code> to decrypt the
direct message that includes the seed secret.</li>
<li>Otherwise, it returns an <code>ack</code> message without deriving an update secret.</li>
</ol>
<p>Afterwards, <code>process-seed</code> 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 <code>senderSecret</code>, while
those for the other group members are stored in <code>gamma.memberSecret</code>.
The sender's member secret is immediately utilized to update their KDF ratchet
and compute their update secret <code>I_sender</code> using <code>update-ratchet</code>.
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 <code>ack</code> control
message is constructed for broadcast, including the sender ID and sequence
number of the message being acknowledged.</p>
<p>The final step computes an update secret <code>I_me</code> for the local user invoking the
<code>process-ack</code> function.</p>
<pre><code class="language-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)
else
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)
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)}
(gamma, _, _, I_me, _) = process-ack(gamma, gamma.myId, gamma.mySeq,
(sender, seq), empty_string)
return (gamma, control, forward, I_sender, I_me)
</code></pre>
<h4 id="process-create"><a class="header" href="#process-create">process-create</a></h4>
<p>This function is called by the sender and each of the receivers of the <code>create</code>
control message.
First, it records the information from the create message in the
<code>gamma.history+ {op}</code>, which is used to track group membership changes. Then,
it proceeds to call <code>process-seed</code>.</p>
<pre><code class="language-text">op = (”create”, sender, seq, IDs)
gamma.history = gamma.history + {op}
return (process-seed(gamma, sender, seq, dmsg))
</code></pre>
<h4 id="process-ack"><a class="header" href="#process-ack">process-ack</a></h4>
<p>This function is called by those group members once they receive an ack
message.
In <code>process-ack</code>, <code>ackID</code> and <code>ackSeq</code> 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 <code>gamma.history</code>.</p>
<p>Following this, the function retrieves the relevant member secret from
<code>gamma.memberSecret</code>, which was previously obtained from the seed secret
contained in the acknowledged message.</p>
<p>Finally, it updates the ratchet for the sender of the <code>ack</code> and returns the
resulting update secret.</p>
<pre><code class="language-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) &amp; (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)
</code></pre>
<p>The HKDF function MUST follow RFC 5869 using the hash function SHA256.</p>
<h3 id="post-compromise-security-updates-and-group-member-removal"><a class="header" href="#post-compromise-security-updates-and-group-member-removal">Post-compromise security updates and group member removal</a></h3>
<p>The functions <code>update</code> and <code>remove</code> share similarities with <code>create</code>:
they both call the function <code>generate-seed</code> to encrypt a new seed secret for
each group member.
The distinction lies in the determination of the group members using <code>member view</code>.
In the case of <code>remove</code>, the user being removed is excluded from the recipients
of the seed secret.
Additionally, the control message they construct is designated with type
<code>update</code> or <code>remove</code> respectively.</p>
<p>Likewise, <code>process-update</code> and <code>process-remove</code> are akin to <code>process-create</code>.
The function <code>process-update</code> skips the update of <code>gamma.history</code>,
whereas <code>process-remove</code> includes a removal operation in the history.</p>
<h4 id="update"><a class="header" href="#update">update</a></h4>
<pre><code class="language-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)
return (gamma, control, dmsgs, I)
</code></pre>
<h4 id="remove"><a class="header" href="#remove">remove</a></h4>
<pre><code class="language-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)
return (gamma, control, dmsgs, I)
</code></pre>
<h4 id="process-update"><a class="header" href="#process-update">process-update</a></h4>
<p><code>return process-seed(gamma, sender, seq, dmsg)</code></p>
<h4 id="process-remove"><a class="header" href="#process-remove">process-remove</a></h4>
<pre><code class="language-text">op = ("remove", sender, seq, removed)
gamma.history = gamma.history + {op}
return process-seed(gamma, sender, seq, dmsg)
</code></pre>
<h3 id="group-member-addition"><a class="header" href="#group-member-addition">Group member addition</a></h3>
<h4 id="add"><a class="header" href="#add">add</a></h4>
<p>When adding a new group member, an existing member initiates the process by
invoking the <code>add</code> function and providing the ID of the user to be added.
This function prepares a control message marked as <code>add</code> for broadcast to the
group. Simultaneously, it creates a welcome message intended for the new member
as a direct message.
This <code>welcome</code> message includes the current state of the sender's KDF ratchet,
encrypted using <code>2SM</code>, along with the history of group membership operations
conducted so far.</p>
<pre><code class="language-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)
</code></pre>
<h4 id="process-add"><a class="header" href="#process-add">process-add</a></h4>
<p>This function is invoked by both the sender and each recipient of an <code>add</code>
message, which includes the new group member. If the local user is the newly
added member, the function proceeds to call <code>process-welcome</code> and then exits.
Otherwise, it extends <code>gamma.history</code> with the <code>add</code> operation.</p>
<p>Line 5 determines whether the local user was already a group member at the time
the <code>add</code> message was sent; this condition is typically true but may be false
if multiple users were added concurrently.</p>
<p>On lines 6 to 8, the ratchet for the sender of the <em>add</em> message is updated
twice. In both calls to <code>update-ratchet</code>, a constant string is used as the
ratchet input instead of a random seed secret.</p>
<p>The value returned by the first ratchet update is stored in
<code>gamma.memberSecret</code> as the added users initial member secret. The result of
the second ratchet update becomes <code>I_sender</code>, the update secret for the sender
of the <code>add</code> message. On line 10, if the local user is the sender, the update
secret is returned.</p>
<p>If the local user is not the sender, an acknowledgment for the <code>add</code> message is
required.
Therefore, on line 11, a control message of type <code>add-ack</code> is constructed for
broadcast.
Subsequently, in line 12 the current ratchet state is encrypted using <code>2SM</code> 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, <code>process-add-ack</code> is called to calculate the local
users update secret (<code>I_me</code>), which is then returned along with <code>I_sender</code>.</p>
<pre><code class="language-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)
</code></pre>
<h4 id="process-add-ack"><a class="header" href="#process-add-ack">process-add-ack</a></h4>
<p>This function is invoked by both the sender and each recipient of an <code>add-ack</code>
message, including the new group member. Upon lines 12, the acknowledgment is
added to <code>gamma.history</code>, mirroring the process in <code>process-ack</code>.
If the current user is the new group member, the <code>add-ack</code> message includes the
direct message constructed in <code>process-add</code>; this direct message contains the
encrypted ratchet state of the sender of the <code>add-ack</code>, then it is decrypted on
lines 35.</p>
<p>Upon line 6, a check is performed to check if the local user was already a
group member at the time the <code>add-ack</code> was sent. If affirmative, a new update
secret <code>I</code> for the sender of the <code>add-ack</code> is computed on line 7 by invoking
<code>update-ratchet</code> with the constant string <code>add</code>.</p>
<p>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 members update by obtaining any
update secret from before their inclusion.</p>
<pre><code class="language-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
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)
else return (gamma, empty_string, empty_string, empty_string, empty_string)
</code></pre>
<h4 id="process-welcome"><a class="header" href="#process-welcome">process-welcome</a></h4>
<p>This function serves as the second step called by a newly added group member.
In this context, <code>adderHistory</code> represents the adding users copy of
<code>gamma.history</code> sent in their welcome message, which is utilized to initialize
the added users history.
Here, <code>c</code> denotes the ciphertext of the adding users ratchet state, which is
decrypted on line 2 using <code>decrypt-from</code>.</p>
<p>Once <code>gamma.ratchet[sender]</code> is initialized, <code>update-ratchet</code> is invoked twice
on lines 3 to 5 with the constant strings <code>welcome</code> and <code>add</code> respectively.
These operations mirror the ratchet operations performed by every other group
member in <code>process-add</code>.
The outcome of the first <code>update-ratchet</code> call becomes the first member secret
for the added user,
while the second call returns <code>I_sender</code>, the update secret for the sender of
the add operation.</p>
<p>Subsequently, the new group member constructs an <em>ack</em> control message to
broadcast on line 6 and calls <code>process-ack</code> to compute their initial update
secret I_me. The function <code>process-ack</code> reads from <code>gamma.memberSecret</code> and
passes it to <code>update-ratchet</code>. The previous ratchet state for the new member is
the empty string <code>empty</code>, as established by <code>init</code>, thereby initializing the
new members ratchet.
Upon receiving the new members <code>ack</code>, every other group member initializes
their copy of the new members ratchet in a similar manner.</p>
<p>By the conclusion of <code>process-welcome</code>, 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 <code>process-add-ack</code>.</p>
<pre><code class="language-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)
return (gamma, control, empty_string , I_sender, I_me)
</code></pre>
<h2 id="privacy-considerations"><a class="header" href="#privacy-considerations">Privacy Considerations</a></h2>
<h3 id="dependency-on-pki"><a class="header" href="#dependency-on-pki">Dependency on PKI</a></h3>
<p>The <a href="https://eprint.iacr.org/2020/1281">DCGKA</a> 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.</p>
<p>One method to overcome this limitation is adapting the protocol SIWE (Sign in
with Ethereum) so a user <code>u_1</code> who wants to start a communication with a user
<code>u_2</code> can interact with latters wallet to request a public key using an
Ethereum address as <code>ID</code>.</p>
<h4 id="siwe"><a class="header" href="#siwe">SIWE</a></h4>
<p>The <a href="https://docs.login.xyz/general-information/siwe-overview">SIWE</a> (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:</p>
<ol>
<li>A server generates a unique Nonce for each user intending to sign in.</li>
<li>A user initiates a request to connect to a website using their wallet.</li>
<li>The user is presented with a distinctive message that includes the Nonce and
details about the website.</li>
<li>The user authenticates their identity by signing in with their wallet.</li>
<li>Upon successful authentication, the user's identity is confirmed or
approved.</li>
<li>The website grants access to data specific to the authenticated user.</li>
</ol>
<h4 id="our-approach"><a class="header" href="#our-approach">Our approach</a></h4>
<p>The idea in the <a href="https://eprint.iacr.org/2020/1281">DCGKA</a> setting closely
resembles the procedure outlined in SIWE. Here:</p>
<ol>
<li>The server corresponds to user D1,who initiates a request (instead of
generating a nonce) to obtain the public key of user D2.</li>
<li>Upon receiving the request, the wallet of D2 send the request to the user,</li>
<li>User D2 receives the request from the wallet, and decides whether accepts or
rejects.</li>
<li>The wallet and responds with a message containing the requested public key
in case of acceptance by D2.</li>
</ol>
<p>This message may be signed, allowing D1 to verify that the owner of the
received public key is indeed D2.</p>
<h3 id="multi-device-setting"><a class="header" href="#multi-device-setting">Multi-device setting</a></h3>
<p>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 <code>ID</code>, which is held by one of them, and from other
users point of view, they would look as a single user.</p>
<p>Using servers, like in the paper
<a href="https://eprint.iacr.org/2019/1363">Multi-Device for Signal</a>, 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.</p>
<p>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.</p>
<p>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.</p>
<p>The mechanism for the substitution of misbehaving leader devices follows:</p>
<ol>
<li>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.</li>
<li>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.</li>
<li>To get the ability to sign messages, this new leader should request the
keypair associated to the ID to the wallet.</li>
<li>Once the leader has been changed, it revocates access from DCGKA to the
former leader using the DCGKA protocol.</li>
<li>The new leader starts a key update in DCGKA.</li>
</ol>
<p>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 <code>ID</code>
should only be in control of the leader device.</p>
<p>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.</p>
<p>To detect missing messages or potential misbehavior, messages must include a
counter.</p>
<h3 id="using-upke"><a class="header" href="#using-upke">Using UPKE</a></h3>
<p>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.</p>
<p>The other approach to managing the group of devices is using each devices
keypair, but it would require each device updating these materia frequently,
something that may not happens.</p>
<p><a href="https://eprint.iacr.org/2022/068">UPKE</a> is a form of asymetric cryptography
where any user can update any other users key pair by running an update
algorithm with (high-entropy) private coins. Any sender can initiate a <em>key
update</em> by sending a special update ciphertext.
This ciphertext updates the receivers public key and also, once processed by
the receiver, will update their secret key.</p>
<p>To the best of my knowledge, there exists several efficient constructions both
<a href="https://eprint.iacr.org/2019/1189">UPKE from ElGamal</a> (based in the DH
assumption) and <a href="(https://eprint.iacr.org/2023/1400)">UPKE from Lattices</a>
(based in lattices).
None of them have been implemented in a secure messaging protocol, and this
opens the door to some novel research.</p>
<h2 id="copyright"><a class="header" href="#copyright">Copyright</a></h2>
<p>Copyright and related rights waived via
<a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>
<h2 id="references"><a class="header" href="#references">References</a></h2>
<ul>
<li><a href="https://eprint.iacr.org/2020/1281">DCGKA</a></li>
<li><a href="https://messaginglayersecurity.rocks">MLS</a></li>
<li><a href="https://eprint.iacr.org/2022/251">CoCoa</a></li>
<li><a href="https://mattweidner.com/assets/pdf/acs-dissertation.pdf">Causal TreeKEM</a></li>
<li><a href="https://docs.login.xyz/general-information/siwe-overview">SIWE</a></li>
<li><a href="https://eprint.iacr.org/2019/1363">Multi-device for Signal</a></li>
<li><a href="https://eprint.iacr.org/2022/068">UPKE</a></li>
<li><a href="https://eprint.iacr.org/2019/1189">UPKE from ElGamal</a></li>
<li><a href="https://eprint.iacr.org/2023/1400">UPKE from Lattices</a></li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../vac/raw/consensus-hashgraphlike.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../vac/raw/eth-mls-offchain.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../vac/raw/consensus-hashgraphlike.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../vac/raw/eth-mls-offchain.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../../elasticlunr.min.js"></script>
<script src="../../mark.min.js"></script>
<script src="../../searcher.js"></script>
<script src="../../clipboard.min.js"></script>
<script src="../../highlight.js"></script>
<script src="../../book.js"></script>
<!-- Custom JS scripts -->
<script src="../../scripts/rfc-index.js"></script>
</div>
</body>
</html>