Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
602eaec
WIP: Add CKD implementation and integrate derivation path in signing …
vietddude Jul 12, 2024
43d0a41
Update .gitignore to exclude node modules and modify CKD example
vietddude Jul 23, 2025
0a143f6
chore: fix lint error
vietddude Jul 23, 2025
351618b
feat: support eddsa ckd
vietddude Oct 28, 2025
72e6bce
CKD struct refactor: rename chain code field to masterChainCode and a…
vietddude Oct 31, 2025
d6b4992
Enable wallet-scoped derivation: add walletID to Derive and wire thro…
vietddude Oct 31, 2025
c2468a0
Add chain_code setup instructions and integrate chain_code into confi…
vietddude Oct 31, 2025
4bc9344
Enhance setup scripts: distribute event initiator public key to node …
vietddude Oct 31, 2025
887ebe2
Update dependencies: replace bnb-chain/tss-lib with fystack/tss-lib a…
vietddude Nov 4, 2025
c10ecc4
Fix reshare event handling: ensure successEvent.PubKey is non-empty b…
vietddude Nov 4, 2025
831eb00
Add chain_code config and integration CKD sign into e2e
vietddude Nov 4, 2025
5d2c55a
Update e2e test matrix to include TestCKDSigning
vietddude Nov 4, 2025
8129477
Remove unused functions
anhthii Nov 26, 2025
4d997bb
Update derivatoin logic
anhthii Dec 2, 2025
5c90a58
Add hd wallet examples for both ecdsa and eddsa
anhthii Dec 2, 2025
d6684ab
Fix lint issue
anhthii Dec 2, 2025
86474eb
Update cI
anhthii Dec 9, 2025
fc853a0
Udpate chain code instruction
anhthii Dec 9, 2025
7abc4ad
Update go version
anhthii Dec 9, 2025
ed0dfc7
Udpate golint
anhthii Dec 9, 2025
69250f8
Update installation instruction
anhthii Dec 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches: ["*"]

env:
GO_VERSION: "1.24"
GO_VERSION: "1.25.5"

jobs:
test:
Expand Down Expand Up @@ -49,13 +49,11 @@ jobs:
go-version: ${{ env.GO_VERSION }}
cache: true

- name: Clean Go build cache
run: go clean -cache -modcache

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v6
with:
version: latest
install-mode: goinstall
args: --timeout=5m

# Security vulnerability scanning
Expand Down Expand Up @@ -101,8 +99,17 @@ jobs:
fi
continue-on-error: true

- name: Clean SARIF file (remove duplicate tags)
if: always()
run: |
# Remove duplicate tags from SARIF rules to fix validation errors
jq '(.runs[]?.tool.driver.rules[]?.properties.tags) |= unique' \
govulncheck-results.sarif > govulncheck-results-clean.sarif
mv govulncheck-results-clean.sarif govulncheck-results.sarif
echo "✅ Cleaned govulncheck SARIF file"

- name: Upload govulncheck results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: govulncheck-results.sarif
Expand All @@ -116,8 +123,17 @@ jobs:
gosec -fmt sarif -out gosec-results.sarif -exclude G304 ./...
continue-on-error: true

- name: Clean gosec SARIF file (remove duplicate tags)
if: always()
run: |
# Remove duplicate tags from SARIF rules to fix validation errors
jq '(.runs[]?.tool.driver.rules[]?.properties.tags) |= unique' \
gosec-results.sarif > gosec-results-clean.sarif
mv gosec-results-clean.sarif gosec-results.sarif
echo "✅ Cleaned gosec SARIF file"

- name: Upload gosec results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: gosec-results.sarif
Expand Down Expand Up @@ -151,7 +167,7 @@ jobs:
run: go mod download

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
Expand All @@ -162,7 +178,7 @@ jobs:
go build -v ./cmd/mpcium-cli

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"

Expand Down Expand Up @@ -237,7 +253,7 @@ jobs:
continue-on-error: true

- name: Upload Grype results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: grype-results.sarif
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
needs: build
strategy:
matrix:
testcase: [TestKeyGeneration, TestSigning, TestResharing]
testcase: [TestKeyGeneration, TestSigning, TestResharing, TestCKDSigning]
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ event_initiator.key
event_initiator.key.age
coverage.out
coverage.html
node*/
peers.json

# E2E test artifacts
Expand All @@ -23,3 +24,4 @@ node2
config.yaml
.vscode
.vagrant
.chain_code
92 changes: 87 additions & 5 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Before starting, ensure you have:

