From 03ad98a0d5eb3a02f5055cbcbc42e3648a20c8e7 Mon Sep 17 00:00:00 2001
From: Marco Esposito
Date: Wed, 8 Apr 2026 17:32:03 +0200
Subject: [PATCH 1/4] add drafts for erc proposal and discussion
---
.gitignore | 2 +-
erc/ERC-pre-draft.md | 569 +++++++++++++++++++++++++
erc/ethereum-magicians-thread-draft.md | 140 ++++++
3 files changed, 710 insertions(+), 1 deletion(-)
create mode 100644 erc/ERC-pre-draft.md
create mode 100644 erc/ethereum-magicians-thread-draft.md
diff --git a/.gitignore b/.gitignore
index 21f39a9..674fdd2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,7 +30,7 @@ ignition/deployments/chain-84532
*apps/notes/
.claudeignore
*.claude/
-*.md
+/*.md
*myplans
.vercel/
/tests/scan-engine.test.ts
diff --git a/erc/ERC-pre-draft.md b/erc/ERC-pre-draft.md
new file mode 100644
index 0000000..2622cc3
--- /dev/null
+++ b/erc/ERC-pre-draft.md
@@ -0,0 +1,569 @@
+---
+title: Event-Log Encrypted Messaging
+description: A minimal application-layer standard for post-quantum-resistant encrypted messaging over EVM event logs.
+author: Marco (@okrame)
+discussions-to:
+status: Draft
+type: Standards Track
+category: ERC
+created: 2026-04-08
+---
+
+> Note: this document is a pre-draft working paper kept in the Verbeth repository.
+
+## Abstract
+
+This proposal defines a minimal application-layer standard for post-quantum-resistant encrypted messaging over EVM event logs.
+
+It standardizes:
+
+- a transport contract interface with three functions and three events for handshake initiation, handshake response, and post-handshake message delivery;
+- canonical wire formats for long-term public keys, handshake payloads, handshake response payloads, and ratcheted message payloads;
+- derivation rules for recipient discovery hashes and post-handshake message topics; and
+- a wallet-bound identity proof format that binds messaging keys to an Ethereum account.
+
+The design aims to preserve message confidentiality while still supporting disclosure-time authorship and accountability: the chain proves that an account authorized publication of a ciphertext, and disclosed protocol artifacts can later bind that ciphertext to a wallet-authorized messaging identity.
+
+The proposal does not standardize local storage, notifications, indexers, private retrieval, wallet UX, gas sponsorship, session modules, or deployment addresses.
+
+## Motivation
+
+Ethereum applications lack a widely documented application-layer standard for interoperable encrypted messaging based purely on onchain transport. Existing applications typically rely on proprietary relays, application-specific servers, or unpublished wire formats, which makes interoperation between independent clients difficult.
+
+This proposal is motivated by five goals:
+
+1. Define a minimal transport primitive that any EVM application can implement without depending on an operator-controlled message server.
+2. Standardize enough of the wire format to allow independent implementations to parse, verify, and decrypt the same handshake and message flows.
+3. Bind messaging keys to Ethereum accounts using wallet signatures, so recipients can authenticate long-term messaging keys before trusting them.
+4. Preserve accountable privacy by combining encrypted payloads with public transport-level authorship and signed transcript artifacts that can be verified after voluntary disclosure.
+5. Preserve a narrow scope suitable for standardization by excluding storage, indexing, private retrieval, and account-abstraction-specific UX choices.
+
+This proposal is deliberately narrower than a full messaging stack. It does not attempt to standardize contact lists, inbox sync, push notifications, message history export, anti-spam systems, or application-specific presentation logic.
+
+Unlike deniable offchain messaging systems, this proposal treats public transport-level attribution as a first-class design constraint. That tradeoff enables applications where message contents should remain private during normal operation, but participants may later need portable proof of who authorized a given encrypted exchange. Example use cases include private deal negotiation, agent-to-agent commerce, delegated service procurement, dispute resolution, and compliance-sensitive messaging where confidentiality and accountable authorship are both required.
+
+This proposal also differs from registry-centric messaging approaches such as [ERC-7627](https://eips.ethereum.org/EIPS/eip-7627) by focusing on event-log transport and interoperable message exchange rather than requiring an onchain public-key directory as a mandatory prerequisite. A future extension MAY define optional registry mechanisms compatible with this transport.
+
+This proposal standardizes transport interoperability, not full metadata anonymity. In particular, it distinguishes two privacy goals that are often conflated:
+
+1. recipient privacy against public onchain observers; and
+2. query privacy against malicious RPC providers or indexers.
+
+The current design provides strong unlinkability between `HandshakeResponse` and later `MessageSent` events, but it does not fully hide attempted first contact when recipient discovery uses a deterministic `recipientHash`.
+
+### Design goals
+
+- Minimal onchain logic.
+- Offchain cryptographic verification.
+- Interoperable wire formats.
+- Support for EOAs and smart accounts as transport senders.
+- Compatibility with event-log retrieval via `eth_getLogs`.
+
+### Non-goals
+
+- Onchain message decryption or validation.
+- Onchain nonce enforcement or replay prevention.
+- Standardizing a specific indexer architecture.
+- Standardizing private mailbox retrieval.
+- Standardizing Safe modules, paymaster flows, or bundler flows.
+- Standardizing contract upgrade governance.
+- Standardizing deterministic deployment addresses.
+
+## Specification
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
+
+### 1. Transport contract
+
+A compliant transport contract MUST expose the following functions:
+
+```solidity
+function sendMessage(
+ bytes calldata ciphertext,
+ bytes32 topic,
+ uint256 timestamp,
+ uint256 nonce
+) external;
+
+function initiateHandshake(
+ bytes32 recipientHash,
+ bytes calldata pubKeys,
+ bytes calldata ephemeralPubKey,
+ bytes calldata plaintextPayload
+) external;
+
+function respondToHandshake(
+ bytes32 inResponseTo,
+ bytes32 responderEphemeralR,
+ bytes calldata ciphertext
+) external;
+```
+
+A compliant transport contract MUST emit the following events:
+
+```solidity
+event MessageSent(
+ address indexed sender,
+ bytes ciphertext,
+ uint256 timestamp,
+ bytes32 indexed topic,
+ uint256 nonce
+);
+
+event Handshake(
+ bytes32 indexed recipientHash,
+ address indexed sender,
+ bytes pubKeys,
+ bytes ephemeralPubKey,
+ bytes plaintextPayload
+);
+
+event HandshakeResponse(
+ bytes32 indexed inResponseTo,
+ address indexed responder,
+ bytes32 responderEphemeralR,
+ bytes ciphertext
+);
+```
+
+The transport contract:
+
+- MUST set `sender` or `responder` to `msg.sender`;
+- MUST NOT require recipient registration;
+- MUST NOT parse or validate encrypted payload contents onchain;
+- MUST NOT enforce nonce uniqueness; and
+- MAY include non-messaging administrative functions, but such functions are outside the scope of this proposal.
+
+`timestamp` and `nonce` are sender-supplied metadata. Receivers MUST treat them as application-level ordering and deduplication hints, not as globally trusted consensus facts.
+
+### 2. Recipient discovery hash
+
+Handshake discovery uses a recipient hash derived from the intended recipient address.
+
+The canonical derivation is:
+
+```text
+recipientHash = keccak256(utf8("contact:" + lowercase(recipientAddress)))
+```
+
+Implementations MUST lowercase the hex address before concatenation.
+
+The `recipientHash` is a discovery selector for efficiency, not a guarantee of recipient anonymity. Because it is deterministic, observers who can guess candidate recipient addresses can test those guesses offline.
+
+Implementations:
+
+- MUST treat `recipientHash` as a privacy tradeoff rather than a privacy proof;
+- SHOULD assume that server-side filtering on `recipientHash` reveals recipient interest to any RPC or indexer that sees the query; and
+- SHOULD prefer client-side scanning or equivalent private retrieval mechanisms when query privacy against a third-party RPC or indexer is a primary goal.
+
+### 3. Long-term public key format
+
+The `pubKeys` field in `Handshake` MUST encode the sender's long-term messaging public keys as a versioned 65-byte blob:
+
+```text
+Byte 0 Bytes 1..32 Bytes 33..64
+0x01 X25519 public key Ed25519 public key
+```
+
+- Version `0x01` is REQUIRED for this proposal.
+- The X25519 key MUST be 32 bytes.
+- The Ed25519 key MUST be 32 bytes.
+
+Implementations MAY accept legacy unversioned 64-byte formats for backwards compatibility, but compliant emitters MUST emit the 65-byte versioned format above.
+
+### 4. Handshake payload
+
+The `ephemeralPubKey` field in `Handshake` MUST contain:
+
+```text
+Bytes 0..31 Bytes 32..1215
+X25519 ephemeral key ML-KEM-768 public key
+```
+
+Total length: `1216` bytes.
+
+The `plaintextPayload` field in `Handshake` MUST be a UTF-8 encoded JSON object with the following shape:
+
+```json
+{
+ "plaintextPayload": "string",
+ "identityProof": {
+ "message": "string",
+ "signature": "0x..."
+ }
+}
+```
+
+The payload is intentionally plaintext. Implementations MUST assume its contents are publicly visible.
+
+### 5. Wallet-bound identity proof
+
+The `identityProof` object binds the sender's long-term messaging keys to an Ethereum account using a wallet signature.
+
+The canonical message format is a newline-delimited UTF-8 string:
+
+```text
+VerbEth Key Binding v1
+Address: 0xabc...
+PkEd25519: 0x123...
+PkX25519: 0x456...
+ExecutorAddress: 0xdef...
+ChainId: 8453
+RpId: example.app
+```
+
+Rules:
+
+- `Address` MUST be the signing Ethereum account.
+- `PkEd25519` MUST equal the Ed25519 public key published in `pubKeys`.
+- `PkX25519` MUST equal the X25519 public key published in `pubKeys`.
+- `ExecutorAddress` MUST identify the account expected to appear as the transport sender.
+- `ChainId` is OPTIONAL but RECOMMENDED.
+- `RpId` is OPTIONAL but RECOMMENDED.
+
+For direct EOA transport, `Address` and `ExecutorAddress` MAY be equal. For smart-account transport, `Address` MAY identify the signing controller while `ExecutorAddress` identifies the account that emits the transport events.
+
+How implementations derive long-term messaging keys is out of scope. This proposal standardizes the binding proof format, not the seed derivation algorithm.
+
+Implementations verifying identity proofs:
+
+- MUST verify that the signature authorizes the exact binding message;
+- MUST verify that the bound public keys equal the keys carried by the transport payload;
+- MUST verify that `ExecutorAddress` matches the transport sender expected by the receiver's context; and
+- SHOULD support smart-account verification methods in addition to EOA verification.
+
+### 6. Handshake response tag
+
+The `inResponseTo` field in `HandshakeResponse` MUST be derived from both:
+
+- an X25519 shared secret computed from a dedicated response tag keypair; and
+- an ML-KEM-768 shared secret derived from the initiator's ML-KEM public key.
+
+The canonical derivation is:
+
+```text
+ecdhShared = X25519(r, A)
+okm = HKDF-SHA256(
+ ikm=kemSecret,
+ salt=ecdhShared,
+ info="verbeth:hsr-hybrid:v1",
+ len=32
+ )
+tag = keccak256(okm)
+```
+
+Where:
+
+- `A` is the initiator's X25519 ephemeral public key from `Handshake`;
+- `r` is the responder's dedicated response-tag private key; and
+- `kemSecret` is the ML-KEM-768 shared secret produced by encapsulation to the initiator's ML-KEM public key.
+
+The responder MUST publish the corresponding tag public key `R` as `responderEphemeralR`.
+
+### 7. Two-key handshake response requirement
+
+To prevent linkability between the handshake response and the first post-handshake ratchet key, the responder MUST use two distinct X25519 keypairs:
+
+1. a response-tag keypair `(r, R)` used only for `inResponseTo` derivation; and
+2. a ratchet keypair `(rk_s, rk_p)` used only for encrypted response delivery and ratchet session bootstrapping.
+
+The public key `R` MUST be published onchain as `responderEphemeralR`.
+
+The public key `rk_p` MUST be carried only inside the encrypted handshake response payload.
+
+### 8. Handshake response payload
+
+The `ciphertext` field in `HandshakeResponse` MUST be a UTF-8 encoded JSON envelope with the following shape:
+
+```json
+{
+ "v": 1,
+ "epk": "",
+ "n": "",
+ "ct": "",
+ "sig": ""
+}
+```
+
+The canonical encryption method for version `1` is NaCl box (`X25519 + XSalsa20-Poly1305`).
+
+For version `1`:
+
+- `epk` MUST be the responder ratchet public key `rk_p`;
+- `n` MUST be a 24-byte nonce;
+- `ct` MUST be the NaCl box ciphertext encrypted to the initiator's X25519 ephemeral public key from the handshake; and
+- `sig`, if present, is OPTIONAL and reserved for detached signatures over the envelope fields.
+
+After decryption, the inner JSON object MUST have the following shape:
+
+```json
+{
+ "unifiedPubKeys": "",
+ "ephemeralPubKey": "",
+ "kemCiphertext": "",
+ "note": "string, optional",
+ "identityProof": {
+ "message": "string",
+ "signature": "0x..."
+ }
+}
+```
+
+Rules:
+
+- `unifiedPubKeys` MUST use the format defined in section 3;
+- `ephemeralPubKey` MUST be the responder ratchet public key `rk_p`;
+- `kemCiphertext` MUST be the ML-KEM-768 ciphertext corresponding to the shared secret used in section 6; and
+- `identityProof` MUST bind the responder's long-term keys to the responder's Ethereum account.
+
+### 9. Post-handshake message payload
+
+Each post-handshake message carried in `MessageSent.ciphertext` MUST be encoded as a single binary blob with the following layout:
+
+```text
+Offset Size Field
+0 1 version
+1 64 Ed25519 detached signature
+65 32 DH ratchet public key
+97 4 pn (uint32, big-endian)
+101 4 n (uint32, big-endian)
+105 24 XSalsa20-Poly1305 nonce
+129 var ciphertext
+```
+
+Version `0x01` is REQUIRED for this proposal.
+
+The Ed25519 signature MUST cover all bytes from offset `65` to the end of the payload.
+
+When a transcript is later disclosed, verifiers can combine this signature with the wallet-bound identity proof established during the handshake to attribute the message to the sender's bound messaging key.
+
+The payload semantics are:
+
+- `pn`: number of messages in the sender's previous DH epoch;
+- `n`: message number in the sender's current DH epoch.
+
+### 10. Message framing and padding
+
+Before symmetric encryption, plaintext MUST be framed as:
+
+```text
+0x00 || uint32_be(plaintext_length) || plaintext || random_padding
+```
+
+The padded size MUST be selected using the following bucket rules:
+
+- framed size `<= 64` bytes: bucket size `64`;
+- framed size `65..16384` bytes: next power of two;
+- framed size `> 16384` bytes: next multiple of `4096`.
+
+An implementation MAY add random jitter up to `floor(bucket / 8)` bytes before symmetric encryption.
+
+### 11. Topic derivation
+
+Post-handshake message transport uses topic hashes derived from ratchet state.
+
+The canonical topic derivation is:
+
+```text
+okm = HKDF-SHA256(
+ ikm=dhOutput,
+ salt=rootKey,
+ info="verbeth:topic-{direction}:v3",
+ len=32
+ )
+topic = keccak256(okm)
+```
+
+Where:
+
+- `direction` is either `outbound` or `inbound`;
+- `rootKey` is the current ratchet root key; and
+- `dhOutput` is the X25519 DH output for the relevant ratchet step.
+
+The root key used as HKDF salt SHOULD incorporate both classical and post-quantum shared secrets.
+
+For the hybrid session bootstrap used by this proposal, the canonical initial root key is:
+
+```text
+combined = x25519Secret || kemSecret
+rootKey = HKDF-SHA256(
+ ikm=combined,
+ salt=zeros(32),
+ info="VerbethHybrid",
+ len=32
+ )
+```
+
+### 12. Session behavior
+
+This proposal standardizes the transport and wire formats needed for interoperable session establishment and message exchange. It does not fully standardize application storage behavior, but the following receiver behavior is RECOMMENDED:
+
+- receivers SHOULD track at least current, next, and previous inbound topics during topic transitions;
+- receivers SHOULD support skipped-message handling for out-of-order delivery; and
+- senders SHOULD treat ratchet state as committed before transaction broadcast, so failed broadcasts consume a ratchet slot rather than reusing it.
+
+## Rationale
+
+### Why event logs
+
+Event logs provide the narrowest onchain primitive needed for interoperable message publication and retrieval. This keeps contract logic simple, allows independent clients to discover messages via standard RPC methods, and avoids entangling the standard with operator-run relay infrastructure.
+
+### Why no onchain validation
+
+The transport contract intentionally does not validate ciphertexts, public keys, signatures, or nonce sequencing. Those checks are performed offchain by clients. This lowers gas costs and preserves flexibility for implementations.
+
+### Why plaintext handshake payloads
+
+The handshake payload is plaintext so that the recipient can verify the wallet-bound identity proof immediately upon discovery. The tradeoff is that the handshake note is public, so applications that need a private first-contact message should use a future extension or an optional pre-key mechanism.
+
+### Why wallet-bound identity and non-repudiation matter
+
+Event-log transport already gives public evidence that some account authorized publication of a ciphertext at a particular block and transaction. This proposal embraces that property instead of trying to emulate deniable transport semantics that do not fit well with public logs.
+
+The wallet-bound identity proof standardizes how long-term messaging keys are bound to an Ethereum account, while the signed ratcheted payload standardizes how later disclosed transcript material can be attributed to that bound messaging identity. Together, these pieces provide accountable privacy: message contents remain encrypted by default, but participants can later reveal specific plaintexts and protocol artifacts to prove authorship, timing, and transport publication to a third party.
+
+This property enables use cases that benefit from both confidentiality and portable accountability. One example is an agentic economy in which autonomous agents negotiate terms, quotes, or side agreements privately, yet their operators may later need to prove which account authorized a disputed instruction or accepted a private deal. Similar requirements appear in escrow coordination, B2B operations, delegated execution, and compliance workflows.
+
+This is intentionally different from deniable protocols in the Signal family, where transcript artifacts are designed not to become portable third-party proof. Here, the goal is not deniability; it is private communication with optional, disclosure-dependent authorship.
+
+### Why deterministic recipient discovery remains in v1
+
+This proposal retains a deterministic `recipientHash` because it offers a simple and easily implementable discovery primitive for first contact without requiring an onchain key registry or specialized discovery infrastructure.
+
+The tradeoff is explicit: a deterministic recipient selector leaks attempted first-contact edges to public observers whenever the recipient is guessable from a candidate set. This proposal therefore standardizes a minimal interoperable transport, not a complete anonymous-discovery system.
+
+A future extension MAY define an anonymous handshake-discovery profile in which recipient-targeting information is carried only inside encrypted payload material rather than exposed as a deterministic public selector.
+
+### Why two response keypairs
+
+Using a dedicated response-tag keypair and a separate ratchet keypair prevents an observer from linking the `HandshakeResponse` event to the first ratcheted message header.
+
+### Why standardized wire formats
+
+Without fixed binary and JSON layouts, independent clients may all be "Verbeth-compatible" in principle while still failing to parse each other's messages in practice. The wire format is therefore a core interoperability surface and belongs in the standard.
+
+### Why this proposal is narrow
+
+This proposal leaves storage, indexers, sync, UX, anti-spam systems, delegated execution modules, and deployment conventions out of scope because those concerns are either environment-specific or still evolving. The goal is to standardize the smallest stable surface first.
+
+## Backwards Compatibility
+
+This is a new application-layer standard and introduces no backwards compatibility issues for existing ERCs.
+
+For local backwards compatibility with earlier Verbeth experiments:
+
+- implementations MAY accept unversioned 64-byte long-term public key blobs;
+- implementations MAY support alternative internal storage layouts; and
+- implementations MAY expose additional non-standard helper methods.
+
+However, compliant emitters MUST emit the versioned wire formats defined in this document.
+
+## Test Cases
+
+The following conformance scenarios SHOULD be covered by reference tests and test vectors:
+
+1. Handshake initiation with valid `recipientHash`, `pubKeys`, `ephemeralPubKey`, and `plaintextPayload`.
+2. Handshake payload rejection when `identityProof` is missing or malformed.
+3. Identity proof verification failure on mismatched X25519 key, Ed25519 key, `ExecutorAddress`, `ChainId`, or `RpId`.
+4. Handshake response matching via `inResponseTo` recomputation from the initiator secret material.
+5. Handshake response decryption and extraction of responder long-term keys, ratchet public key, and `kemCiphertext`.
+6. Initiator and responder deriving the same hybrid initial root key.
+7. Post-handshake message signature verification using Ed25519 over the canonical payload bytes.
+8. Topic derivation producing identical `bytes32` outputs across independent implementations.
+9. Out-of-order message handling via skipped keys and previous-topic grace behavior.
+10. Smart-account and EOA transport senders both interoperating with the same wire format.
+11. Disclosed transcript verification combining onchain event inclusion, wallet-bound identity proof validation, and ratcheted payload signature verification.
+
+Current reference tests in this repository include:
+
+- `packages/sdk/test/verify.test.ts`
+- `packages/sdk/test/ratchet.test.ts`
+- `packages/sdk/test/codec.test.ts`
+- `packages/sdk/test/pq.test.ts`
+- `tests/handshaking.test.ts`
+- `tests/e2e.test.ts`
+
+## Reference Implementation
+
+The current reference implementation is Verbeth:
+
+- transport contract: `packages/contracts/contracts/VerbethV1.sol`
+- SDK and wire-format logic: `packages/sdk/src`
+- end-to-end integration tests: `tests`
+
+This pre-draft should be accompanied by public test vectors before submission to `ethereum/ERCs`.
+
+## Security Considerations
+
+### Metadata goals
+
+This proposal distinguishes between:
+
+- privacy against a public onchain observer that sees events but not client queries; and
+- privacy against a malicious RPC provider or indexer that sees both onchain events and recipient query filters.
+
+The current design provides stronger protection for conversation continuity than for first-contact discovery.
+
+### Public observer metadata
+
+All onchain observers can see sender addresses, event timing, gas usage, topic hashes, and ciphertext sizes. This proposal protects message contents, not all metadata.
+
+### Recipient discovery leakage
+
+Because `recipientHash` is derived deterministically from the recipient address, a public observer who can guess candidate addresses can test those guesses offline.
+
+This means the current design does not provide full recipient anonymity at handshake time. A public observer may learn that sender `A` attempted first contact with recipient `B` when `B` is guessable from the observer's candidate set.
+
+### Continuity protection after first contact
+
+Even when a public observer can recover the recipient from `recipientHash`, the observer still cannot use public data alone to:
+
+- cryptographically link a `Handshake` to a later `HandshakeResponse`;
+- cryptographically prove that the recipient accepted the handshake; or
+- cryptographically link the handshake to later ratcheted `MessageSent` topics.
+
+So the current design may leak attempted first contact while still protecting the stronger continuity property that later responses and post-handshake message flows are not publicly linkable by a direct cryptographic test.
+
+### RPC and indexer query privacy
+
+Clients querying a third-party RPC or indexer for `recipientHash`-specific handshake filters may reveal recipient interest directly to that service. This creates a bootstrap deanonymization risk: once an RPC or indexer can associate a network client with a recipient address during handshake discovery, later topic queries may become attributable to that same recipient even if the topics themselves are unlinkable onchain.
+
+Private retrieval mechanisms are explicitly out of scope for this proposal. Implementations that rely on third-party RPCs SHOULD treat server-side recipient filtering as a privacy-sensitive operation. Implementations concerned with this threat SHOULD prefer client-side scanning or other private retrieval techniques.
+
+### Residual traffic analysis
+
+Even if query privacy is improved and deterministic recipient discovery is removed in a future extension, visible sender addresses, event timing, activity bursts, and traffic sparsity still create heuristic linkage opportunities.
+
+So the intended privacy statement of this proposal is not that observers learn nothing, but that they lack a public cryptographic test for exact linkage and are forced to fall back to statistical traffic analysis over visible metadata.
+
+### Attribution and no deniability
+
+Each emitted ciphertext is also an onchain transaction effect. As a result, third parties can always verify that a specific transport sender authorized publication of a given ciphertext at a specific block and transaction.
+
+If plaintext and session artifacts are later disclosed, the wallet-bound identity proof and ratcheted message signature can turn that public transport fact into stronger transcript-level attribution. In other words, the design supports disclosure-dependent non-repudiation.
+
+This is a feature for applications that need accountable privacy, but it is also a sharp tradeoff. Users and integrators MUST NOT assume Signal-style deniability. Implementations SHOULD explain clearly that disclosed transcripts may become portable proof of authorship.
+
+### Duplicate nonce and spam
+
+The transport contract does not enforce nonce uniqueness, replay prevention, or anti-spam controls. Receivers MUST perform their own deduplication and abuse handling.
+
+### State loss
+
+Because ratchet state lives offchain, losing local session state may render stored ciphertext undecryptable even though the transport log remains available.
+
+### Compromise recovery
+
+Forward secrecy and post-compromise recovery depend on correct ratchet state management by clients. A compromised device may decrypt future messages until a fresh DH ratchet step restores security.
+
+### Cryptographic assumptions
+
+The privacy and unlinkability properties of this proposal depend on the security of X25519, Ed25519, XSalsa20-Poly1305, HKDF-SHA256, keccak256, and ML-KEM-768 as used by the selected versioned formats.
+
+### Algorithm agility
+
+Future versions MAY define new key types, new KEMs, new symmetric encryption schemes, or new topic derivation strings. Implementations MUST NOT silently reinterpret version `0x01` payloads under different algorithms.
+
+## Copyright
+
+Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
diff --git a/erc/ethereum-magicians-thread-draft.md b/erc/ethereum-magicians-thread-draft.md
new file mode 100644
index 0000000..cac1e96
--- /dev/null
+++ b/erc/ethereum-magicians-thread-draft.md
@@ -0,0 +1,140 @@
+# Event log end-to-end encrypted messaging
+
+Hi all
+
+I have been working on a predraft for a post-quantum resistant encrypted messaging over EVM event logs and I wanted to share it early for feedback before trying to turn it into a formal ERC submission. Also, I want to gather opinions if this needs a standardization at all.
+
+[Public draft link goes here](PUBLIC_URL_HERE)
+
+The goal is to standardize a small transport and wire format surface that independent clients can actually interoperate on, not to standardize indexing, notifications, storage, spam control, account abstraction UX or inbox behavior. Those concerns are left to frontend applications.
+
+## Related work
+
+This is not the first attempt in this area.
+
+- [ERC 7627](https://ethereum-magicians.org/t/erc-7627-secure-messaging-protocol/18761) explores secure messaging with more emphasis on onchain key registration and flexible conversation metadata.
+
+- [ERC 7970](https://ethereum-magicians.org/t/erc-stateless-encrypted-communication-standard/24554) is probably the closest event based proposal in spirit, but it keeps the cryptographic behavior and wire format somewhat unspecified.
+
+- [ERC 8180](https://ethereum-magicians.org/t/erc-8180-blob-authenticated-messaging-bam/27868) (somewhat the evolution od ERC-3722) is also relevant, but to me it sits next to this work rather than on top of the same exact problem, since it is about authenticated messaging over blobs and decoder discovery.
+
+My impression is that the design space still has not converged, and I think there is room for a more opinionated interoperable approach here. This post also comes from an implementation first perspective, since I have been exploring and testing these ideas in a [public SDK]((https://github.com/okrame/verbeth/tree/main/packages/sdk)) and [demo](https://verbeth-demo.vercel.app/) already.
+
+
+## What I am proposing
+
+1. A small transport contract with `sendMessage`, `initiateHandshake`, and `respondToHandshake`
+2. Three events for handshake initiation, handshake response, and post handshake message delivery
+3. Versioned long term public keys for encryption and signing
+4. Wallet bound identity proofs that bind those keys to an EVM account
+5. Handshake response tags that are not publicly linkable to the initiating handshake
+6. Ratcheted message topics that rotate across epochs rather than behaving like stable conversation identifiers
+
+## High level flow
+
+This is the simplified lifecycle I have been experimenting with:
+
+```text
+Alice Bob
+
+1. Gen ephemeral X25519 key
+2. Gen ML-KEM 768 keypair
+3. Build wallet bound identity proof
+
+Handshake event ------------------------------------------>
+ recipientHash selector
+ sender longterm pubkeys
+ initiator ephemeral X25519 + ML-KEM pubkey
+ identity proof + optional pt note
+
+ 4. Read handshake
+ 5. Verify identity proof
+ 6. Gen response tag keypair
+ 7. Gen first ratchet keypair
+ 8. Encapsulate to Alice ML-KEM pubkey
+ 9. Derive hybrid response tag
+
+HandshakeResponse event <---------------------------------
+ inResponseTo derived from classical + PQ secret material
+ public response tag key
+ encrypted payload carrying
+ responder longterm pubkeys
+ first ratchet public key
+ ML-KEM ciphertext
+ responder identity proof
+
+10. Decrypt response
+11. Recompute and verify inResponseTo
+12. Derive the same hybrid root key
+13. Initialize ratchet session
+
+Session established
+
+MessageSent event ---------------------------------------->
+ signed ratcheted payload on current topic
+
+MessageSent event <----------------------------------------
+ signed ratcheted payload on current topic
+
+As new DH epochs appear, topics rotate and old topics stop behaving like a
+stable public conversation identifier.
+```
+
+
+## Why non-repudiation matters
+
+[Non-repudiation](https://en.wikipedia.org/wiki/Non-repudiation) is an unusual property for a e2ee messaging protocol, and I think it is worth considering it more closely, as it allows for some interesting applications.
+
+Since every delivered ciphertext is also an onchain tx, any third party can verify the block, the tx hash, the emitting contract and the account that published it. Attribution is direct if the sender is an EOA, less so if it's smart account (i.e. still it reduces to owner signatures in calldata or a UserOp signature). Either way, that means the chain already proves one important fact without any transcript disclosure at all: a specific account authorized the publication of a specific ciphertext at a specific time. If plaintext is later disclosed, the wallet bound identity proof and the signed ratcheted payload can connect that disclosed content to the messaging identity used in the session.
+
+This is quite different from systems in the Signal family which are designed so that a saved transcript does not become a portable proof for outsiders (i.e. messages are verified with symmetric MAC keys that both parties share, so either side could plausibly have forged any message).
+
+What I propose here is also different from offchain systems like XMTP but in a more specific way. XMTP can support verifiable attribution through exported protocol artifacts and its identity layer, but that proof is not normally a publicly witnessed chain event. It depends on disclosing offchain transcript material and relating installation level keys to an inbox identity and then to a wallet or other identifier.
+
+### Thoughts on further extensions
+
+One possible extension is hidden delegation, where a relay publishes the ciphertext while the principal identity remains inside the encrypted envelope. In that case, accountability becomes disclosure dependent. Once the recipient reveals the hidden identity proof, a third party can verify both the onchain relay publication and the principal attribution carried in the disclosed proof.
+
+As for deniability, my current view is that full transport level deniability is not compatible with public event logs. A narrower form of deniability inside the ratchet transcript may still be worth exploring, and I would be interested in feedback on whether that is meaningful.
+
+## How to deal with metadata privacy
+
+Assuming full e2ee with forward secrecy and post-comprimosie security, the achievable goal is not to eliminate all metadata, but to eliminate any efficiently verifiable linkage and leave observers with only statistical inference whose quality depends on traffic volume and side information.
+
+Put differently, once deterministic recipient discovery is removed from the transport, or recipient filtering happens client-side rather than at the RPC layer, an observer falls back to heuristics. A simple way to express that is: let `C(e')` be the set of earlier events that are not cryptographically ruled out as possible predecessors of a target event `e'`. Then
+
+`Pr[e ↔ e' | view] = w(e, e') / Σx∈C(e') w(x, e')`
+
+where `w(e, e')` is a heuristic weight derived from timing, visible sender activity, traffic sparsity and any other side information available to the observer. So what should disappear is any public rule that makes one candidate pair dominate the distribution with near certainty. This, of course, matters differently at the public chain observer level and at the RPC or indexer level. that also see client queries.
+
+### Mitigation options
+
+If this proposal says anything about metadata privacy, I think it should explicitly acknowledge the main mitigation choices and their tradeoffs:
+
+- **Keep `recipientHash`, but require client-side scanning**. Clients scan handshake events locally instead of querying an RPC or indexer with recipient-specific filters. This removes the bootstrap leak to a malicious RPC, but it does not hide attempted first contact from public observers who can dictionary-match `recipientHash`. Also it can get heavy recipient-side with `O(N)` scanning.
+
+- **Remove `recipientHash` from the public handshake selector**. Instead of publishing a deterministic recipient selector, the sender includes recipient-targeting material inside an encrypted payload. Recipients then scan handshake events and keep only the ones they can decrypt. This is arguably better, but it still requires linear client-side scanning at least for handshake discovery.
+
+- **Use private signaling with a TEE-assisted indexer**. Another option is to hide recipient interest from the indexing service, following the private-signaling direction explored in [this paper](https://eprint.iacr.org/2021/853.pdf): the sender posts a public mailbox entry while recipient-targeting material is processed inside a TEE, and only the intended recipient learns the match. The tradeoff is extra infrastructure, hardware assumptions, and scalability limits that are very different from the other approaches.
+
+
+My current view is that the ERC should probably avoid over-standardizing this layer, but it would still be useful to be explicit about which privacy model it assumes.
+
+## Resistance to HNDL
+
+Message content confidentiality should not face the threat of harvest now decrypt later. A future attacker should not be able to record traffic today and later use stronger capabilities to recover message contents, link handshake responses to later traffic, or link later ratcheted topics from stored traces alone.
+
+The current construction tries to enforce that with a hybrid bootstrap based on `X25519 + ML-KEM 768`, a handshake response tag derived from both classical and PQ secret material, and topic derivation salted by a hybrid root key. My intent is that the PQ story should cover both confidentiality and linkage resistance, not only message decryption.
+
+
+## What I would most like feedback on
+
+1. Is this the right layer to standardize, or is it still too application-specific to benefit from an ERC?
+2. Is the privacy model coherent, especially the distinction between public-observer privacy and query privacy against RPCs or indexers?
+3. Of the mitigation options above, which one feels realistic for an interoperable standard, if any?
+4. Does the non-repudiation property feel useful here, or is it more likely to be a reason not to pursue this design?
+5. Is the current scope narrow enough, or am I still standardizing too much of the messaging stack?
+
+I would especially value pushback on the privacy and security model. For more details on the contract the sdk, you can find some work in progress docs [here](https://docs.verbeth.xyz/docs/).
+
+Thanks
From 8c48d96bf931fb6a14d96d727c903da9a5135439 Mon Sep 17 00:00:00 2001
From: Marco Esposito
Date: Wed, 8 Apr 2026 17:39:00 +0200
Subject: [PATCH 2/4] link drafts
---
erc/ERC-pre-draft.md | 4 ++--
erc/ethereum-magicians-thread-draft.md | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/erc/ERC-pre-draft.md b/erc/ERC-pre-draft.md
index 2622cc3..dcbdfcf 100644
--- a/erc/ERC-pre-draft.md
+++ b/erc/ERC-pre-draft.md
@@ -1,4 +1,5 @@
---
+
title: Event-Log Encrypted Messaging
description: A minimal application-layer standard for post-quantum-resistant encrypted messaging over EVM event logs.
author: Marco (@okrame)
@@ -7,9 +8,8 @@ status: Draft
type: Standards Track
category: ERC
created: 2026-04-08
----
-> Note: this document is a pre-draft working paper kept in the Verbeth repository.
+---
## Abstract
diff --git a/erc/ethereum-magicians-thread-draft.md b/erc/ethereum-magicians-thread-draft.md
index cac1e96..c406e36 100644
--- a/erc/ethereum-magicians-thread-draft.md
+++ b/erc/ethereum-magicians-thread-draft.md
@@ -4,7 +4,7 @@ Hi all
I have been working on a predraft for a post-quantum resistant encrypted messaging over EVM event logs and I wanted to share it early for feedback before trying to turn it into a formal ERC submission. Also, I want to gather opinions if this needs a standardization at all.
-[Public draft link goes here](PUBLIC_URL_HERE)
+[ERC pre-draft](./ERC-pre-draft.md)
The goal is to standardize a small transport and wire format surface that independent clients can actually interoperate on, not to standardize indexing, notifications, storage, spam control, account abstraction UX or inbox behavior. Those concerns are left to frontend applications.
From dd04c96bc32d47cde03a4874b75e7d7e51a4b0f7 Mon Sep 17 00:00:00 2001
From: Marco Esposito
Date: Fri, 10 Apr 2026 17:45:39 +0200
Subject: [PATCH 3/4] add discussion link
---
erc/ERC-pre-draft.md | 2 +-
erc/ethereum-magicians-thread-draft.md | 140 -------------------------
2 files changed, 1 insertion(+), 141 deletions(-)
delete mode 100644 erc/ethereum-magicians-thread-draft.md
diff --git a/erc/ERC-pre-draft.md b/erc/ERC-pre-draft.md
index dcbdfcf..7b5dfce 100644
--- a/erc/ERC-pre-draft.md
+++ b/erc/ERC-pre-draft.md
@@ -3,7 +3,7 @@
title: Event-Log Encrypted Messaging
description: A minimal application-layer standard for post-quantum-resistant encrypted messaging over EVM event logs.
author: Marco (@okrame)
-discussions-to:
+discussions-to: https://ethereum-magicians.org/t/hybrid-post-quantum-e2ee-messaging-over-evm-event-logs/28198
status: Draft
type: Standards Track
category: ERC
diff --git a/erc/ethereum-magicians-thread-draft.md b/erc/ethereum-magicians-thread-draft.md
deleted file mode 100644
index c406e36..0000000
--- a/erc/ethereum-magicians-thread-draft.md
+++ /dev/null
@@ -1,140 +0,0 @@
-# Event log end-to-end encrypted messaging
-
-Hi all
-
-I have been working on a predraft for a post-quantum resistant encrypted messaging over EVM event logs and I wanted to share it early for feedback before trying to turn it into a formal ERC submission. Also, I want to gather opinions if this needs a standardization at all.
-
-[ERC pre-draft](./ERC-pre-draft.md)
-
-The goal is to standardize a small transport and wire format surface that independent clients can actually interoperate on, not to standardize indexing, notifications, storage, spam control, account abstraction UX or inbox behavior. Those concerns are left to frontend applications.
-
-## Related work
-
-This is not the first attempt in this area.
-
-- [ERC 7627](https://ethereum-magicians.org/t/erc-7627-secure-messaging-protocol/18761) explores secure messaging with more emphasis on onchain key registration and flexible conversation metadata.
-
-- [ERC 7970](https://ethereum-magicians.org/t/erc-stateless-encrypted-communication-standard/24554) is probably the closest event based proposal in spirit, but it keeps the cryptographic behavior and wire format somewhat unspecified.
-
-- [ERC 8180](https://ethereum-magicians.org/t/erc-8180-blob-authenticated-messaging-bam/27868) (somewhat the evolution od ERC-3722) is also relevant, but to me it sits next to this work rather than on top of the same exact problem, since it is about authenticated messaging over blobs and decoder discovery.
-
-My impression is that the design space still has not converged, and I think there is room for a more opinionated interoperable approach here. This post also comes from an implementation first perspective, since I have been exploring and testing these ideas in a [public SDK]((https://github.com/okrame/verbeth/tree/main/packages/sdk)) and [demo](https://verbeth-demo.vercel.app/) already.
-
-
-## What I am proposing
-
-1. A small transport contract with `sendMessage`, `initiateHandshake`, and `respondToHandshake`
-2. Three events for handshake initiation, handshake response, and post handshake message delivery
-3. Versioned long term public keys for encryption and signing
-4. Wallet bound identity proofs that bind those keys to an EVM account
-5. Handshake response tags that are not publicly linkable to the initiating handshake
-6. Ratcheted message topics that rotate across epochs rather than behaving like stable conversation identifiers
-
-## High level flow
-
-This is the simplified lifecycle I have been experimenting with:
-
-```text
-Alice Bob
-
-1. Gen ephemeral X25519 key
-2. Gen ML-KEM 768 keypair
-3. Build wallet bound identity proof
-
-Handshake event ------------------------------------------>
- recipientHash selector
- sender longterm pubkeys
- initiator ephemeral X25519 + ML-KEM pubkey
- identity proof + optional pt note
-
- 4. Read handshake
- 5. Verify identity proof
- 6. Gen response tag keypair
- 7. Gen first ratchet keypair
- 8. Encapsulate to Alice ML-KEM pubkey
- 9. Derive hybrid response tag
-
-HandshakeResponse event <---------------------------------
- inResponseTo derived from classical + PQ secret material
- public response tag key
- encrypted payload carrying
- responder longterm pubkeys
- first ratchet public key
- ML-KEM ciphertext
- responder identity proof
-
-10. Decrypt response
-11. Recompute and verify inResponseTo
-12. Derive the same hybrid root key
-13. Initialize ratchet session
-
-Session established
-
-MessageSent event ---------------------------------------->
- signed ratcheted payload on current topic
-
-MessageSent event <----------------------------------------
- signed ratcheted payload on current topic
-
-As new DH epochs appear, topics rotate and old topics stop behaving like a
-stable public conversation identifier.
-```
-
-
-## Why non-repudiation matters
-
-[Non-repudiation](https://en.wikipedia.org/wiki/Non-repudiation) is an unusual property for a e2ee messaging protocol, and I think it is worth considering it more closely, as it allows for some interesting applications.
-
-Since every delivered ciphertext is also an onchain tx, any third party can verify the block, the tx hash, the emitting contract and the account that published it. Attribution is direct if the sender is an EOA, less so if it's smart account (i.e. still it reduces to owner signatures in calldata or a UserOp signature). Either way, that means the chain already proves one important fact without any transcript disclosure at all: a specific account authorized the publication of a specific ciphertext at a specific time. If plaintext is later disclosed, the wallet bound identity proof and the signed ratcheted payload can connect that disclosed content to the messaging identity used in the session.
-
-This is quite different from systems in the Signal family which are designed so that a saved transcript does not become a portable proof for outsiders (i.e. messages are verified with symmetric MAC keys that both parties share, so either side could plausibly have forged any message).
-
-What I propose here is also different from offchain systems like XMTP but in a more specific way. XMTP can support verifiable attribution through exported protocol artifacts and its identity layer, but that proof is not normally a publicly witnessed chain event. It depends on disclosing offchain transcript material and relating installation level keys to an inbox identity and then to a wallet or other identifier.
-
-### Thoughts on further extensions
-
-One possible extension is hidden delegation, where a relay publishes the ciphertext while the principal identity remains inside the encrypted envelope. In that case, accountability becomes disclosure dependent. Once the recipient reveals the hidden identity proof, a third party can verify both the onchain relay publication and the principal attribution carried in the disclosed proof.
-
-As for deniability, my current view is that full transport level deniability is not compatible with public event logs. A narrower form of deniability inside the ratchet transcript may still be worth exploring, and I would be interested in feedback on whether that is meaningful.
-
-## How to deal with metadata privacy
-
-Assuming full e2ee with forward secrecy and post-comprimosie security, the achievable goal is not to eliminate all metadata, but to eliminate any efficiently verifiable linkage and leave observers with only statistical inference whose quality depends on traffic volume and side information.
-
-Put differently, once deterministic recipient discovery is removed from the transport, or recipient filtering happens client-side rather than at the RPC layer, an observer falls back to heuristics. A simple way to express that is: let `C(e')` be the set of earlier events that are not cryptographically ruled out as possible predecessors of a target event `e'`. Then
-
-`Pr[e ↔ e' | view] = w(e, e') / Σx∈C(e') w(x, e')`
-
-where `w(e, e')` is a heuristic weight derived from timing, visible sender activity, traffic sparsity and any other side information available to the observer. So what should disappear is any public rule that makes one candidate pair dominate the distribution with near certainty. This, of course, matters differently at the public chain observer level and at the RPC or indexer level. that also see client queries.
-
-### Mitigation options
-
-If this proposal says anything about metadata privacy, I think it should explicitly acknowledge the main mitigation choices and their tradeoffs:
-
-- **Keep `recipientHash`, but require client-side scanning**. Clients scan handshake events locally instead of querying an RPC or indexer with recipient-specific filters. This removes the bootstrap leak to a malicious RPC, but it does not hide attempted first contact from public observers who can dictionary-match `recipientHash`. Also it can get heavy recipient-side with `O(N)` scanning.
-
-- **Remove `recipientHash` from the public handshake selector**. Instead of publishing a deterministic recipient selector, the sender includes recipient-targeting material inside an encrypted payload. Recipients then scan handshake events and keep only the ones they can decrypt. This is arguably better, but it still requires linear client-side scanning at least for handshake discovery.
-
-- **Use private signaling with a TEE-assisted indexer**. Another option is to hide recipient interest from the indexing service, following the private-signaling direction explored in [this paper](https://eprint.iacr.org/2021/853.pdf): the sender posts a public mailbox entry while recipient-targeting material is processed inside a TEE, and only the intended recipient learns the match. The tradeoff is extra infrastructure, hardware assumptions, and scalability limits that are very different from the other approaches.
-
-
-My current view is that the ERC should probably avoid over-standardizing this layer, but it would still be useful to be explicit about which privacy model it assumes.
-
-## Resistance to HNDL
-
-Message content confidentiality should not face the threat of harvest now decrypt later. A future attacker should not be able to record traffic today and later use stronger capabilities to recover message contents, link handshake responses to later traffic, or link later ratcheted topics from stored traces alone.
-
-The current construction tries to enforce that with a hybrid bootstrap based on `X25519 + ML-KEM 768`, a handshake response tag derived from both classical and PQ secret material, and topic derivation salted by a hybrid root key. My intent is that the PQ story should cover both confidentiality and linkage resistance, not only message decryption.
-
-
-## What I would most like feedback on
-
-1. Is this the right layer to standardize, or is it still too application-specific to benefit from an ERC?
-2. Is the privacy model coherent, especially the distinction between public-observer privacy and query privacy against RPCs or indexers?
-3. Of the mitigation options above, which one feels realistic for an interoperable standard, if any?
-4. Does the non-repudiation property feel useful here, or is it more likely to be a reason not to pursue this design?
-5. Is the current scope narrow enough, or am I still standardizing too much of the messaging stack?
-
-I would especially value pushback on the privacy and security model. For more details on the contract the sdk, you can find some work in progress docs [here](https://docs.verbeth.xyz/docs/).
-
-Thanks
From 20e096432bf575a6fa0290babe52806eb6d48874 Mon Sep 17 00:00:00 2001
From: Marco Esposito
Date: Wed, 15 Apr 2026 17:23:29 +0200
Subject: [PATCH 4/4] fix readme
---
README.md | 61 +++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index af32588..a7aab29 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,9 @@
-
+
@@ -32,28 +32,63 @@
- [**TweetNaCl**](https://tweetnacl.js.org/) – for encryption/decryption with NaCl box
- [**Ethers v6**](https://docs.ethers.org/v6/) – for all Ethereum interactions
- [**Viem**](https://viem.sh/) – specific for EIP-1271/6492 verification
-- [**Dexie**](https://dexie.org/) – used for the local IndexedDB storage in the [demo app](https://verbeth-demo.vercel.app/)
----
+
## How it works
-To start a conversation, Alice emits a `Handshake` event with her ephemeral keys and an identity proof. Bob sees it, verifies her, and replies with a `HandshakeResponse`. They combine X25519 and ML-KEM-768 secrets to derive a shared root key that's secure even against future quantum computers.
+To start a conversation, Alice emits a `Handshake` event with her ephemeral keys and an identity proof. Bob sees it, verifies her, and replies with a `HandshakeResponse`. They combine X25519 and ML-KEM-768 secrets to derive a shared root key that's secure against future quantum computers.
+
+From there it's just encrypted `MessageSent` events back and forth. A Double Ratchet keeps churning keys forward so old messages stay safe even if something leaks later. Topics rotate too, making it hard for observers to link conversations across time.
+
+
+### Deployed Address
+
+Verbeth goes through the proxy at `0x82C9c5475D63e4C9e959280e9066aBb24973a663`. The current implementation behind it is `VerbethV1` at `0x51670aB6eDE1d1B11C654CCA53b7D42080802326`. Every deployment uses deterministic CREATE2, so the same address shows up on every supported chain:
+
+| Chain | Chain ID |
+| --- | --- |
+| Base mainnet | 8453 |
+| Base Sepolia | 84532 |
+| Ethereum Sepolia | 11155111 |
+
+For mor in-depth explanations on like discoverability, identity key binding and non-repudiation head over to the [docs](https://docs.verbeth.xyz).
+
+
+## Install
+
+The SDK is published on npm as [`@verbeth/sdk`](https://www.npmjs.com/package/@verbeth/sdk). Drop it into any project with
+
+```bash
+npm install @verbeth/sdk
+```
-From there it's just encrypted `MessageSent` events back and forth. A Double Ratchet keeps churning keys forward so old messages stay safe even if something leaks later. Topics rotate too, making it hard for observers to link conversations across time. More info [here]().
+or with pnpm
+```bash
+pnpm add @verbeth/sdk
+```
-### Deployed Addresses (base mainnet)
-VerbethV1 (singleton) `0x51670aB6eDE1d1B11C654CCA53b7D42080802326`
+## Build from source
-ERC1967Proxy `0x82C9c5475D63e4C9e959280e9066aBb24973a663`
+If you want to hack on the protocol locally, clone the repo and build everything from scratch. You'll need pnpm since the workspace relies on it.
+```bash
+git clone https://github.com/okrame/verbeth.git
+cd verbeth
+pnpm install
+pnpm run build
+```
-### Notes on the current model
+That compiles both the SDK and the contracts. The SDK lands in `packages/sdk/dist` with CJS and ESM outputs ready to be consumed.
-**Discoverability**: If the sender does not yet know the recipient’s long-term public key (X25519), the sender (i.e. initiator) must emit a `Handshake` event. The recipient (i.e. reponder) replies with their keys and identity proof, after which the sender caches the verified mapping. If the key is already known (from a past `HandshakeResponse`, an on-chain announcement, or a static mapping), the handshake can be skipped.
+To run the test suite
-**Identity key binding**: The message (es. “VerbEth Key Binding v1\nAddress: …\nPkEd25519: …\nPkX25519: …\nContext: …\nVersion: …”) is signed by the evm account directly binding its address to the long-term keys (i.e. preventing impersonation).
+```bash
+pnpm run test:unit
+pnpm run test:contracts
+pnpm run test:integration
+```
-**Non-repudiation**: By default, confidentiality and integrity are guaranteed by AEAD with NaCl box. Additionally, the sender can attach a detached Ed25519 signature over using the Ed25519 key bound in the handshake. This effectively provides per-message origin authentication that is verifiable: a recipient (or any third party) can prove the message was produced by the holder of that specific Ed25519 key. Otherwise, attribution relies on context, making sender spoofing at the application layer harder to detect. |
+The integration tests need Anvil running, so run it in another terminal first with `pnpm run anvil:start`.