IdMap-Core is the cryptographic backbone of the IdMap protocol, implementing a secure, production-ready 2-of-2 threshold signature scheme using Ed25519 and the CGGMP21 protocol. It enables two independent parties to jointly generate Solana keypairs and collaboratively sign transactions without ever exposing the complete private key to any single entity β ensuring true non-custodial, trustless transaction security.
Powered by CGGMP21 DKG and Ed25519 Threshold Signatures
This system implements multi-party computation (MPC) for Solana key management, enabling secure wallet creation and transaction signing across distributed nodes without reconstructing private keys.
Key Features:
- β 2-of-2 threshold distributed key generation (DKG)
- β Collaborative Ed25519 signature generation
- β TCP-based MPC protocol transport with length-delimited framing
- β Redis Pub/Sub orchestration for session coordination
- β Production-grade async Rust with Tokio
- β Zero private key exposure (keys never fully reconstructed)
- β Modular workspace architecture (library + server + client)
Here are all the key resources related to IdMap and its components:
- π₯ Demo Video β IdMap in Action: demo video
- π IdMap Gateway Repository: github.com/akash-R-A-J/idmap-gateway
- π IdMap Core β Detailed Documentation: deepwiki.com/akash-R-A-J/idmap-core
- π IdMap Gateway β Detailed Documentation: deepwiki.com/akash-R-A-J/idmap-gateway
- π Live Website: id-map.shop
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β External Systems β
β (Gateway Backend / CLI) β
ββββββββββββββ¬βββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββ
β β
β Trigger keygen/signing β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Redis Pub/Sub Layer β
β Channels: dkg-start, dkg-result, β
β sign-start, sign-result β
ββββββββββββ¬βββββββββββββββββββββββ¬βββββββββββββββββ
β β
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ
β Server (N=0) βββββββΊβ Client (N=1) β
β β TCP β β
β Port 7001 DKG β β Connects to β
β Port 7002 Sign β β Server Ports β
ββββββββββ¬ββββββββ ββββββββββ¬ββββββββ
β β
βββββββββββββ¬ββββββββββββ
βΌ
ββββββββββββββββββββββββββ
β MPC Protocol Engine β
β - CGGMP21 DKG β
β - Ed25519 Signing β
β - Round-based msgs β
ββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββ
β Solana Blockchain β
β (Transaction Submit) β
ββββββββββββββββββββββββββ
Two parties jointly generate a shared Solana keypair without exposing the full private key
sequenceDiagram
participant E as π External System
participant R as π Redis
participant S as π₯οΈ Server (N=0)
participant C as π» Client (N=1)
participant DB as ποΈ Key Store
E->>R: PUBLISH dkg-start {"action":"startdkg", "session":"session-001"}
R->>S: Broadcast to server
R->>C: Broadcast to client
Note over S,C: Server starts listening on TCP port 7001
C->>S: TCP Connect to 127.0.0.1:7001
Note over S,C: Round-based MPC Protocol (CGGMP21)
S<<->>C: Exchange DKG Round 1 messages
S<<->>C: Exchange DKG Round 2 messages
S<<->>C: Exchange DKG Round 3 messages
S->>S: Generate key share (server)
C->>C: Generate key share (client)
S->>DB: Store share for session-001
C->>DB: Store share for session-001
S->>R: PUBLISH dkg-result {"data":"<pubkey>", "server_id":0}
C->>R: PUBLISH dkg-result {"data":"<pubkey>", "server_id":1}
R->>E: Collect results (both parties agree on public key)
π Text-Based Flow Diagram
ββββββββββββββ βββββββββ ββββββββββββ ββββββββββββ ββββββββββββ
β External β β Redis β β Server β β Client β βKey Store β
β System β β β β (N=0) β β (N=1) β β β
βββββββ¬βββββββ βββββ¬ββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ
β β β β β
β PUBLISH β β β β
β dkg-start β β β β
βββββββββββββ>β β β β
β β β β β
β β Broadcast β β β
β βββββββββββ>β β β
β β β β β
β β Broadcast β β β
β βββββββββββββββββββββββββββ>β β
β β β β β
β β β TCP Listen β β
β β β :7001 β β
β β β β β
β β β TCP Connect β
β β β<ββββββββββββββ β
β β β β β
β β β β β
β β ββββββ΄βββββββββββββββ΄βββββ β
β β β MPC Protocol Rounds β β
β β β (CGGMP21 DKG) β β
β β ββββββ¬βββββββββββββββ¬βββββ β
β β β β β
β β β Generate β β
β β β key share β β
β β β β β
β β β β Generate β
β β β β key share β
β β β β β
β β β Store share β β
β β ββββββββββββββββββββββββββββββ>β
β β β β β
β β β β Store share β
β β β βββββββββββββββ>β
β β β β β
β β PUBLISH β β β
β β dkg-result β β
β β<βββββββββββ β β
β β β β β
β β PUBLISH β β
β β dkg-result β β
β β<ββββββββββββββββββββββββββ β
β β β β β
β Results β β β β
β<βββββββββββββ β β β
β β β β β
Two parties collaboratively sign a Solana transaction using their key shares
sequenceDiagram
participant E as π External System
participant R as π Redis
participant S as π₯οΈ Server (N=0)
participant C as π» Client (N=1)
participant DB as ποΈ Key Store
participant SOL as π Solana
E->>E: Create Solana transaction
E->>E: Serialize message bytes
E->>R: PUBLISH sign-start {"action":"sign", "session":"session-001", "message":"<base64>"}
R->>S: Broadcast to server
R->>C: Broadcast to client
S->>DB: Fetch key share for session-001
C->>DB: Fetch key share for session-001
DB->>S: Return server key share
DB->>C: Return client key share
Note over S,C: Server starts listening on TCP port 7002
C->>S: TCP Connect to 127.0.0.1:7002
Note over S,C: Threshold Signing Protocol
S<<->>C: Exchange signing Round 1 messages
S<<->>C: Exchange signing Round 2 messages
S->>S: Generate partial signature (r, z)
C->>C: Generate partial signature (r, z)
S->>R: PUBLISH sign-result {"data":"<signature>", "server_id":0}
C->>R: PUBLISH sign-result {"data":"<signature>", "server_id":1}
R->>E: Return aggregated signature
E->>SOL: Submit signed transaction
SOL->>E: Transaction confirmation
π Text-Based Flow Diagram
ββββββββββββββ βββββββββ ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββ
β External β β Redis β β Server β β Client β βKey Store β β Solana β
β System β β β β (N=0) β β (N=1) β β β β β
βββββββ¬βββββββ βββββ¬ββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ βββββ¬βββββ
β β β β β β
β Create TX β β β β β
β Serialize β β β β β
β β β β β β
β PUBLISH β β β β β
β sign-start β β β β β
βββββββββββββ>β β β β β
β β β β β β
β β Broadcast β β β β
β βββββββββββ>β β β β
β β β β β β
β β Broadcast β β β β
β βββββββββββββββββββββββββββ>β β β
β β β β β β
β β β Fetch share β β β
β β ββββββββββββββββββββββββββββββ> β
β β β β β β
β β β β Fetch share β β
β β β βββββββββββββββ> β
β β β β β β
β β β Key share β β β
β β β<βββββββββββββββββββββββββββββ β
β β β β β β
β β β β Key share β β
β β β β<βββββββββββββ β
β β β β β β
β β β TCP Listen β β β
β β β :7002 β β β
β β β β β β
β β β TCP Connect β β
β β β<ββββββββββββββ β β
β β β β β β
β β ββββββ΄βββββββββββββββ΄βββββ β β
β β β Threshold Signing β β β
β β β Protocol Rounds β β β
β β ββββββ¬βββββββββββββββ¬βββββ β β
β β β β β β
β β β Generate β β β
β β β partial sig β β β
β β β β β β
β β β β Generate β β
β β β β partial sig β β
β β β β β β
β β PUBLISH β β β β
β β sign-result β β β
β β<βββββββββββ β β β
β β β β β β
β β PUBLISH β β β
β β sign-result β β β
β β<ββββββββββββββββββββββββββ β β
β β β β β β
β Aggregated β β β β β
β signature β β β β β
β<βββββββββββββ β β β β
β β β β β β
β Submit signed transaction β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ>β
β β β β β β
β Transaction confirmation β β
β<βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β β β β
|
|
Make sure you have the following installed:
| Tool | Version | Purpose |
|---|---|---|
| Rust | 1.70+ | Compile the project (edition 2024) |
| Redis | v6+ | Pub/Sub coordination |
| Solana CLI | (Optional) | For devnet testing |
Click to expand/collapse
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/envgit clone https://github.com/akash-R-A-J/idmap-core.git
cd idmap-core# Development build
cargo build
# Release build (optimized)
cargo build --releaseβ
Build artifacts will be in target/debug/ or target/release/
Click to expand/collapse
Create server/.env file:
# Node Identity
NODE_ID=0
N=2
# Redis Connection
REDIS_URL=redis://127.0.0.1:6379
# TCP Bind Addresses
DKG_SERVER_ADDR=0.0.0.0:7001
SIGN_SERVER_ADDR=0.0.0.0:7002
# Session Management
DEFAULT_SESSION_ID=session-001Create client/.env file:
# Node Identity
NODE_ID=1
N=2
# Redis Connection
REDIS_URL=redis://127.0.0.1:6379
# Server Connection
DKG_SERVER_ADDR=127.0.0.1:7001
SIGN_SERVER_ADDR=127.0.0.1:7002
# Session Management
DEFAULT_SESSION_ID=session-001
β οΈ Important: Both server and client must use the sameDEFAULT_SESSION_IDfor protocols to succeed.
Click to expand/collapse
redis-servercargo run -p server
# With debug logging
RUST_LOG=debug cargo run -p servercargo run -p client
# With debug logging
RUST_LOG=debug cargo run -p clientredis-cli PUBLISH "dkg-start" '{"action":"startdkg","session":"session-001","id":"test-keygen-1"}'# Subscribe to results channel
redis-cli SUBSCRIBE "dkg-result"β Both parties will publish the same Solana public key (base58 encoded)
# First, create a base64-encoded message (example: "Hello Solana")
MESSAGE=$(echo "Hello Solana" | base64)
redis-cli PUBLISH "sign-start" "{\"action\":\"sign\",\"session\":\"session-001\",\"message\":\"$MESSAGE\",\"id\":\"test-sign-1\"}"redis-cli SUBSCRIBE "sign-result"
|
|
|||||||||||||||||||||||||||||||||
|
|
Currently, both server and client use in-memory storage for key shares:
type ShareStore = Arc<RwLock<HashMap<(u64, String), Valid<DirtyKeyShare<Ed25519>>>>>;Key format: (node_id, session_id) β Key Share
| Node | Session ID | Key Share |
|---|---|---|
| 0 | session-001 |
Server's share for session-001 |
| 1 | session-001 |
Client's share for session-001 |
Note: Shares are lost on restart. For production, integrate persistent storage (PostgreSQL via sqlx).
|
Threshold Cryptography
Network Security
|
Operational Security
Protocol Guarantees
|
Channel: dkg-start
Payload:
{
"action": "startdkg",
"session": "session-001",
"id": "unique-request-id"
}Description: Triggers distributed key generation for the specified session.
Channel: dkg-result
Payload:
{
"id": "unique-request-id",
"result_type": "dkg-result",
"data": "9vTq7K8yJ3xL5mN2pQ4rS6tU8vW0xY1zA3bC5dE7fG9hJ",
"server_id": 0
}Description: Published by both parties with the base58-encoded Solana public key.
Channel: sign-start
Payload:
{
"action": "sign",
"session": "session-001",
"message": "SGVsbG8gU29sYW5h",
"id": "unique-request-id"
}Fields:
message: Base64-encoded serialized Solana transaction bytes
Description: Triggers threshold signing for the specified session.
Channel: sign-result
Payload:
{
"id": "unique-request-id",
"result_type": "sign-result",
"data": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJGz...",
"server_id": 0
}Fields:
data: Complete Ed25519 signature (64 bytes, base58 encoded)
Description: Published by both parties with the final signature.
Channel: sign-result or dkg-result
Payload:
{
"id": "unique-request-id",
"result_type": "sign-error",
"error": "No share found for node 0 session session-001",
"server_id": 0
}Common Errors:
"No share found..."β DKG not completed for session"Signing phase timed out"β Protocol exceeded 15s timeout"TCP accept error"β Network connectivity issue
# Trace-level logging (very verbose)
RUST_LOG=trace cargo run -p server
# Module-specific logging
RUST_LOG=dkg_tcp::keygen=debug,dkg_tcp::sign=debug cargo run -p client
# Filter out noisy crates
RUST_LOG=debug,tokio=info,givre=info cargo run -p server| Problem | Diagnostic | Solution |
|---|---|---|
| Connection refused | Client can't reach server | Ensure server is running before client |
| DKG timeout | No DKG result after 30s | Check Redis connectivity and NODE_ID configs |
| Signature verification fails | Invalid signature on Solana | Ensure both parties use same session ID |
| Key share not found | Signing before DKG completes | Wait for DKG result before triggering signing |
| Redis connection error | Can't connect to Redis | Verify Redis is running: redis-cli PING |
# Terminal 1: Monitor Redis traffic
redis-cli MONITOR
# Terminal 2: Subscribe to results
redis-cli PSUBSCRIBE "*-result"
# Terminal 3: Run server
RUST_LOG=debug cargo run -p server
# Terminal 4: Run client
RUST_LOG=debug cargo run -p client
# Terminal 5: Trigger protocols
redis-cli PUBLISH "dkg-start" '{"action":"startdkg","session":"test-123","id":"1"}'
# Wait for DKG to complete, then:
MESSAGE=$(echo -n "test message" | base64)
redis-cli PUBLISH "sign-start" "{\"action\":\"sign\",\"session\":\"test-123\",\"message\":\"$MESSAGE\",\"id\":\"2\"}"This system is designed to work seamlessly with the idmap-gateway backend:
| Gateway Component | Core Component | Integration Method |
|---|---|---|
/register-verify endpoint |
DKG protocol | Publishes to dkg-start channel |
/send-verify endpoint |
Signing protocol | Publishes to sign-start channel |
| Session management | Session IDs | Gateway generates UUIDs for sessions |
| Result handling | Redis subscribers | Gateway listens to *-result channels |
Gateway .env:
BACKEND_ID=0
TOTAL_NODES=2
REDIS_ACTION=signCore server .env:
NODE_ID=0
N=2Note:
BACKEND_ID(gateway) maps toNODE_ID(core). Ensure consistency across systems.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β (idmap-gateway + Frontend) β
ββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββ
β Redis Pub/Sub Bus β
β (Session Router) β
βββββββ¬ββββββββββββββ¬βββββ
β β
βΌ βΌ
ββββββββββββββββ ββββββββββββββββ
β Server β β Client β
β (N=0) β β (N=1) β
β β β β
β Listens: β β Connects: β
β - :7001 DKG β β - :7001 DKG β
β - :7002 Signβ β - :7002 Signβ
ββββββββ¬ββββββββ βββββββββ¬βββββββ
β β
ββββββββββ¬ββββββββββ
βΌ
βββββββββββββββββββ
β MPC Protocols β
β (TCP Layer) β
βββββββββββββββββββ
Paper: Canetti et al. 2021 - UC Non-Interactive, Proactive, Threshold ECDSA
Properties:
- Threshold: t-of-n (currently 2-of-2)
- Rounds: 3 rounds of interaction
- Security: UC-secure against malicious adversaries
- Key Refresh: Supports proactive secret sharing
Implementation: Via givre crate (Rust MPC framework)
Algorithm: EdDSA with Curve25519
Signature Format:
- r: 32 bytes (curve point)
- z: 32 bytes (scalar)
- Total: 64 bytes (Solana-compatible)
Protocol:
- Each party generates partial signature using their key share
- Signatures are combined without revealing key shares
- Result is a valid Ed25519 signature verifiable with public key
- Rust 1.70+ installed
- Redis running on port 6379
- Server
.envconfigured with NODE_ID=0 - Client
.envconfigured with NODE_ID=1 - Server running and listening on ports 7001, 7002
- Client running and connected to Redis
- Test DKG:
redis-cli PUBLISH "dkg-start" '{"action":"startdkg","session":"test","id":"1"}' - Verify both parties publish same public key
- Test signing: Publish to
sign-startwith base64 message
Ready for production? Integrate with idmap-gateway and deploy to secure infrastructure!
- N-of-M Threshold Support: Extend beyond 2-of-2 to support flexible threshold configurations (e.g., 2-of-3, 3-of-5)
- Persistent Key Storage: Integrate PostgreSQL via sqlx for durable key share storage and recovery
- TLS Transport Layer: Add mutual TLS authentication for encrypted TCP communication between nodes
- SGX Enclave Integration: Secure key shares within Intel SGX trusted execution environments
- WASM Client Support: Enable browser-based DKG participation with IndexedDB storage
- Key Refresh Protocol: Implement proactive secret sharing to rotate key shares without changing public key
- Metrics & Monitoring: Add Prometheus metrics for protocol performance and failure tracking
- High Availability: Support multiple server replicas with leader election via Redis
This project is part of an open-source initiative for secure, decentralized Web3 key management.
Contributions are welcome! Please open issues or submit pull requests.
Built with β€οΈ for secure, decentralized Solana transactions