- **Go** 1.23+ installed: [Install Go here](https://go.dev/doc/install)
- **Go** 1.25.0+ installed: [Install Go here](https://go.dev/doc/install)
- **NATS** server running
- **Consul** server running

Expand Down Expand Up @@ -41,21 +41,103 @@ go install ./cmd/mpcium-cli

---

### Set everything up in one go
## Setup Instructions

**For detailed step-by-step instructions, see [SETUP.md](SETUP.md).**

### Quick Reference

#### 1. Generate peers.json

First, generate the peers configuration file:

```bash
mpcium-cli generate-peers -n 3
```

This creates a `peers.json` file with 3 peer nodes (node0, node1, node2). Adjust `-n` for a different number of nodes.

#### 2. Set up Event Initiator

```bash
./setup_initiator.sh
```

This generates the event initiator identity used to authorize MPC operations.

#### 3. Set up Node Identities

```bash
chmod +x ./setup.sh
./setup.sh
./setup_identities.sh
```

Detailed steps can be found in [SETUP.md](SETUP.md).
This script:

- Creates node directories (node0, node1, node2)
- Generates identities for each node
- Distributes identity files across nodes
- Configures chain_code for all nodes

**Note:** This script requires `peers.json` to exist. If you see an error about missing peers.json, run step 1 first.

---

![All node ready](images/all-node-ready.png)

---

## chain_code setup (REQUIRED)

### What is chain_code?

The `chain_code` is a cryptographic parameter used for Hierarchical Deterministic (HD) wallet functionality. It enables mpcium to derive child keys from a parent key, allowing you to generate multiple wallet addresses from a single master key.

**Important Requirements:**

- **All nodes in your MPC cluster MUST use the identical chain_code value**
- Must be a 32-byte value represented as a 64-character hexadecimal string
- Should be generated once and stored securely
- Without a valid chain_code, mpcium nodes will fail to start

### How to generate and configure

Generate one 32-byte hex chain code and set it in all node configurations:

```bash
# Navigate to your mpcium directory
cd /path/to/mpcium

# Generate a random 32-byte chain code and save it
CC=$(openssl rand -hex 32) && echo "$CC" > .chain_code

# Apply to main config
sed -i -E "s|^([[:space:]]*chain_code:).*|\1 \"$CC\"|" config.yaml

# Apply to all node configs
for n in node0 node1 node2; do
sed -i -E "s|^([[:space:]]*chain_code:).*|\1 \"$CC\"|" "$n/config.yaml"
done

# Verify it was set correctly
echo "Chain code configured: $CC"
```

**Example config.yaml entry:**

```yaml
chain_code: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
```

Start nodes normally:

```bash
cd node0 && mpcium start -n node0
```

Repeat for `node1` and `node2`. The value must be exactly 64 hex chars (32 bytes).

---

## Production Deployment (High Security)

1. Use production-grade **NATS** and **Consul** clusters.
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ The application uses a YAML configuration file (`config.yaml`) with the followin
- `event_initiator_pubkey`: Public key of the event initiator
- `max_concurrent_keygen`: Maximum concurrent key generation operations

#### chain_code (REQUIRED)
- **Required** for Hierarchical Deterministic (HD) wallet functionality to derive child keys
- Must be a 32-byte hexadecimal string (64 characters)
- **All nodes MUST use the exact same chain_code value**
- Generate with: `openssl rand -hex 32`
- See [INSTALLATION.md](./INSTALLATION.md#chain_code-setup-required) for detailed setup instructions

## Installation

- **Local Development**: For quick setup and testing, see [INSTALLATION.md](./INSTALLATION.md)
Expand Down
15 changes: 15 additions & 0 deletions cmd/mpcium/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ func runNode(ctx context.Context, c *cli.Command) error {
peerNodeIDs := GetPeerIDs(peers)
peerRegistry := mpc.NewRegistry(nodeID, peerNodeIDs, consulClient.KV(), directMessaging, pubsub, identityStore)

chainCodeHex := viper.GetString("chain_code")
ckd, err := mpc.NewCKDFromHex(chainCodeHex)
if err != nil {
logger.Fatal("Failed to create ckd store", err)
}

mpcNode := mpc.NewNode(
nodeID,
peerNodeIDs,
Expand All @@ -212,6 +218,7 @@ func runNode(ctx context.Context, c *cli.Command) error {
keyinfoStore,
peerRegistry,
identityStore,
ckd,
)
defer mpcNode.Close()

Expand Down Expand Up @@ -443,6 +450,14 @@ func checkRequiredConfigValues(appConfig *config.AppConfig) {
if viper.GetString("event_initiator_pubkey") == "" {
logger.Fatal("Event initiator public key is required", nil)
}

chainCode := strings.TrimSpace(viper.GetString("chain_code"))
if chainCode == "" {
logger.Fatal("chain_code is required in config.yaml", nil)
}
if len(chainCode) != 64 { // 32 bytes hex
logger.Fatal("chain_code must be 32-byte hex (64 chars)", nil)
}
}

func NewConsulClient(addr string) *api.Client {
Expand Down
9 changes: 8 additions & 1 deletion config.prod.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ mpc_threshold: 1
environment: production # Set to production for production environment
backup_enabled: true
event_initiator_pubkey: ""
event_initiator_algorithm: ed25519 # ed25519 or p256
event_initiator_algorithm: ed25519 # ed25519 or p256

# Chain Code for HD Wallet Child Key Derivation (REQUIRED)
# This is used for hierarchical deterministic (HD) wallet functionality to derive child keys.
# All nodes in the MPC cluster MUST use the same chain_code value.
# Generate once with: openssl rand -hex 32
# Store securely and use the same value across all nodes
chain_code: ""
backup_period_seconds: 300 # Seconds
backup_dir: backups
max_concurrent_keygen: 2
Expand Down
7 changes: 7 additions & 0 deletions config.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ environment: development
badger_password: "F))ysJp?E]ol&I;^"
event_initiator_algorithm: "ed25519" # or "ed25519", default: ed25519
event_initiator_pubkey: "event_initiator_pubkey"

# Chain Code for HD Wallet Child Key Derivation (REQUIRED)
# This is used for hierarchical deterministic (HD) wallet functionality to derive child keys.
# All nodes in the MPC cluster MUST use the same chain_code value.
# Generate once with: openssl rand -hex 32
# Example: chain_code: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
chain_code: ""
db_path: "."
backup_enabled: true
backup_period_seconds: 300 # 5 minutes
Expand Down
21 changes: 21 additions & 0 deletions deployments/systemd/setup-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,27 @@ validate_config_credentials() {
else
log_info "✓ event_initiator_pubkey configured"
fi

# Check for required chain_code
if ! grep -q "^chain_code:" "$config_file" || grep -q "^chain_code: *$" "$config_file" || grep -q '^chain_code: ""' "$config_file"; then
log_error "❌ chain_code not configured in config.yaml"
log_error " Generate with: openssl rand -hex 32"
log_error " All nodes MUST use the same chain_code value"
((errors++))
else
# Validate chain_code is 64 hex characters (32 bytes)
local chain_code=$(grep "^chain_code:" "$config_file" | sed 's/chain_code: *//g' | sed 's/"//g' | sed "s/'//g" | sed 's/#.*//g' | sed 's/ *$//g')
if [[ ${#chain_code} -ne 64 ]]; then
log_error "❌ chain_code must be 64 hex characters (32 bytes), got ${#chain_code} characters"
log_error " Generate with: openssl rand -hex 32"
((errors++))
elif ! [[ "$chain_code" =~ ^[0-9a-fA-F]{64}$ ]]; then
log_error "❌ chain_code must be hexadecimal (0-9, a-f), got invalid characters"
((errors++))
else
log_info "✓ chain_code configured (${#chain_code} hex chars)"
fi
fi

# Check for NATS configuration
local nats_url=$(grep -A 10 "^nats:" "$config_file" | grep "url:" | sed 's/.*url: *//g' | sed 's/"//g' | sed "s/'//g" | sed 's/#.*//g' | sed 's/ *$//g')
Expand Down
4 changes: 4 additions & 0 deletions e2e/config.test.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ nats:
max_concurrent_keygen: 1
max_concurrent_signing: 10
session_warm_up_delay_ms: 500

# Chain Code for HD Wallet Child Key Derivation (REQUIRED)
# All nodes MUST use the same chain_code value
chain_code: "{{.CKDChainCode}}"
2 changes: 2 additions & 0 deletions e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,5 @@ require (
replace github.com/fystack/mpcium => ../

replace github.com/agl/ed25519 => github.com/binance-chain/edwards25519 v0.0.0-20200305024217-f36fc4b53d43

replace github.com/bnb-chain/tss-lib/v2 => github.com/fystack/tss-lib/v2 v2.0.1
4 changes: 2 additions & 2 deletions e2e/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/binance-chain/edwards25519 v0.0.0-20200305024217-f36fc4b53d43 h1:Vkf7rtHx8uHx8gDfkQaCdVfc+gfrF9v6sR6xJy7RXNg=
github.com/binance-chain/edwards25519 v0.0.0-20200305024217-f36fc4b53d43/go.mod h1:TnVqVdGEK8b6erOMkcyYGWzCQMw7HEMCOw3BgFYCFWs=
github.com/bnb-chain/tss-lib/v2 v2.0.2 h1:dL2GJFCSYsYQ0bHkGll+hNM2JWsC1rxDmJJJQEmUy9g=
github.com/bnb-chain/tss-lib/v2 v2.0.2/go.mod h1:s4LRfEqj89DhfNb+oraW0dURt5LtOHWXb9Gtkghn0L8=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.4/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
Expand Down Expand Up @@ -118,6 +116,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fystack/tss-lib/v2 v2.0.1 h1:xnC2+DYShoVWco1geliW0km9IvGD7T2FqFOeXM3/7K0=
github.com/fystack/tss-lib/v2 v2.0.1/go.mod h1:s4LRfEqj89DhfNb+oraW0dURt5LtOHWXb9Gtkghn0L8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
Expand Down
Loading
Loading