From 7ce6031c27622ebe1ff97a0de83b6ca3bf4d24ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Abadesso?= Date: Sun, 15 Mar 2026 13:42:07 -0300 Subject: [PATCH 1/3] feat: RFC for Web3Auth social login integration Design document for integrating Web3Auth into Hathor wallets, enabling social login (Google, Apple, email) as an alternative to seed phrase management. --- projects/wallets/0001-web3auth-integration.md | 570 ++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 projects/wallets/0001-web3auth-integration.md diff --git a/projects/wallets/0001-web3auth-integration.md b/projects/wallets/0001-web3auth-integration.md new file mode 100644 index 0000000..53caa10 --- /dev/null +++ b/projects/wallets/0001-web3auth-integration.md @@ -0,0 +1,570 @@ +- Feature Name: web3auth_social_login +- Start Date: 2026-03-15 +- RFC PR: +- Hathor Issue: +- Author: André Cardoso + +# Summary +[summary]: #summary + +Integrate Web3Auth into the Hathor desktop wallet to allow users to create and access wallets via social login (Google, Apple, email, etc.) instead of managing 24-word seed phrases. Web3Auth splits the user's private key into multiple shares using a threshold scheme, so no single party (including Web3Auth) ever holds the full key. The user authenticates with a familiar social provider, and the wallet reconstructs the key client-side from the social login share and a device share — providing a non-custodial UX that feels custodial. + +# Motivation +[motivation]: #motivation + +Seed phrases are the single biggest barrier to mainstream adoption of self-custodial wallets. Users lose them, screenshot them, or never write them down. This creates two problems: (1) new users are intimidated by the onboarding flow and abandon it, and (2) existing users lose access to funds when devices are lost or replaced. + +Web3Auth solves this by replacing seed phrase management with social login. The expected outcomes are: + +- **Lower onboarding friction**: Users sign in with Google/Apple instead of writing down 24 words. +- **Reduced fund loss**: Key recovery is tied to the user's social identity, not a piece of paper. +- **Non-custodial guarantee preserved**: Hathor and Web3Auth never have access to the full private key. +- **Existing wallet compatibility**: Users can still import/export seed phrases for power-user workflows and interoperability with other Hathor wallets. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +## User experience + +When a user opens the Hathor wallet for the first time, they will see a new option alongside "Software Wallet" and "Hardware Wallet": + +- **Social Login** — Create or access a wallet using Google, Apple, email, or other social providers. + +### Creating a wallet with social login + +1. User selects "Social Login" on the wallet type screen. +2. A Web3Auth modal opens (or an embedded UI, depending on SDK choice). The user picks a provider (e.g., Google). +3. The user authenticates with the provider in a popup/redirect flow. +4. Web3Auth reconstructs the private key client-side from two shares (social share + device share). +5. The wallet derives the Hathor xpriv from the reconstructed key and starts normally. +6. The user is prompted to set a PIN (same as the current software wallet flow) for local session locking. +7. The wallet is ready — no seed phrase needed. + +### Returning to the wallet + +On subsequent visits, the user unlocks with their PIN (if the device share is present). If the user clears browser data or uses a new device, they re-authenticate via social login to retrieve the social share, and Web3Auth prompts them to set up a new device share. + +### Recovery + +If the user loses their device: +1. They authenticate via social login on a new device (retrieves social share from Web3Auth Auth Network). +2. They use their recovery share (set up during onboarding — e.g., a backup file, security question, or secondary device). +3. The key is reconstructed and the wallet is restored. + +### Exporting to a standard wallet + +Advanced users can export their private key or derive seed words from it, allowing migration to any standard Hathor wallet. This is an opt-in power-user feature. + +### Impact on existing flows + +- The existing "Software Wallet" and "Hardware Wallet" paths remain unchanged. +- Social login is a new, parallel onboarding path that produces the same wallet object (`HathorWallet`) internally. +- All downstream features (token management, nano contracts, atomic swaps) work identically regardless of how the wallet was created. + +## Concepts + +- **Social Share (ShareA)**: A key share managed by the Web3Auth Auth Network. It is itself split across 5 nodes — no single node holds the complete social share. Released only when the user successfully authenticates via OAuth. +- **Device Share (ShareB)**: A key share stored locally on the user's device (browser localStorage or Electron secure storage). +- **Recovery Share (ShareC)**: A backup key share the user controls — stored as a file, derived from a security question, or held on a secondary device. +- **Threshold**: 2-of-3 shares are needed to reconstruct the private key. Any combination of two shares works. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +## How Web3Auth works — infrastructure deep dive + +### The Auth Network: servers and nodes + +Web3Auth's Auth Network (formerly the Torus Network) is the infrastructure that manages the social login share. It currently consists of **5 nodes on Sapphire Mainnet**: + +| Node | Endpoint | +|------|----------| +| Node 1 | `https://node-1.node.web3auth.io` | +| Node 2 | `https://node-2.node.web3auth.io` | +| Node 3 | `https://node-3.node.web3auth.io` | +| Node 4 | `https://node-4.node.web3auth.io` | +| Node 5 | `https://node-5.node.web3auth.io` | + +Each node exposes several JSON-RPC service paths: +- `/sss/jrpc` — Shamir Secret Sharing operations (key retrieval) +- `/rss` — Resharing/Recovery operations +- `/tss` — Threshold Signature Scheme (DKLS19, for ECDSA/secp256k1) +- `/tss-frost` — FROST TSS (for Ed25519) + +**All 5 nodes are operated by Web3Auth (Torus Labs).** The nodes are geographically distributed (US-East, US-West, Singapore, South America, Europe) but are not operated by independent parties. This is a critical trust assumption discussed in the Drawbacks section. + +The node list is anchored on-chain via a smart contract on Ethereum mainnet (`0xf20336e16B5182637f09821c27BDe29b0AFcfe80`), which acts as a registry. Node membership is governed by epochs, but in practice changes are controlled by the Web3Auth team. + +Beyond the 5 Auth Network nodes, the Web3Auth SDK also connects to: + +| Service | Endpoint | Purpose | +|---------|----------|---------| +| Metadata server | `https://api.web3auth.io/metadata-service` | Key-value store for encrypted metadata (share commitments, device list, threshold config) | +| Session server | `https://session.web3auth.io` | WebSocket-based session management | +| Signer service | `https://api.web3auth.io/signer-service` | Transaction signing coordination | +| Node discovery | `https://api.web3auth.io/fnd-service` | Fetches current node list and endpoints | +| Auth service | `https://api.web3auth.io/authjs-service` | OAuth flow backend | + +The node software is written in Go (open-source at `github.com/torusresearch/torus-node`) and uses **Tendermint BFT** consensus for inter-node agreement and **libp2p** for peer-to-peer DKG (Distributed Key Generation) messaging. + +### How keys are generated — Distributed Key Generation (DKG) + +When a user signs up for the first time, no single machine ever generates or sees the complete private key. Instead, the 5 nodes collectively perform a **Distributed Key Generation (DKG)** protocol based on Asynchronous Verifiable Secret Sharing (AVSS, Cachin et al. 2002): + +```mermaid +sequenceDiagram + participant N1 as Node 1 + participant N2 as Node 2 + participant N3 as Node 3 + participant N4 as Node 4 + participant N5 as Node 5 + + Note over N1,N5: Each node generates a random bivariate polynomial B_i(x,y) + + N1->>N2: B_1(2, y) (horizontal slice) + N1->>N3: B_1(3, y) + N1->>N4: B_1(4, y) + N1->>N5: B_1(5, y) + N2->>N1: B_2(1, y) + N2->>N3: B_2(3, y) + Note over N1,N5: ... (all nodes exchange slices with all other nodes) + + Note over N1,N5: Each node verifies consistency
using echo-based verification + + Note over N1,N5: Result: each node holds a sub-share
of the user's key.
The complete private key σ = Σ B_i(0,0)
was never computed anywhere. +``` + +The result: the user's private key `σ` is defined as the sum of the constant terms of each node's polynomial, but no single node (or any single machine) ever computes this sum. Each node only knows its own contribution. + +Keys are pre-generated in batches so that assignment to new users is fast (no DKG needed at login time). + +### How the key is split — Shamir Secret Sharing math + +The user's key is protected by a **(2,3) Shamir Secret Sharing** scheme over the finite field `Zq` (where `q` is the order of the secp256k1 curve group): + +**Polynomial construction:** +A degree-1 polynomial is defined: `f(z) = a₁·z + σ` over `Zq`, where `σ = f(0)` is the private key scalar. + +**Three shares are computed at distinct evaluation points:** +- `ShareA = f(z₁)` — the social login share (distributed across the 5 nodes) +- `ShareB = f(z₂)` — stored on the user's device +- `ShareC = f(z₃)` — recovery/backup share controlled by the user + +**Reconstruction via Lagrange interpolation:** +Given any 2 shares, e.g., `f(zᵢ)` and `f(zⱼ)`, reconstruct: + +``` +σ = f(0) = f(zᵢ) · Lⱼ(0) + f(zⱼ) · Lᵢ(0) +``` + +where `Lᵢ`, `Lⱼ` are Lagrange basis polynomials evaluated at 0. + +```mermaid +graph TB + subgraph "2-of-3 Threshold Scheme" + KEY["Private Key σ = f(0)"] + SA["ShareA = f(z₁)
Social Login Share
Split across 5 nodes"] + SB["ShareB = f(z₂)
Device Share
User's localStorage"] + SC["ShareC = f(z₃)
Recovery Share
User-controlled backup"] + end + + SA --> |"Any 2 shares"| KEY + SB --> |"reconstruct σ via"| KEY + SC --> |"Lagrange interpolation"| KEY + + subgraph "Normal Login" + NL["ShareA + ShareB → σ"] + end + + subgraph "Device Lost" + DL["ShareA + ShareC → σ"] + end + + subgraph "Web3Auth Down" + WD["ShareB + ShareC → σ"] + end +``` + +### Where each share is physically stored + +#### ShareA — Social Login Share (Web3Auth Auth Network) + +ShareA is **not stored as a single value on any server**. It is itself distributed across the 5 Auth Network nodes using a 5-of-9 internal threshold. Each node holds a sub-share. When the user authenticates, each node releases its sub-share (encrypted) to the client, which reconstructs ShareA locally. + +``` +ShareA is NOT stored whole anywhere. +Node 1 holds: sub-share₁ of ShareA +Node 2 holds: sub-share₂ of ShareA +Node 3 holds: sub-share₃ of ShareA +Node 4 holds: sub-share₄ of ShareA +Node 5 holds: sub-share₅ of ShareA +``` + +Sub-shares are encrypted at rest in each node's database. During retrieval, they are encrypted with the client's ephemeral public key (ECIES/secp256k1) before transmission over the network. + +#### ShareB — Device Share + +Stored in the user's browser `localStorage` or `IndexedDB` (web) or the OS secure keychain (mobile). In Electron, this could be secured with the `safeStorage` API. The share is a raw scalar value stored as an encrypted blob. + +#### ShareC — Recovery Share + +Controlled entirely by the user. Web3Auth does not hold this share. Storage options include: +- A downloadable backup file +- Derived deterministically from a security question/password +- Stored on a separate device +- A paper backup + +#### Metadata (not a share) + +The metadata server (`api.web3auth.io/metadata-service`) stores non-sensitive information: +- Polynomial commitments (`g^a₀`, `g^a₁` — public values, cannot derive shares) +- Share commitments (`g^ShareA`, `g^ShareB`, `g^ShareC` — public values) +- Device list and device metadata +- Threshold configuration (2-of-3) +- Encrypted nonces linking keys across accounts + +Metadata is signed by the user's key on write and verified on read. Contents are encrypted with the user's key — Web3Auth can see that data exists for a user but cannot read the encrypted contents without the user's key. + +### The full private key is NEVER sent over the network + +The full private key `σ` is never transmitted, never stored on any server, and never exists outside the user's device memory. The only things that travel over the network are: +- OAuth tokens (from the social provider to the client and nodes) +- Encrypted sub-shares of ShareA (from each node to the client, encrypted with ephemeral ECIES keys) +- Metadata reads/writes (encrypted, non-sensitive) + +### Authentication flow — step by step + +Here is exactly what happens when a user clicks "Sign in with Google": + +```mermaid +sequenceDiagram + actor User + participant SDK as Web3Auth SDK
(client-side) + participant Google as Google OAuth + participant N1 as Node 1 + participant N2 as Node 2 + participant N3 as Node 3 + participant N4 as Node 4 + participant N5 as Node 5 + participant Meta as Metadata Server + participant LS as localStorage + + User->>SDK: Click "Sign in with Google" + SDK->>Google: OAuth 2.0 / OIDC redirect + User->>Google: Enter credentials + Google-->>SDK: JWT id_token (sub, email, iss, aud, exp) + + Note over SDK: Generate ephemeral secp256k1 keypair
(pubKeyₑ, privKeyₑ) + + Note over SDK: Compute commitment = hash(id_token) + + par Anti-replay commit phase (Bracha's Reliable Broadcast) + SDK->>N1: commitment + pubKeyₑ + SDK->>N2: commitment + pubKeyₑ + SDK->>N3: commitment + pubKeyₑ + SDK->>N4: commitment + pubKeyₑ + SDK->>N5: commitment + pubKeyₑ + end + + Note over N1,N5: Each node checks: is this
commitment novel? Sign if yes. + + N1-->>SDK: signature₁ on commitment + N2-->>SDK: signature₂ on commitment + N3-->>SDK: signature₃ on commitment + + Note over SDK: Threshold of signatures collected.
Reveal id_token to nodes. + + par Token verification + share release + SDK->>N1: id_token (reveal) + SDK->>N2: id_token (reveal) + SDK->>N3: id_token (reveal) + SDK->>N4: id_token (reveal) + SDK->>N5: id_token (reveal) + end + + Note over N1,N5: Each node independently:
1. Verifies JWT signature via Google JWKS
2. Checks iss, aud, exp, sub
3. Looks up (verifier=google, id=sub)
in BFT mapping state
4. If new user → assign pre-generated key
5. Encrypts its sub-share with pubKeyₑ + + N1-->>SDK: ECIES(sub-share₁, pubKeyₑ) + N2-->>SDK: ECIES(sub-share₂, pubKeyₑ) + N3-->>SDK: ECIES(sub-share₃, pubKeyₑ) + N4-->>SDK: ECIES(sub-share₄, pubKeyₑ) + N5-->>SDK: ECIES(sub-share₅, pubKeyₑ) + + Note over SDK: Decrypt sub-shares with privKeyₑ
Reconstruct ShareA via Lagrange interpolation + + SDK->>LS: Read ShareB from localStorage + LS-->>SDK: ShareB + + Note over SDK: Combine ShareA + ShareB
via Lagrange interpolation
→ Private Key σ (in memory only) + + SDK->>Meta: Read encrypted metadata + Meta-->>SDK: Encrypted device list, config + + Note over SDK: Private key σ lives in JS heap.
Never written to disk.
Garbage collected on tab close. +``` + +#### Anti-replay protection + +The commit-reveal scheme (inspired by Bracha's Reliable Broadcast) prevents replay attacks: +1. A token can only be committed once — if a node has already seen a commitment for a given token hash, it rejects the duplicate. +2. OAuth tokens have short TTL (typically 1 hour for Google id_tokens). +3. The ephemeral keypair ensures intercepted encrypted sub-shares are useless without `privKeyₑ` (which never leaves the client). + +#### Key assignment + +The BFT mapping layer maintains a consensus-protected state machine mapping `(verifier, verifier_id)` tuples (e.g., `("google", "user@gmail.com")`) to key indexes. When a new user authenticates, nodes reach BFT consensus to assign a pre-generated key from the key buffer. Once assigned, the mapping is permanent. + +### Key lifecycle in memory + +```mermaid +stateDiagram-v2 + [*] --> NoKey: App starts + NoKey --> Authenticating: User clicks social login + Authenticating --> ShareAReconstructed: OAuth success +
sub-shares received + ShareAReconstructed --> FullKeyInMemory: ShareA + ShareB combined
via Lagrange interpolation + FullKeyInMemory --> WalletActive: xpriv derived via BIP32,
HathorWallet started + WalletActive --> FullKeyInMemory: PIN lock (xpriv encrypted
to localStorage with PIN) + WalletActive --> KeyDestroyed: Tab closed / app quit + KeyDestroyed --> [*]: Key garbage collected + + note right of FullKeyInMemory + Private key σ exists ONLY + in JavaScript heap memory. + Never written to disk. + Never sent over network. + end note + + note right of KeyDestroyed + On next session: + PIN unlock → decrypt xpriv from localStorage + OR re-authenticate → reconstruct from shares + end note +``` + +### Trust model — who must you trust, and with what + +| Entity | What you trust them with | What they CANNOT do | +|--------|--------------------------|---------------------| +| **Web3Auth / Torus Labs** (operates all 5 nodes) | Honest execution of the node software; availability of ShareA sub-shares; not modifying node code to exfiltrate sub-shares | Reconstruct the full private key (they only hold ShareA sub-shares, not ShareB or ShareC) | +| **OAuth provider** (Google, Apple, etc.) | Correctly authenticating users; not issuing fraudulent tokens for your identity | Access any key material (they only provide identity attestation) | +| **User's device** | Not being compromised by malware | — (if compromised, ShareB can be extracted from localStorage) | +| **User's browser / Electron runtime** | Faithfully executing the Web3Auth SDK JavaScript | — (malicious browser extensions could read memory) | +| **Web3Auth metadata server** | Honestly storing/returning metadata; not tampering with threshold configurations | Read encrypted metadata contents (encrypted with user's key) | +| **Web3Auth CDN / npm** | Serving unmodified SDK code (supply chain trust) | — (a compromised SDK could exfiltrate the reconstructed key) | +| **Ethereum mainnet** | Accurately reflecting the node registry smart contract | — | + +**Critical risk: all nodes operated by one entity.** Since Web3Auth operates all 5 nodes, a sufficiently privileged insider could theoretically modify the node software to log sub-shares as they are released. This would give them ShareA. However, they would still need ShareB (device) or ShareC (recovery) to reconstruct the full key. The risk is mitigated by: +- SOC 2 Type II certification +- Deployed node code is auditable (open-source Go codebase) +- The commit-reveal protocol limits the window for exfiltration + +**Could a rogue Web3Auth employee steal funds?** Only if they both (a) exfiltrate ShareA from the node infrastructure AND (b) obtain ShareB from the user's device or ShareC from the user's backup. Getting ShareA alone is insufficient. + +### What happens if Web3Auth disappears + +```mermaid +graph TD + subgraph "Web3Auth Online (normal)" + A1[ShareA from nodes] --> R1[Reconstruct σ] + B1[ShareB from device] --> R1 + end + + subgraph "Web3Auth Offline (company gone)" + A2[ShareA ❌ unavailable] ~~~ X[Cannot get ShareA] + B2[ShareB from device] --> R2[Reconstruct σ ✅] + C2[ShareC recovery backup] --> R2 + end + + subgraph "Device Lost (new device)" + A3[ShareA from nodes] --> R3[Reconstruct σ ✅] + C3[ShareC recovery backup] --> R3 + end + + subgraph "No Recovery Share + Web3Auth Down" + A4[ShareA ❌] ~~~ Y[FUNDS LOST ⚠️] + B4[ShareB only] ~~~ Y + end +``` + +- If the user has **ShareB + ShareC**: funds are safe, Web3Auth is bypassed entirely. +- If the user only has **ShareB** and Web3Auth goes down: **funds are lost**. This is why recovery share setup during onboarding is critical. +- The node software is open-source (Go), so in theory replacement nodes could be stood up — but they would need the key share data from the original nodes' databases. + +### Security audits and certifications + +- **SOC 2 Type II** certification +- **GDPR, CCPA, CPRA** compliance +- Penetration testing reports (available at `trust.web3auth.io`) +- Legal opinion confirming non-custodial status +- DKG Technical Specification published for audit at `github.com/torusresearch/audit` + +## Hathor-specific integration + +### Architecture overview + +Hathor uses secp256k1 keys with BIP44 derivation path `m/44'/280'/0'/0/i`. Web3Auth natively supports secp256k1, so the reconstructed key can be used directly as entropy for Hathor key derivation. + +### SDK choice: Core Kit vs PnP + +We recommend **PnP (Plug and Play) Web SDK** for the initial integration: + +- Faster time-to-market with pre-built auth UI. +- Handles OAuth flows, share management, and device registration out of the box. +- Sufficient for the initial feature; Core Kit can be adopted later for full UI customization. + +### Integration flow + +```mermaid +flowchart LR + subgraph Web3Auth + OAuth[OAuth Provider] --> SDK[Web3Auth PnP SDK] + Nodes[Auth Network
5 nodes] --> SDK + end + + subgraph "Hathor Wallet (client)" + SDK --> |"raw secp256k1
private key"| Derive[BIP32 Derivation
m/44'/280'/0'] + Derive --> |xpriv| HW[HathorWallet
instance] + HW --> PIN[PIN encryption
to localStorage] + end + + subgraph "Hathor Network" + HW --> |addresses,
transactions| FullNode[Full Node] + end +``` + +### Key derivation from Web3Auth private key + +Web3Auth's `CommonPrivateKeyProvider` exposes the raw secp256k1 private key. Since Hathor's `HathorWallet` accepts an `xpriv` parameter, the integration would: + +1. Retrieve the raw private key from Web3Auth: `await web3auth.provider.request({ method: "private_key" })`. +2. Use the private key as the master key for BIP32 derivation, producing an xpriv for path `m/44'/280'/0'`. +3. Pass the xpriv to `HathorWallet` via the existing `xpriv` config option (same path used when unlocking from encrypted `mainKey`). +4. The wallet then derives addresses and signs transactions as usual. + +Alternatively, the Web3Auth key can be used as entropy to derive a BIP39 mnemonic deterministically. This has the advantage of producing standard 24 words that can be exported, but requires careful implementation to ensure deterministic derivation. + +### Changes to existing code + +#### New files + +- `src/utils/web3auth.js` — Web3Auth SDK initialization, login, logout, key retrieval, and share management helpers. + +#### Modified files + +- `src/screens/WalletType.js` — Add "Social Login" option alongside "Software Wallet" and "Hardware Wallet". +- `src/screens/` — New screen `SocialLoginWallet.js` for the Web3Auth flow (initialize SDK, trigger login, handle callbacks). +- `src/sagas/wallet.js` — In `startWallet()`, handle the new `web3auth: true` payload variant. The wallet receives an xpriv directly (no seed words or password needed). The PIN is still required for local encryption of the xpriv in localStorage. +- `src/storage.js` — Add a new flag `IS_WEB3AUTH_KEY` to `storageKeys` to distinguish Web3Auth-created wallets from seed-based wallets. This controls whether to show "Export Seed Phrase" (unavailable for Web3Auth wallets unless explicitly derived) vs "Export Private Key" in settings. +- `src/App.js` — Route for the new social login screen. +- `src/components/Settings.js` — Show Web3Auth-specific options (linked social account, recovery share status, key export). + +#### Interaction with existing features + +| Feature | Impact | +|---|---| +| PIN lock/unlock | Works identically. xpriv is encrypted with PIN in localStorage. | +| Network change | Works identically. The xpriv is network-agnostic; network is set via Connection config. | +| Token management | No impact. Tokens are managed post-wallet-creation. | +| Nano contracts | No impact. | +| Atomic swaps | No impact. | +| Hardware wallet | No interaction. These are separate onboarding paths. | +| Wallet reset | Must also clear Web3Auth device share from localStorage. | +| WalletService facade | Compatible. xpriv can be used with both HathorWallet and HathorWalletServiceWallet. | + +### Corner cases + +**User clears browser data**: The device share is lost. The user must re-authenticate via social login (gets social share) and use the recovery share. After recovery, a new device share is created. + +**Social provider account compromised**: The attacker gets the social share but not the device share. They cannot reconstruct the key without a second share. The user should revoke the compromised social account and re-share using device + recovery shares. + +**Web3Auth Auth Network goes down**: The user can still access funds using device share + recovery share (2-of-3 threshold), bypassing Web3Auth entirely. + +**User wants to migrate to seed-based wallet**: Export the private key from Web3Auth. Use it to derive a BIP39 mnemonic or import the raw xpriv into a standard Hathor wallet. + +**Electron vs browser context**: The Web3Auth PnP SDK supports both browser and Electron environments. In Electron, the OAuth popup is handled via `BrowserWindow`. The device share should be stored in Electron's secure storage (`safeStorage` API) rather than plain localStorage for enhanced security. + +# Drawbacks +[drawbacks]: #drawbacks + +- **Centralized node operation**: All 5 Auth Network nodes are operated by Web3Auth (Torus Labs). This is a single-entity dependency despite the multi-node architecture. A coordinated compromise of node infrastructure could expose ShareA for all users. This is the most significant trust concern. +- **SSS security model**: In the SSS (non-MPC) tier, the full private key is reconstructed in browser memory during every signing operation. This is vulnerable to memory-based attacks (browser extensions, malware, memory dumps). MPC-TSS avoids this but requires Enterprise pricing. +- **Cost**: Free tier supports 1,000 monthly active wallets. Growth tier ($69/month) supports 3,000. Scale tier ($399/month) supports 10,000. MPC-TSS requires custom Enterprise pricing. +- **Third-party dependency**: Web3Auth is a critical dependency. If their Auth Network permanently goes offline, users without a recovery share lose access to funds. +- **Increased complexity**: A third onboarding path increases maintenance burden and testing surface. +- **User confusion**: Users may not understand the security model. "Sign in with Google" feels custodial, which may lead to false assumptions about recovery (e.g., "Google can recover my funds"). +- **Supply chain risk**: The Web3Auth JavaScript SDK runs in the user's browser. A compromised SDK (via CDN or npm) could exfiltrate the reconstructed private key. +- **Key export UX**: Exporting a Web3Auth-derived key to a seed phrase requires extra derivation steps and careful UX to avoid confusion. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +## Why Web3Auth + +- **Non-custodial by design**: Unlike AWS KMS-based solutions (e.g., Magic), Web3Auth never holds the full key. This aligns with Hathor's self-custody ethos. +- **secp256k1 native support**: No key curve translation needed for Hathor's BIP44/secp256k1 architecture. +- **Censorship resistant**: Users with device + recovery shares can bypass Web3Auth entirely. +- **Battle-tested**: 20M+ monthly active users. Powers MetaMask Embedded Wallets (Consensys acquired Torus Labs, creators of Web3Auth). +- **Electron compatible**: Supports desktop environments, not just browser-only. +- **Open-source node software**: The Go node code is publicly auditable. + +## Alternatives considered + +### Magic (magic.link) +- Uses AWS KMS for key management — keys are technically in AWS's HSMs. +- Less truly non-custodial than Web3Auth's threshold approach. +- Simpler integration but weaker security guarantees. +- **Rejected because**: Custodial risk conflicts with Hathor's non-custodial stance. + +### Privy +- Embedded wallet with social login. +- Strong EVM focus; limited non-EVM support. +- **Rejected because**: Poor fit for non-EVM chains like Hathor. + +### Dynamic +- Acquired by Fireblocks (2025). Strong multi-chain support. +- MPC planned but not shipped at time of writing. +- **Rejected because**: Less mature MPC story, primarily EVM-focused. + +### Custom MPC implementation +- Build threshold signing in-house using libraries like `tss-lib`. +- Full control, no third-party dependency. +- **Rejected because**: Extremely high engineering effort, ongoing maintenance of cryptographic infrastructure, and security audit costs. + +## Impact of not doing this + +The wallet continues to require seed phrase management, limiting adoption to crypto-native users comfortable with self-custody mechanics. Mainstream users will prefer custodial alternatives. + +# Prior art +[prior-art]: #prior-art + +- **MetaMask Embedded Wallets**: MetaMask (via Consensys acquiring Torus Labs) uses Web3Auth's MPC architecture for their embedded wallet product. This is the most prominent production deployment of Web3Auth's technology. +- **Phantom Wallet**: Solana's leading wallet explored social recovery mechanisms, though they ultimately kept seed phrases as the primary flow. +- **Argent (Ethereum)**: Pioneered social recovery for smart contract wallets (guardians-based, not threshold keys). Different approach but similar UX goals. +- **Binance Web3 Wallet**: Uses MPC with three key shares (Binance cloud, device, recovery password). Similar architecture to Web3Auth but proprietary. Demonstrates market demand for seedless wallets. +- **Smart contract wallets (ERC-4337)**: Account abstraction enables social recovery at the contract level. Not applicable to Hathor's UTXO model, but validates the UX direction. + +The common lesson from these implementations: users strongly prefer social login over seed phrases, but the security model must be clearly communicated to avoid false expectations about recoverability. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +- **SSS vs MPC-TSS**: Should we start with the free/Growth SSS tier and upgrade to MPC later, or go directly to Enterprise MPC? SSS reconstructs the key in memory; MPC never does. The security difference is significant, but MPC has higher cost and integration complexity. +- **Key-to-seed derivation**: Should we derive a BIP39 mnemonic from the Web3Auth key to enable seed export? If so, what deterministic derivation method? This affects interoperability with other Hathor wallets. +- **Electron secure storage**: How to best secure the device share in Electron? `safeStorage` API encrypts at the OS level, but the integration with Web3Auth's share storage needs investigation. +- **Recovery share UX**: What recovery mechanism should we offer? Options include: downloadable backup file, security questions, secondary device, or email-based recovery. Each has different security/usability tradeoffs. +- **WalletService compatibility**: The WalletService facade requires `acctPathKey` and `authKey`. How to derive these from a Web3Auth key? The current flow generates them from seed words during `initStorage()`. +- **Multi-device sync**: When a user logs in on a second device, how should the device share be provisioned? Web3Auth handles this, but we need to define the UX for Hathor's desktop wallet context. +- **Session management**: How long should a Web3Auth session last before requiring re-authentication? This affects the balance between security and convenience. +- **Recovery share enforcement**: Should onboarding require setting up a recovery share, or allow users to skip it? Skipping means Web3Auth downtime = fund loss. + +# Future possibilities +[future-possibilities]: #future-possibilities + +- **MPC-TSS upgrade**: Move from SSS to MPC-TSS so the private key is never reconstructed in memory. This is the gold standard for threshold wallet security and would differentiate Hathor's wallet from competitors. +- **Passkey support**: Web3Auth supports passkeys (WebAuthn/FIDO2) as an authentication method. This could replace social login entirely, providing phishing-resistant, device-bound authentication. +- **Mobile wallet integration**: The same Web3Auth integration can be extended to a Hathor mobile wallet (React Native SDK available), enabling cross-device wallet access via the same social identity. +- **Pre-generated wallets**: Web3Auth's Scale tier supports pre-generating wallets before users sign up. This could enable airdrop campaigns or onboarding flows where users receive tokens before creating an account. +- **Fiat on-ramp integration**: Web3Auth's Scale tier includes fiat on-ramp partnerships. Combined with social login, this could provide a complete "zero-to-crypto" onboarding flow. +- **Account abstraction**: If Hathor introduces account abstraction in the future, Web3Auth's social login could be combined with smart contract wallets for enhanced recovery and multi-sig capabilities. +- **Institutional/team wallets**: Web3Auth's threshold architecture could be extended to team wallets where multiple parties each hold a share, requiring multi-party approval for transactions. +- **Independent node operation**: If Web3Auth opens up node operation to third parties, the centralization concern is mitigated. We should monitor this and advocate for it. From c7fe40ed978a1e3a10c454c82abf973ba2d04c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Abadesso?= Date: Tue, 14 Apr 2026 21:19:21 -0300 Subject: [PATCH 2/3] rfc: rewrite Web3Auth RFC to be concise and actionable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original draft was 570 lines of open-ended exploration. Rewrite to 277 lines focused on what we actually have to do. Major changes: - Fix architectural contradiction: replaced the "use raw Web3Auth key as BIP32 master entropy and derive a tree" approach with a pointer to the single-key wallet mode in internal-rfcs#46. Fabricating a chain code from the raw key breaks cross-app portability and is a non-standard crypto construction. - Add operational setup section — the missing actionable piece. Covers Web3Auth dashboard registration, pricing tier selection, OAuth provider setup per platform, verifier strategy (recommend custom verifiers), recovery-share enforcement, monitoring, and legal/DPA requirements. These are company-level actions that have to happen before any code runs. - Scope as cross-cutting foundation: link to internal-rfcs#46 (wallet- lib + mobile UI), internal-rfcs#47 (wallet-service support), and hathor-wallet-lib#1062 (library PoC) as the per-layer designs this foundation enables. - Cut content that was exploratory but not actionable: full DKG protocol walkthrough with bivariate polynomials, Lagrange interpolation math, per-node endpoint tables, Electron smart contract registry address, the "what happens if Web3Auth disappears" Mermaid diagram (kept a concise table instead). - Replace "Unresolved questions" with "Open decisions" — each item now names an owner (product / security / ops / finance) and is a choice, not a research question. - Remove outdated desktop-specific file-level changes (/src/screens/ WalletType.js, etc.) — the desktop wallet is now a future possibility, not phase 1 scope. --- projects/wallets/0001-web3auth-integration.md | 643 +++++------------- 1 file changed, 175 insertions(+), 468 deletions(-) diff --git a/projects/wallets/0001-web3auth-integration.md b/projects/wallets/0001-web3auth-integration.md index 53caa10..053e135 100644 --- a/projects/wallets/0001-web3auth-integration.md +++ b/projects/wallets/0001-web3auth-integration.md @@ -1,570 +1,277 @@ - Feature Name: web3auth_social_login -- Start Date: 2026-03-15 -- RFC PR: -- Hathor Issue: -- Author: André Cardoso +- Start Date: 2026-03-15 (updated 2026-04-14) +- RFC PR: HathorNetwork/rfcs#106 +- Hathor Issue: HathorNetwork/internal-issues#516 +- Author: André Abadesso # Summary [summary]: #summary -Integrate Web3Auth into the Hathor desktop wallet to allow users to create and access wallets via social login (Google, Apple, email, etc.) instead of managing 24-word seed phrases. Web3Auth splits the user's private key into multiple shares using a threshold scheme, so no single party (including Web3Auth) ever holds the full key. The user authenticates with a familiar social provider, and the wallet reconstructs the key client-side from the social login share and a device share — providing a non-custodial UX that feels custodial. +Integrate Web3Auth (MetaMask Embedded Wallets) into Hathor wallets so users can onboard via social login (Google, Apple, email) instead of managing a 24-word seed phrase. This RFC is the **foundation document**: what Web3Auth is, how we talk to it, and the operational steps required at a company level to ship the integration. The per-layer implementation designs live in companion RFCs: + +- **Wallet-lib + mobile UI**: [internal-rfcs#46](https://github.com/HathorNetwork/internal-rfcs/pull/46) +- **Wallet-service support**: [internal-rfcs#47](https://github.com/HathorNetwork/internal-rfcs/pull/47) +- **Library PoC**: [hathor-wallet-lib#1062](https://github.com/HathorNetwork/hathor-wallet-lib/pull/1062) # Motivation [motivation]: #motivation -Seed phrases are the single biggest barrier to mainstream adoption of self-custodial wallets. Users lose them, screenshot them, or never write them down. This creates two problems: (1) new users are intimidated by the onboarding flow and abandon it, and (2) existing users lose access to funds when devices are lost or replaced. - -Web3Auth solves this by replacing seed phrase management with social login. The expected outcomes are: +Seed-phrase onboarding is the single biggest drop-off point for non-crypto-native users. Web3Auth replaces it with social login while keeping the wallet non-custodial — the full private key is never held by Web3Auth, Hathor, or any single party. -- **Lower onboarding friction**: Users sign in with Google/Apple instead of writing down 24 words. -- **Reduced fund loss**: Key recovery is tied to the user's social identity, not a piece of paper. -- **Non-custodial guarantee preserved**: Hathor and Web3Auth never have access to the full private key. -- **Existing wallet compatibility**: Users can still import/export seed phrases for power-user workflows and interoperability with other Hathor wallets. +Expected outcomes: +- Sign in with Google / Apple / email in seconds, no seed backup. +- Lower fund-loss rate (key recovery is tied to social identity + an explicit recovery share, not a piece of paper). +- Parallel onboarding path — existing HD-wallet users are unaffected. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -## User experience +## What Web3Auth is -When a user opens the Hathor wallet for the first time, they will see a new option alongside "Software Wallet" and "Hardware Wallet": +Web3Auth (owned by Consensys / MetaMask, formerly Torus Labs) is a key-management service that issues **one secp256k1 private key per authenticated user**. The key is protected by a 2-of-3 Shamir Secret Sharing scheme: -- **Social Login** — Create or access a wallet using Google, Apple, email, or other social providers. +- **ShareA** — "social share", distributed across a 5-node Auth Network operated by Torus Labs. Released after OAuth authentication with the user's social provider. +- **ShareB** — "device share", stored locally on the user's device (Keychain on iOS, Keystore on Android, `safeStorage` on Electron, IndexedDB on web). +- **ShareC** — "recovery share", controlled by the user (downloadable backup file, security questions, or secondary device). -### Creating a wallet with social login +Any two shares reconstruct the private key client-side. The key is never transmitted and never stored whole on any server. If Web3Auth disappears, users with ShareB + ShareC still have their key. -1. User selects "Social Login" on the wallet type screen. -2. A Web3Auth modal opens (or an embedded UI, depending on SDK choice). The user picks a provider (e.g., Google). -3. The user authenticates with the provider in a popup/redirect flow. -4. Web3Auth reconstructs the private key client-side from two shares (social share + device share). -5. The wallet derives the Hathor xpriv from the reconstructed key and starts normally. -6. The user is prompted to set a PIN (same as the current software wallet flow) for local session locking. -7. The wallet is ready — no seed phrase needed. +The SDK exposes the reconstructed key via `provider.request({ method: 'private_key' })` as a raw 32-byte hex string. That is all we get from Web3Auth — **no BIP32 chain code, no HD tree, no xpub**. -### Returning to the wallet +## Key architectural decision: single-key wallet, NOT BIP32-from-raw-key -On subsequent visits, the user unlocks with their PIN (if the device share is present). If the user clears browser data or uses a new device, they re-authenticate via social login to retrieve the social share, and Web3Auth prompts them to set up a new device share. +Because Web3Auth returns a raw private key with no chain code, the natural temptation is to use it as BIP32 master entropy and derive a full HD tree. **We explicitly do not do this.** The decision and its rationale live in [internal-rfcs#46](https://github.com/HathorNetwork/internal-rfcs/pull/46); summarized: -### Recovery +- Fabricating a chain code from the raw key is a non-standard cryptographic construction. +- It breaks cross-app portability — the same Web3Auth login would produce different Hathor addresses depending on each app's chosen chain-code construction, defeating the point of using a portable auth provider. +- It doesn't simplify signing (the only signable key is still the one raw key) and doesn't fix wallet-service compatibility. -If the user loses their device: -1. They authenticate via social login on a new device (retrieves social share from Web3Auth Auth Network). -2. They use their recovery share (set up during onboarding — e.g., a backup file, security question, or secondary device). -3. The key is reconstructed and the wallet is restored. +Instead, the wallet-lib gains a **single-key wallet mode**: one raw private key, one address, signing routed through the existing `setExternalTxSigningMethod` hook. Web3Auth-issued wallets are single-key wallets. -### Exporting to a standard wallet +## Trust model in one table -Advanced users can export their private key or derive seed words from it, allowing migration to any standard Hathor wallet. This is an opt-in power-user feature. +| You trust | With | They cannot | +|---|---|---| +| **Torus Labs** (operates all 5 Auth Network nodes) | Honest node operation; availability of ShareA sub-shares | Reconstruct the full key (they hold only ShareA; ShareB and ShareC live elsewhere) | +| **OAuth provider** (Google/Apple/etc.) | Authenticating the user honestly | Access any key material | +| **User's device** | Not being compromised by malware | — (compromise leaks ShareB) | +| **Web3Auth SDK supply chain** (npm / CDN) | Serving unmodified JS | — (compromised SDK could exfiltrate the reconstructed key at runtime) | -### Impact on existing flows +The single material risk specific to Web3Auth's architecture is that **all 5 nodes are operated by Torus Labs**. A privileged insider could modify node software to log released sub-shares — they'd get ShareA but would still need ShareB or ShareC to reconstruct a key. Web3Auth has SOC 2 Type II and the node software is open source ([`torusresearch/torus-node`](https://github.com/torusresearch/torus-node)); we accept this risk because every alternative has worse properties (see "Alternatives"). -- The existing "Software Wallet" and "Hardware Wallet" paths remain unchanged. -- Social login is a new, parallel onboarding path that produces the same wallet object (`HathorWallet`) internally. -- All downstream features (token management, nano contracts, atomic swaps) work identically regardless of how the wallet was created. +## Recovery scenarios -## Concepts +| Situation | Outcome | +|---|---| +| Normal login on same device | ShareA (from nodes) + ShareB (from device) → key | +| New device (old device lost) | ShareA (from nodes) + ShareC (recovery backup) → key | +| Web3Auth Auth Network down | ShareB (device) + ShareC (recovery) → key | +| Web3Auth down AND no recovery share set up | **Funds are lost.** | -- **Social Share (ShareA)**: A key share managed by the Web3Auth Auth Network. It is itself split across 5 nodes — no single node holds the complete social share. Released only when the user successfully authenticates via OAuth. -- **Device Share (ShareB)**: A key share stored locally on the user's device (browser localStorage or Electron secure storage). -- **Recovery Share (ShareC)**: A backup key share the user controls — stored as a file, derived from a security question, or held on a secondary device. -- **Threshold**: 2-of-3 shares are needed to reconstruct the private key. Any combination of two shares works. +The last row is why enforcing recovery-share setup during onboarding is a hard requirement (see "Open decisions"). # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -## How Web3Auth works — infrastructure deep dive - -### The Auth Network: servers and nodes - -Web3Auth's Auth Network (formerly the Torus Network) is the infrastructure that manages the social login share. It currently consists of **5 nodes on Sapphire Mainnet**: - -| Node | Endpoint | -|------|----------| -| Node 1 | `https://node-1.node.web3auth.io` | -| Node 2 | `https://node-2.node.web3auth.io` | -| Node 3 | `https://node-3.node.web3auth.io` | -| Node 4 | `https://node-4.node.web3auth.io` | -| Node 5 | `https://node-5.node.web3auth.io` | - -Each node exposes several JSON-RPC service paths: -- `/sss/jrpc` — Shamir Secret Sharing operations (key retrieval) -- `/rss` — Resharing/Recovery operations -- `/tss` — Threshold Signature Scheme (DKLS19, for ECDSA/secp256k1) -- `/tss-frost` — FROST TSS (for Ed25519) - -**All 5 nodes are operated by Web3Auth (Torus Labs).** The nodes are geographically distributed (US-East, US-West, Singapore, South America, Europe) but are not operated by independent parties. This is a critical trust assumption discussed in the Drawbacks section. - -The node list is anchored on-chain via a smart contract on Ethereum mainnet (`0xf20336e16B5182637f09821c27BDe29b0AFcfe80`), which acts as a registry. Node membership is governed by epochs, but in practice changes are controlled by the Web3Auth team. - -Beyond the 5 Auth Network nodes, the Web3Auth SDK also connects to: - -| Service | Endpoint | Purpose | -|---------|----------|---------| -| Metadata server | `https://api.web3auth.io/metadata-service` | Key-value store for encrypted metadata (share commitments, device list, threshold config) | -| Session server | `https://session.web3auth.io` | WebSocket-based session management | -| Signer service | `https://api.web3auth.io/signer-service` | Transaction signing coordination | -| Node discovery | `https://api.web3auth.io/fnd-service` | Fetches current node list and endpoints | -| Auth service | `https://api.web3auth.io/authjs-service` | OAuth flow backend | - -The node software is written in Go (open-source at `github.com/torusresearch/torus-node`) and uses **Tendermint BFT** consensus for inter-node agreement and **libp2p** for peer-to-peer DKG (Distributed Key Generation) messaging. - -### How keys are generated — Distributed Key Generation (DKG) - -When a user signs up for the first time, no single machine ever generates or sees the complete private key. Instead, the 5 nodes collectively perform a **Distributed Key Generation (DKG)** protocol based on Asynchronous Verifiable Secret Sharing (AVSS, Cachin et al. 2002): - -```mermaid -sequenceDiagram - participant N1 as Node 1 - participant N2 as Node 2 - participant N3 as Node 3 - participant N4 as Node 4 - participant N5 as Node 5 - - Note over N1,N5: Each node generates a random bivariate polynomial B_i(x,y) - - N1->>N2: B_1(2, y) (horizontal slice) - N1->>N3: B_1(3, y) - N1->>N4: B_1(4, y) - N1->>N5: B_1(5, y) - N2->>N1: B_2(1, y) - N2->>N3: B_2(3, y) - Note over N1,N5: ... (all nodes exchange slices with all other nodes) +## Integration architecture - Note over N1,N5: Each node verifies consistency
using echo-based verification - - Note over N1,N5: Result: each node holds a sub-share
of the user's key.
The complete private key σ = Σ B_i(0,0)
was never computed anywhere. ``` - -The result: the user's private key `σ` is defined as the sum of the constant terms of each node's polynomial, but no single node (or any single machine) ever computes this sum. Each node only knows its own contribution. - -Keys are pre-generated in batches so that assignment to new users is fast (no DKG needed at login time). - -### How the key is split — Shamir Secret Sharing math - -The user's key is protected by a **(2,3) Shamir Secret Sharing** scheme over the finite field `Zq` (where `q` is the order of the secp256k1 curve group): - -**Polynomial construction:** -A degree-1 polynomial is defined: `f(z) = a₁·z + σ` over `Zq`, where `σ = f(0)` is the private key scalar. - -**Three shares are computed at distinct evaluation points:** -- `ShareA = f(z₁)` — the social login share (distributed across the 5 nodes) -- `ShareB = f(z₂)` — stored on the user's device -- `ShareC = f(z₃)` — recovery/backup share controlled by the user - -**Reconstruction via Lagrange interpolation:** -Given any 2 shares, e.g., `f(zᵢ)` and `f(zⱼ)`, reconstruct: - +User → OAuth provider → Web3Auth SDK (client-side) + ↓ + raw secp256k1 private key + ↓ + ┌─ derive public key + Hathor address locally + ↓ + HathorWallet({ privateKey, publicKey, preCalculatedAddresses: [address] }) + ↓ + wallet.setExternalTxSigningMethod(web3AuthSigner) + ↓ + wallet starts; UI shows one address, uses existing tx flow ``` -σ = f(0) = f(zᵢ) · Lⱼ(0) + f(zⱼ) · Lᵢ(0) -``` - -where `Lᵢ`, `Lⱼ` are Lagrange basis polynomials evaluated at 0. -```mermaid -graph TB - subgraph "2-of-3 Threshold Scheme" - KEY["Private Key σ = f(0)"] - SA["ShareA = f(z₁)
Social Login Share
Split across 5 nodes"] - SB["ShareB = f(z₂)
Device Share
User's localStorage"] - SC["ShareC = f(z₃)
Recovery Share
User-controlled backup"] - end +No BIP32 derivation. No seed. No xpub. Everything downstream of the raw key is handled by the single-key wallet mode defined in internal-rfcs#46 and implemented in hathor-wallet-lib#1062. - SA --> |"Any 2 shares"| KEY - SB --> |"reconstruct σ via"| KEY - SC --> |"Lagrange interpolation"| KEY +## SDK choice - subgraph "Normal Login" - NL["ShareA + ShareB → σ"] - end +**Use the Plug-and-Play (PnP) SDK family**, not Core Kit: - subgraph "Device Lost" - DL["ShareA + ShareC → σ"] - end - - subgraph "Web3Auth Down" - WD["ShareB + ShareC → σ"] - end -``` +| | PnP | Core Kit | +|---|---|---| +| Pre-built OAuth UI | yes | no | +| Share management handled for us | yes | we handle it | +| Time to ship | weeks | months | +| UI customization | limited | full | +| MPC-TSS available | yes (Enterprise) | yes (Enterprise) | -### Where each share is physically stored +Per-platform SDKs: +- **Mobile** (phase 1 target): `@web3auth/react-native-sdk` — integration details in internal-rfcs#46. +- **Desktop** (future): `@web3auth/modal` (web build running in Electron). Electron's `safeStorage` API for the device share instead of localStorage. +- **Web** (future): `@web3auth/modal` again, device share in IndexedDB. -#### ShareA — Social Login Share (Web3Auth Auth Network) +We start with **SSS (non-MPC)** pricing tier. MPC-TSS (where the private key is never reconstructed in memory) is Enterprise-only and is a future upgrade; SSS is sufficient for launch. -ShareA is **not stored as a single value on any server**. It is itself distributed across the 5 Auth Network nodes using a 5-of-9 internal threshold. Each node holds a sub-share. When the user authenticates, each node releases its sub-share (encrypted) to the client, which reconstructs ShareA locally. +## Operational setup — what we actually have to do -``` -ShareA is NOT stored whole anywhere. -Node 1 holds: sub-share₁ of ShareA -Node 2 holds: sub-share₂ of ShareA -Node 3 holds: sub-share₃ of ShareA -Node 4 holds: sub-share₄ of ShareA -Node 5 holds: sub-share₅ of ShareA -``` +This is the list of company-level actions required **before any integration code runs**. These are tracked as explicit setup steps, not as implementation work: -Sub-shares are encrypted at rest in each node's database. During retrieval, they are encrypted with the client's ephemeral public key (ECIES/secp256k1) before transmission over the network. +### 1. Create the Web3Auth account and project -#### ShareB — Device Share +- Sign up at [`dashboard.web3auth.io`](https://dashboard.web3auth.io). +- **Account owner**: a single named person or role account at Hathor (billing + admin). Recommend a role account (e.g. `ops@hathor.network`) so access survives team changes. +- Create **two projects**: + - `hathor-wallet-dev` on the Sapphire **Devnet** (free, used by engineering and QA). + - `hathor-wallet-prod` on the Sapphire **Mainnet** (paid tier, used by shipped apps). +- Each project yields a distinct `clientId`, baked into app builds via env vars. +- **Critical**: devnet and mainnet are **separate key universes**. The same Google login produces **different private keys** on devnet vs mainnet. Users onboarded on a staging build cannot recover on prod (and vice versa). Document this in the QA runbook. -Stored in the user's browser `localStorage` or `IndexedDB` (web) or the OS secure keychain (mobile). In Electron, this could be secured with the `safeStorage` API. The share is a raw scalar value stored as an encrypted blob. +### 2. Pick a pricing tier -#### ShareC — Recovery Share +As of writing: -Controlled entirely by the user. Web3Auth does not hold this share. Storage options include: -- A downloadable backup file -- Derived deterministically from a security question/password -- Stored on a separate device -- A paper backup +| Tier | Monthly active wallets | Approx. cost | Includes | +|---|---|---|---| +| Free | 1,000 | — | SSS only | +| Growth | 3,000 | $69/mo | SSS | +| Scale | 10,000 | $399/mo | SSS, fiat on-ramp | +| Enterprise | custom | custom | MPC-TSS, custom SLA | -#### Metadata (not a share) +**Recommendation**: start on **Growth** for launch headroom; upgrade to Scale if uptake exceeds 2k wallets; revisit Enterprise (MPC-TSS) only if security review requires it or we exceed Scale limits. Track MAU to forecast tier transitions. -The metadata server (`api.web3auth.io/metadata-service`) stores non-sensitive information: -- Polynomial commitments (`g^a₀`, `g^a₁` — public values, cannot derive shares) -- Share commitments (`g^ShareA`, `g^ShareB`, `g^ShareC` — public values) -- Device list and device metadata -- Threshold configuration (2-of-3) -- Encrypted nonces linking keys across accounts +### 3. Configure OAuth providers -Metadata is signed by the user's key on write and verified on read. Contents are encrypted with the user's key — Web3Auth can see that data exists for a user but cannot read the encrypted contents without the user's key. +Each social provider has to be (a) configured in the Web3Auth dashboard and (b) registered as an OAuth app with the provider itself. -### The full private key is NEVER sent over the network +| Provider | What we need | Who owns the credentials | +|---|---|---| +| **Google** | Google Cloud project + OAuth 2.0 clients (iOS + Android + web variants) | Hathor ops | +| **Apple** | Apple Developer account + Sign in with Apple service ID + key | Hathor ops (required on iOS per App Store guideline 4.8) | +| **Email-passwordless** | Just enable in dashboard; Web3Auth handles delivery | — | +| **Discord, Twitter, etc.** | Per-provider OAuth app registration | Hathor ops, when enabled | -The full private key `σ` is never transmitted, never stored on any server, and never exists outside the user's device memory. The only things that travel over the network are: -- OAuth tokens (from the social provider to the client and nodes) -- Encrypted sub-shares of ShareA (from each node to the client, encrypted with ephemeral ECIES keys) -- Metadata reads/writes (encrypted, non-sensitive) +**Phase 1 minimum**: Google + Apple + email-passwordless. Anything else is deferred post-launch. -### Authentication flow — step by step +Redirect URIs / allowed bundle IDs must be configured per platform: +- iOS: URL scheme + Apple Team ID + bundle identifier. +- Android: package name + SHA-1 and SHA-256 signing certificate fingerprints (one set per build variant: debug / staging / production). +- Web/desktop: allowed origins and redirect URLs. -Here is exactly what happens when a user clicks "Sign in with Google": +### 4. Verifier strategy -```mermaid -sequenceDiagram - actor User - participant SDK as Web3Auth SDK
(client-side) - participant Google as Google OAuth - participant N1 as Node 1 - participant N2 as Node 2 - participant N3 as Node 3 - participant N4 as Node 4 - participant N5 as Node 5 - participant Meta as Metadata Server - participant LS as localStorage +Web3Auth ties keys to a `(verifier, verifier_id)` tuple. Two options: - User->>SDK: Click "Sign in with Google" - SDK->>Google: OAuth 2.0 / OIDC redirect - User->>Google: Enter credentials - Google-->>SDK: JWT id_token (sub, email, iss, aud, exp) +- **Shared verifiers** (Web3Auth's default `tkey-google`, `tkey-apple`, etc.). Fast to set up. Users who sign into multiple apps that use the same shared verifier get the **same private key** across those apps. This is either a feature (cross-app portability) or a leak (other apps can derive our users' keys) depending on what you're optimizing for. +- **Custom verifiers**. We run our own JWT signing infrastructure; Web3Auth only validates JWTs we sign. Isolated key space, no cross-app leakage. Higher ops cost. - Note over SDK: Generate ephemeral secp256k1 keypair
(pubKeyₑ, privKeyₑ) +**Recommendation**: **custom verifiers for Phase 1**, keyed on Hathor-signed JWTs. The cross-app-portability benefit of shared verifiers is not worth the security posture of "anyone running a Web3Auth app could derive our users' Hathor keys." This adds a one-time backend build (JWT signing service). - Note over SDK: Compute commitment = hash(id_token) +### 5. Recovery-share policy - par Anti-replay commit phase (Bracha's Reliable Broadcast) - SDK->>N1: commitment + pubKeyₑ - SDK->>N2: commitment + pubKeyₑ - SDK->>N3: commitment + pubKeyₑ - SDK->>N4: commitment + pubKeyₑ - SDK->>N5: commitment + pubKeyₑ - end +Open decisions (see below) need resolution here. Options: - Note over N1,N5: Each node checks: is this
commitment novel? Sign if yes. +- **Mandatory**: onboarding blocks until the user sets up a recovery share. +- **Strongly encouraged**: offered during onboarding, dismissible with a clear warning. +- **Optional / later**: set up from Settings after onboarding. - N1-->>SDK: signature₁ on commitment - N2-->>SDK: signature₂ on commitment - N3-->>SDK: signature₃ on commitment +**Recommendation**: **mandatory**. The "Web3Auth down + no recovery share = funds lost" scenario is severe enough that the UX friction of requiring a recovery share is the lesser evil. Product decision, not engineering. - Note over SDK: Threshold of signatures collected.
Reveal id_token to nodes. +### 6. Session and key-lifetime policy - par Token verification + share release - SDK->>N1: id_token (reveal) - SDK->>N2: id_token (reveal) - SDK->>N3: id_token (reveal) - SDK->>N4: id_token (reveal) - SDK->>N5: id_token (reveal) - end +- **Web3Auth session TTL** — accept default (~24h) unless legal requires otherwise. +- **App-level PIN lock** — encrypt the reconstructed private key with a user-chosen PIN; decrypt on unlock. Matches the existing HD-wallet seed encryption model on mobile. +- **Device share refresh** — Web3Auth rotates device shares on a configurable cadence; accept default. - Note over N1,N5: Each node independently:
1. Verifies JWT signature via Google JWKS
2. Checks iss, aud, exp, sub
3. Looks up (verifier=google, id=sub)
in BFT mapping state
4. If new user → assign pre-generated key
5. Encrypts its sub-share with pubKeyₑ +### 7. Monitoring and incident response - N1-->>SDK: ECIES(sub-share₁, pubKeyₑ) - N2-->>SDK: ECIES(sub-share₂, pubKeyₑ) - N3-->>SDK: ECIES(sub-share₃, pubKeyₑ) - N4-->>SDK: ECIES(sub-share₄, pubKeyₑ) - N5-->>SDK: ECIES(sub-share₅, pubKeyₑ) +- Subscribe to Web3Auth's status page; feed alerts into our on-call. +- Instrument our app to log and alert on Web3Auth SDK errors and OAuth failures (without logging PII). +- Document a support playbook: what does mobile support tell a user when the Auth Network is degraded? (Already-onboarded users can still unlock with their PIN; new onboarding is blocked until service restores.) - Note over SDK: Decrypt sub-shares with privKeyₑ
Reconstruct ShareA via Lagrange interpolation +### 8. Legal / compliance - SDK->>LS: Read ShareB from localStorage - LS-->>SDK: ShareB +- Privacy policy updated to disclose Web3Auth as a sub-processor. +- DPA (Data Processing Agreement) with Web3Auth — request during project setup. +- Terms of service updated to disclose the trust model (Torus Labs operates the nodes, recovery-share responsibility, etc.). - Note over SDK: Combine ShareA + ShareB
via Lagrange interpolation
→ Private Key σ (in memory only) +## Existing wallet compatibility - SDK->>Meta: Read encrypted metadata - Meta-->>SDK: Encrypted device list, config +The integration is **additive**. Existing HD wallets (seed-phrase, hardware) are unchanged. The user-type decision happens at onboarding: - Note over SDK: Private key σ lives in JS heap.
Never written to disk.
Garbage collected on tab close. ``` - -#### Anti-replay protection - -The commit-reveal scheme (inspired by Bracha's Reliable Broadcast) prevents replay attacks: -1. A token can only be committed once — if a node has already seen a commitment for a given token hash, it rejects the duplicate. -2. OAuth tokens have short TTL (typically 1 hour for Google id_tokens). -3. The ephemeral keypair ensures intercepted encrypted sub-shares are useless without `privKeyₑ` (which never leaves the client). - -#### Key assignment - -The BFT mapping layer maintains a consensus-protected state machine mapping `(verifier, verifier_id)` tuples (e.g., `("google", "user@gmail.com")`) to key indexes. When a new user authenticates, nodes reach BFT consensus to assign a pre-generated key from the key buffer. Once assigned, the mapping is permanent. - -### Key lifecycle in memory - -```mermaid -stateDiagram-v2 - [*] --> NoKey: App starts - NoKey --> Authenticating: User clicks social login - Authenticating --> ShareAReconstructed: OAuth success +
sub-shares received - ShareAReconstructed --> FullKeyInMemory: ShareA + ShareB combined
via Lagrange interpolation - FullKeyInMemory --> WalletActive: xpriv derived via BIP32,
HathorWallet started - WalletActive --> FullKeyInMemory: PIN lock (xpriv encrypted
to localStorage with PIN) - WalletActive --> KeyDestroyed: Tab closed / app quit - KeyDestroyed --> [*]: Key garbage collected - - note right of FullKeyInMemory - Private key σ exists ONLY - in JavaScript heap memory. - Never written to disk. - Never sent over network. - end note - - note right of KeyDestroyed - On next session: - PIN unlock → decrypt xpriv from localStorage - OR re-authenticate → reconstruct from shares - end note +Onboarding + ├─ "I have a seed phrase" → existing HD flow + ├─ "Create new wallet" → existing HD flow + └─ "Sign in with Google / Apple / email" → Web3Auth flow (this RFC) ``` -### Trust model — who must you trust, and with what - -| Entity | What you trust them with | What they CANNOT do | -|--------|--------------------------|---------------------| -| **Web3Auth / Torus Labs** (operates all 5 nodes) | Honest execution of the node software; availability of ShareA sub-shares; not modifying node code to exfiltrate sub-shares | Reconstruct the full private key (they only hold ShareA sub-shares, not ShareB or ShareC) | -| **OAuth provider** (Google, Apple, etc.) | Correctly authenticating users; not issuing fraudulent tokens for your identity | Access any key material (they only provide identity attestation) | -| **User's device** | Not being compromised by malware | — (if compromised, ShareB can be extracted from localStorage) | -| **User's browser / Electron runtime** | Faithfully executing the Web3Auth SDK JavaScript | — (malicious browser extensions could read memory) | -| **Web3Auth metadata server** | Honestly storing/returning metadata; not tampering with threshold configurations | Read encrypted metadata contents (encrypted with user's key) | -| **Web3Auth CDN / npm** | Serving unmodified SDK code (supply chain trust) | — (a compromised SDK could exfiltrate the reconstructed key) | -| **Ethereum mainnet** | Accurately reflecting the node registry smart contract | — | - -**Critical risk: all nodes operated by one entity.** Since Web3Auth operates all 5 nodes, a sufficiently privileged insider could theoretically modify the node software to log sub-shares as they are released. This would give them ShareA. However, they would still need ShareB (device) or ShareC (recovery) to reconstruct the full key. The risk is mitigated by: -- SOC 2 Type II certification -- Deployed node code is auditable (open-source Go codebase) -- The commit-reveal protocol limits the window for exfiltration - -**Could a rogue Web3Auth employee steal funds?** Only if they both (a) exfiltrate ShareA from the node infrastructure AND (b) obtain ShareB from the user's device or ShareC from the user's backup. Getting ShareA alone is insufficient. - -### What happens if Web3Auth disappears - -```mermaid -graph TD - subgraph "Web3Auth Online (normal)" - A1[ShareA from nodes] --> R1[Reconstruct σ] - B1[ShareB from device] --> R1 - end - - subgraph "Web3Auth Offline (company gone)" - A2[ShareA ❌ unavailable] ~~~ X[Cannot get ShareA] - B2[ShareB from device] --> R2[Reconstruct σ ✅] - C2[ShareC recovery backup] --> R2 - end - - subgraph "Device Lost (new device)" - A3[ShareA from nodes] --> R3[Reconstruct σ ✅] - C3[ShareC recovery backup] --> R3 - end - - subgraph "No Recovery Share + Web3Auth Down" - A4[ShareA ❌] ~~~ Y[FUNDS LOST ⚠️] - B4[ShareB only] ~~~ Y - end -``` - -- If the user has **ShareB + ShareC**: funds are safe, Web3Auth is bypassed entirely. -- If the user only has **ShareB** and Web3Auth goes down: **funds are lost**. This is why recovery share setup during onboarding is critical. -- The node software is open-source (Go), so in theory replacement nodes could be stood up — but they would need the key share data from the original nodes' databases. - -### Security audits and certifications - -- **SOC 2 Type II** certification -- **GDPR, CCPA, CPRA** compliance -- Penetration testing reports (available at `trust.web3auth.io`) -- Legal opinion confirming non-custodial status -- DKG Technical Specification published for audit at `github.com/torusresearch/audit` - -## Hathor-specific integration - -### Architecture overview - -Hathor uses secp256k1 keys with BIP44 derivation path `m/44'/280'/0'/0/i`. Web3Auth natively supports secp256k1, so the reconstructed key can be used directly as entropy for Hathor key derivation. - -### SDK choice: Core Kit vs PnP - -We recommend **PnP (Plug and Play) Web SDK** for the initial integration: - -- Faster time-to-market with pre-built auth UI. -- Handles OAuth flows, share management, and device registration out of the box. -- Sufficient for the initial feature; Core Kit can be adopted later for full UI customization. - -### Integration flow - -```mermaid -flowchart LR - subgraph Web3Auth - OAuth[OAuth Provider] --> SDK[Web3Auth PnP SDK] - Nodes[Auth Network
5 nodes] --> SDK - end - - subgraph "Hathor Wallet (client)" - SDK --> |"raw secp256k1
private key"| Derive[BIP32 Derivation
m/44'/280'/0'] - Derive --> |xpriv| HW[HathorWallet
instance] - HW --> PIN[PIN encryption
to localStorage] - end - - subgraph "Hathor Network" - HW --> |addresses,
transactions| FullNode[Full Node] - end -``` - -### Key derivation from Web3Auth private key - -Web3Auth's `CommonPrivateKeyProvider` exposes the raw secp256k1 private key. Since Hathor's `HathorWallet` accepts an `xpriv` parameter, the integration would: - -1. Retrieve the raw private key from Web3Auth: `await web3auth.provider.request({ method: "private_key" })`. -2. Use the private key as the master key for BIP32 derivation, producing an xpriv for path `m/44'/280'/0'`. -3. Pass the xpriv to `HathorWallet` via the existing `xpriv` config option (same path used when unlocking from encrypted `mainKey`). -4. The wallet then derives addresses and signs transactions as usual. - -Alternatively, the Web3Auth key can be used as entropy to derive a BIP39 mnemonic deterministically. This has the advantage of producing standard 24 words that can be exported, but requires careful implementation to ensure deterministic derivation. - -### Changes to existing code - -#### New files - -- `src/utils/web3auth.js` — Web3Auth SDK initialization, login, logout, key retrieval, and share management helpers. - -#### Modified files - -- `src/screens/WalletType.js` — Add "Social Login" option alongside "Software Wallet" and "Hardware Wallet". -- `src/screens/` — New screen `SocialLoginWallet.js` for the Web3Auth flow (initialize SDK, trigger login, handle callbacks). -- `src/sagas/wallet.js` — In `startWallet()`, handle the new `web3auth: true` payload variant. The wallet receives an xpriv directly (no seed words or password needed). The PIN is still required for local encryption of the xpriv in localStorage. -- `src/storage.js` — Add a new flag `IS_WEB3AUTH_KEY` to `storageKeys` to distinguish Web3Auth-created wallets from seed-based wallets. This controls whether to show "Export Seed Phrase" (unavailable for Web3Auth wallets unless explicitly derived) vs "Export Private Key" in settings. -- `src/App.js` — Route for the new social login screen. -- `src/components/Settings.js` — Show Web3Auth-specific options (linked social account, recovery share status, key export). - -#### Interaction with existing features - -| Feature | Impact | -|---|---| -| PIN lock/unlock | Works identically. xpriv is encrypted with PIN in localStorage. | -| Network change | Works identically. The xpriv is network-agnostic; network is set via Connection config. | -| Token management | No impact. Tokens are managed post-wallet-creation. | -| Nano contracts | No impact. | -| Atomic swaps | No impact. | -| Hardware wallet | No interaction. These are separate onboarding paths. | -| Wallet reset | Must also clear Web3Auth device share from localStorage. | -| WalletService facade | Compatible. xpriv can be used with both HathorWallet and HathorWalletServiceWallet. | - -### Corner cases - -**User clears browser data**: The device share is lost. The user must re-authenticate via social login (gets social share) and use the recovery share. After recovery, a new device share is created. - -**Social provider account compromised**: The attacker gets the social share but not the device share. They cannot reconstruct the key without a second share. The user should revoke the compromised social account and re-share using device + recovery shares. - -**Web3Auth Auth Network goes down**: The user can still access funds using device share + recovery share (2-of-3 threshold), bypassing Web3Auth entirely. - -**User wants to migrate to seed-based wallet**: Export the private key from Web3Auth. Use it to derive a BIP39 mnemonic or import the raw xpriv into a standard Hathor wallet. - -**Electron vs browser context**: The Web3Auth PnP SDK supports both browser and Electron environments. In Electron, the OAuth popup is handled via `BrowserWindow`. The device share should be stored in Electron's secure storage (`safeStorage` API) rather than plain localStorage for enhanced security. +Once started, a Web3Auth wallet and an HD wallet produce identical downstream behavior (send, receive, tokens, nano contracts) because the wallet-lib abstracts over both via the single-key vs HD modes. # Drawbacks [drawbacks]: #drawbacks -- **Centralized node operation**: All 5 Auth Network nodes are operated by Web3Auth (Torus Labs). This is a single-entity dependency despite the multi-node architecture. A coordinated compromise of node infrastructure could expose ShareA for all users. This is the most significant trust concern. -- **SSS security model**: In the SSS (non-MPC) tier, the full private key is reconstructed in browser memory during every signing operation. This is vulnerable to memory-based attacks (browser extensions, malware, memory dumps). MPC-TSS avoids this but requires Enterprise pricing. -- **Cost**: Free tier supports 1,000 monthly active wallets. Growth tier ($69/month) supports 3,000. Scale tier ($399/month) supports 10,000. MPC-TSS requires custom Enterprise pricing. -- **Third-party dependency**: Web3Auth is a critical dependency. If their Auth Network permanently goes offline, users without a recovery share lose access to funds. -- **Increased complexity**: A third onboarding path increases maintenance burden and testing surface. -- **User confusion**: Users may not understand the security model. "Sign in with Google" feels custodial, which may lead to false assumptions about recovery (e.g., "Google can recover my funds"). -- **Supply chain risk**: The Web3Auth JavaScript SDK runs in the user's browser. A compromised SDK (via CDN or npm) could exfiltrate the reconstructed private key. -- **Key export UX**: Exporting a Web3Auth-derived key to a seed phrase requires extra derivation steps and careful UX to avoid confusion. +- **Third-party dependency**: Web3Auth is now on our critical path. Their Auth Network going dark degrades onboarding; only users with recovery shares can move funds on a new device. +- **Centralized node operation**: all 5 nodes are Torus-Labs-operated. Mitigated, not eliminated, by multi-share architecture + open-source node code. +- **SSS tier reconstructs key in memory**: vulnerable to browser extensions or device malware during the signing window. MPC-TSS avoids this but is Enterprise-only. +- **Supply-chain exposure**: the Web3Auth JS SDK runs in our users' app context. A compromised SDK could exfiltrate the reconstructed key at runtime. Mitigate via dependency pinning, Subresource Integrity (where applicable), and periodic SDK audits. +- **User mental model**: "Sign in with Google" feels custodial; users may assume Google can recover their funds. Clear onboarding copy required. +- **Maintenance surface**: one more onboarding path, one more SDK, one more set of OAuth integrations to maintain. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives ## Why Web3Auth -- **Non-custodial by design**: Unlike AWS KMS-based solutions (e.g., Magic), Web3Auth never holds the full key. This aligns with Hathor's self-custody ethos. -- **secp256k1 native support**: No key curve translation needed for Hathor's BIP44/secp256k1 architecture. -- **Censorship resistant**: Users with device + recovery shares can bypass Web3Auth entirely. -- **Battle-tested**: 20M+ monthly active users. Powers MetaMask Embedded Wallets (Consensys acquired Torus Labs, creators of Web3Auth). -- **Electron compatible**: Supports desktop environments, not just browser-only. -- **Open-source node software**: The Go node code is publicly auditable. +- **Non-custodial** by construction (no single party holds the full key). +- **secp256k1 native** — no curve translation for Hathor's key model. +- **Battle-tested**: powers MetaMask Embedded Wallets; 20M+ MAU across the platform. +- **Works offline of Web3Auth**: ShareB + ShareC is sufficient. -## Alternatives considered +## Alternatives rejected -### Magic (magic.link) -- Uses AWS KMS for key management — keys are technically in AWS's HSMs. -- Less truly non-custodial than Web3Auth's threshold approach. -- Simpler integration but weaker security guarantees. -- **Rejected because**: Custodial risk conflicts with Hathor's non-custodial stance. +- **Magic (magic.link)** — uses AWS KMS; effectively custodial. Incompatible with our non-custodial stance. +- **Privy** — strong EVM focus, weak non-EVM support. +- **Dynamic** — primarily EVM, MPC roadmap not yet shipped. +- **Custom MPC (tss-lib)** — extreme engineering and audit cost for a non-differentiating capability. -### Privy -- Embedded wallet with social login. -- Strong EVM focus; limited non-EVM support. -- **Rejected because**: Poor fit for non-EVM chains like Hathor. +## Why single-key mode, not HD-from-raw-key -### Dynamic -- Acquired by Fireblocks (2025). Strong multi-chain support. -- MPC planned but not shipped at time of writing. -- **Rejected because**: Less mature MPC story, primarily EVM-focused. +Covered in internal-rfcs#46's "Rationale and alternatives" section. Summary: fabricating a chain code for BIP32 breaks cross-app portability (a selling point of Web3Auth), is a non-standard crypto construction, and doesn't simplify signing or fix wallet-service compatibility. -### Custom MPC implementation -- Build threshold signing in-house using libraries like `tss-lib`. -- Full control, no third-party dependency. -- **Rejected because**: Extremely high engineering effort, ongoing maintenance of cryptographic infrastructure, and security audit costs. +# Open decisions +[open-decisions]: #open-decisions -## Impact of not doing this +These need answers before Phase 1 ships. None are research questions — they are choices that require a named owner: -The wallet continues to require seed phrase management, limiting adoption to crypto-native users comfortable with self-custody mechanics. Mainstream users will prefer custodial alternatives. +- [ ] **Recovery-share enforcement policy**: mandatory / strongly encouraged / optional? (Product owns this.) +- [ ] **Custom vs shared verifiers**: RFC recommends custom; operational cost of running JWT signing infra. (Security + ops sign-off.) +- [ ] **Pricing tier at launch**: Growth vs Scale vs starting Free and upgrading. (Finance sign-off.) +- [ ] **OAuth provider set at launch**: confirm Google + Apple + email is the Phase 1 minimum, nothing more. (Product.) +- [ ] **Web3Auth account owner at Hathor**: single named human or role account. (Ops.) +- [ ] **MPC-TSS requirement**: security review — is SSS acceptable for launch, or does MPC need to gate release? (Security.) # Prior art [prior-art]: #prior-art -- **MetaMask Embedded Wallets**: MetaMask (via Consensys acquiring Torus Labs) uses Web3Auth's MPC architecture for their embedded wallet product. This is the most prominent production deployment of Web3Auth's technology. -- **Phantom Wallet**: Solana's leading wallet explored social recovery mechanisms, though they ultimately kept seed phrases as the primary flow. -- **Argent (Ethereum)**: Pioneered social recovery for smart contract wallets (guardians-based, not threshold keys). Different approach but similar UX goals. -- **Binance Web3 Wallet**: Uses MPC with three key shares (Binance cloud, device, recovery password). Similar architecture to Web3Auth but proprietary. Demonstrates market demand for seedless wallets. -- **Smart contract wallets (ERC-4337)**: Account abstraction enables social recovery at the contract level. Not applicable to Hathor's UTXO model, but validates the UX direction. +- **MetaMask Embedded Wallets** — MetaMask's production deployment of Web3Auth. The reference integration. +- **Binance Web3 Wallet** — similar 3-share model (cloud / device / recovery password). Proprietary but validates the market. +- **Argent** — social recovery on Ethereum via guardian contracts. Different mechanism, same UX goal. +- **Phantom (Solana)** — explored seedless flows; kept seed phrases as primary. Cautionary tale about UX complexity. + +Lesson across all: users prefer social login, but the security model must be communicated clearly or they develop false expectations about recoverability. -The common lesson from these implementations: users strongly prefer social login over seed phrases, but the security model must be clearly communicated to avoid false expectations about recoverability. +# Related work +[related-work]: #related-work -# Unresolved questions -[unresolved-questions]: #unresolved-questions +This RFC is the foundation for the Web3Auth initiative. The per-layer implementation work is tracked separately: -- **SSS vs MPC-TSS**: Should we start with the free/Growth SSS tier and upgrade to MPC later, or go directly to Enterprise MPC? SSS reconstructs the key in memory; MPC never does. The security difference is significant, but MPC has higher cost and integration complexity. -- **Key-to-seed derivation**: Should we derive a BIP39 mnemonic from the Web3Auth key to enable seed export? If so, what deterministic derivation method? This affects interoperability with other Hathor wallets. -- **Electron secure storage**: How to best secure the device share in Electron? `safeStorage` API encrypts at the OS level, but the integration with Web3Auth's share storage needs investigation. -- **Recovery share UX**: What recovery mechanism should we offer? Options include: downloadable backup file, security questions, secondary device, or email-based recovery. Each has different security/usability tradeoffs. -- **WalletService compatibility**: The WalletService facade requires `acctPathKey` and `authKey`. How to derive these from a Web3Auth key? The current flow generates them from seed words during `initStorage()`. -- **Multi-device sync**: When a user logs in on a second device, how should the device share be provisioned? Web3Auth handles this, but we need to define the UX for Hathor's desktop wallet context. -- **Session management**: How long should a Web3Auth session last before requiring re-authentication? This affects the balance between security and convenience. -- **Recovery share enforcement**: Should onboarding require setting up a recovery share, or allow users to skip it? Skipping means Web3Auth downtime = fund loss. +- **[internal-rfcs#46](https://github.com/HathorNetwork/internal-rfcs/pull/46)** — Wallet-lib single-key mode + mobile onboarding UI. Answers "how does the library accept a raw private key and route signing through the external-signer hook," and "what does the mobile onboarding / lock / settings UI look like." +- **[internal-rfcs#47](https://github.com/HathorNetwork/internal-rfcs/pull/47)** — Wallet-service support for single-key wallets. Answers "how do we identify and authenticate a wallet that has no xpub." Stacked on #46. +- **[hathor-wallet-lib#1062](https://github.com/HathorNetwork/hathor-wallet-lib/pull/1062)** — Library PoC with unit and integration tests proving the single-key mode works end-to-end. # Future possibilities [future-possibilities]: #future-possibilities -- **MPC-TSS upgrade**: Move from SSS to MPC-TSS so the private key is never reconstructed in memory. This is the gold standard for threshold wallet security and would differentiate Hathor's wallet from competitors. -- **Passkey support**: Web3Auth supports passkeys (WebAuthn/FIDO2) as an authentication method. This could replace social login entirely, providing phishing-resistant, device-bound authentication. -- **Mobile wallet integration**: The same Web3Auth integration can be extended to a Hathor mobile wallet (React Native SDK available), enabling cross-device wallet access via the same social identity. -- **Pre-generated wallets**: Web3Auth's Scale tier supports pre-generating wallets before users sign up. This could enable airdrop campaigns or onboarding flows where users receive tokens before creating an account. -- **Fiat on-ramp integration**: Web3Auth's Scale tier includes fiat on-ramp partnerships. Combined with social login, this could provide a complete "zero-to-crypto" onboarding flow. -- **Account abstraction**: If Hathor introduces account abstraction in the future, Web3Auth's social login could be combined with smart contract wallets for enhanced recovery and multi-sig capabilities. -- **Institutional/team wallets**: Web3Auth's threshold architecture could be extended to team wallets where multiple parties each hold a share, requiring multi-party approval for transactions. -- **Independent node operation**: If Web3Auth opens up node operation to third parties, the centralization concern is mitigated. We should monitor this and advocate for it. +- **MPC-TSS upgrade** (Enterprise tier): private key never reconstructed in memory; eliminates the memory-exposure class of attacks. Gate on MAU + security review. +- **Passkey / WebAuthn** as an authentication factor in addition to or instead of social login. Supported by Web3Auth. +- **Desktop wallet integration**: once mobile ships and is validated, the same architecture extends to Electron with `safeStorage` for the device share. +- **Pre-generated wallets** (Scale tier): enables airdrop or marketing flows where users receive tokens before creating an account. +- **Fiat on-ramp** (Scale tier): completes the "zero-to-crypto" path for non-crypto-native users. From dd624a64cb967cd222c2b9f52eb9cf091bb1f254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Abadesso?= Date: Wed, 15 Apr 2026 10:40:04 -0300 Subject: [PATCH 3/3] rfc: add missing URLs and cross-links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Link the inline `internal-rfcs#46` and `hathor-wallet-lib#1062` references in the body text (previously linked only in the top-matter and in the Related work section). - Add URLs to Prior art entries (MetaMask Embedded Wallets, Binance Web3 Wallet, Argent, Phantom) — they were bold labels without hrefs. - Add URLs to Alternatives rejected entries (Magic, Privy, Dynamic, tss-lib) for consistency with the Prior art fix. --- projects/wallets/0001-web3auth-integration.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/projects/wallets/0001-web3auth-integration.md b/projects/wallets/0001-web3auth-integration.md index 053e135..4e31449 100644 --- a/projects/wallets/0001-web3auth-integration.md +++ b/projects/wallets/0001-web3auth-integration.md @@ -89,7 +89,7 @@ User → OAuth provider → Web3Auth SDK (client-side) wallet starts; UI shows one address, uses existing tx flow ``` -No BIP32 derivation. No seed. No xpub. Everything downstream of the raw key is handled by the single-key wallet mode defined in internal-rfcs#46 and implemented in hathor-wallet-lib#1062. +No BIP32 derivation. No seed. No xpub. Everything downstream of the raw key is handled by the single-key wallet mode defined in [internal-rfcs#46](https://github.com/HathorNetwork/internal-rfcs/pull/46) and implemented in [hathor-wallet-lib#1062](https://github.com/HathorNetwork/hathor-wallet-lib/pull/1062). ## SDK choice @@ -104,7 +104,7 @@ No BIP32 derivation. No seed. No xpub. Everything downstream of the raw key is h | MPC-TSS available | yes (Enterprise) | yes (Enterprise) | Per-platform SDKs: -- **Mobile** (phase 1 target): `@web3auth/react-native-sdk` — integration details in internal-rfcs#46. +- **Mobile** (phase 1 target): `@web3auth/react-native-sdk` — integration details in [internal-rfcs#46](https://github.com/HathorNetwork/internal-rfcs/pull/46). - **Desktop** (future): `@web3auth/modal` (web build running in Electron). Electron's `safeStorage` API for the device share instead of localStorage. - **Web** (future): `@web3auth/modal` again, device share in IndexedDB. @@ -227,14 +227,14 @@ Once started, a Web3Auth wallet and an HD wallet produce identical downstream be ## Alternatives rejected -- **Magic (magic.link)** — uses AWS KMS; effectively custodial. Incompatible with our non-custodial stance. -- **Privy** — strong EVM focus, weak non-EVM support. -- **Dynamic** — primarily EVM, MPC roadmap not yet shipped. -- **Custom MPC (tss-lib)** — extreme engineering and audit cost for a non-differentiating capability. +- **[Magic](https://magic.link)** — uses AWS KMS; effectively custodial. Incompatible with our non-custodial stance. +- **[Privy](https://www.privy.io)** — strong EVM focus, weak non-EVM support. +- **[Dynamic](https://www.dynamic.xyz)** — primarily EVM, MPC roadmap not yet shipped. +- **Custom MPC** (using libraries like [tss-lib](https://github.com/bnb-chain/tss-lib)) — extreme engineering and audit cost for a non-differentiating capability. ## Why single-key mode, not HD-from-raw-key -Covered in internal-rfcs#46's "Rationale and alternatives" section. Summary: fabricating a chain code for BIP32 breaks cross-app portability (a selling point of Web3Auth), is a non-standard crypto construction, and doesn't simplify signing or fix wallet-service compatibility. +Covered in [internal-rfcs#46](https://github.com/HathorNetwork/internal-rfcs/pull/46)'s "Rationale and alternatives" section. Summary: fabricating a chain code for BIP32 breaks cross-app portability (a selling point of Web3Auth), is a non-standard crypto construction, and doesn't simplify signing or fix wallet-service compatibility. # Open decisions [open-decisions]: #open-decisions @@ -251,10 +251,10 @@ These need answers before Phase 1 ships. None are research questions — they ar # Prior art [prior-art]: #prior-art -- **MetaMask Embedded Wallets** — MetaMask's production deployment of Web3Auth. The reference integration. -- **Binance Web3 Wallet** — similar 3-share model (cloud / device / recovery password). Proprietary but validates the market. -- **Argent** — social recovery on Ethereum via guardian contracts. Different mechanism, same UX goal. -- **Phantom (Solana)** — explored seedless flows; kept seed phrases as primary. Cautionary tale about UX complexity. +- **[MetaMask Embedded Wallets](https://web3auth.io)** — MetaMask's production deployment of Web3Auth (same technology under the rebrand). The reference integration. +- **[Binance Web3 Wallet](https://www.binance.com/en/web3wallet)** — similar 3-share model (cloud / device / recovery password). Proprietary but validates the market. +- **[Argent](https://www.argent.xyz)** — social recovery on Ethereum via guardian contracts. Different mechanism, same UX goal. +- **[Phantom](https://phantom.app) (Solana)** — explored seedless flows; kept seed phrases as primary. Cautionary tale about UX complexity. Lesson across all: users prefer social login, but the security model must be communicated clearly or they develop false expectations about recoverability.