---
title: "Bảo mật ví MPC"
description: "Cách Fystack triển khai bảo mật ví bằng Tính toán đa bên (MPC) với chữ ký ngưỡng, tạo khóa phân tán và các giao thức ký đa bên an toàn."
url: https://docs.fystack.io/vi/security/mpc-security
last_updated: 2026-11-13
---

> ## Documentation index
> Fetch the complete documentation index at: https://docs.fystack.io/llms.txt
> Use it to discover all available pages before exploring further.

# Bảo mật ví MPC

Fystack sử dụng **Tính toán đa bên (MPC)** để loại bỏ các điểm lỗi đơn lẻ trong quản lý khóa riêng tư. Không một bên nào nắm giữ khóa riêng tư hoàn chỉnh. Thay vào đó, các phần khóa được phân tán trên nhiều node, và chữ ký được tính toán cộng tác bằng mật mã ngưỡng.

Tài liệu này trình bày cách triển khai MPC của Fystack bảo vệ khóa ví thông qua niềm tin phân tán, giao tiếp an toàn và tính toán có thể xác minh.

_Diagram: Kiến trúc bảo mật ví MPC của Fystack_

### Trách nhiệm của node

Mỗi node:

- Chỉ lưu trữ cục bộ **phần khóa đã mã hóa của chính nó**.
- Tham gia ký theo ngưỡng bằng **xác minh Ed25519** và giao tiếp **P2P được bảo vệ bằng ECDH**.
- Không thể tái tạo hoặc xuất toàn bộ khóa, kể cả khi bị xâm phạm.

| Thuộc tính | Mô tả |
| --- | --- |
| Tính bảo mật | Không node hay người vận hành nào có thể truy cập toàn bộ khóa riêng tư. |
| Tính toàn vẹn | Mọi thông điệp giữa các node đều được xác thực bằng chữ ký Ed25519 hoặc Cloud KMS. |
| Khả năng chịu lỗi | Hỗ trợ n node với ngưỡng t, chịu được tối đa (t-1) node gặp sự cố. |
| Mã hóa khi lưu trữ | Các phần khóa được lưu cục bộ với mã hóa AES. |
| Mã hóa khi truyền tải | Được thực thi qua NATS TLS cùng một lớp ECDH cho các kênh P2P. |

---

## 1. Tổng quan

Tính toán đa bên cho phép nhiều bên cùng thực hiện các phép toán mật mã mà không bên nào có quyền truy cập vào khóa riêng tư hoàn chỉnh. Fystack triển khai các lược đồ chữ ký ngưỡng, trong đó cần một số lượng bên tối thiểu (ngưỡng) hợp tác để tạo ra một chữ ký hợp lệ.

| Thành phần | Mô tả |
| --- | --- |
| Node MPC | Tối thiểu 3 node tạo thành một cụm. |
| Ngưỡng (t) | Ví vẫn an toàn ngay cả khi có tối đa (t-1) node bị xâm phạm. |
| Phần khóa | Khóa riêng tư được chia về mặt toán học thành nhiều phần. |
| Mã hóa phần khóa | Mỗi phần khóa được mã hóa bằng AES (mã hóa mặc định của BadgerDB). |
| Bảo mật truyền thông điệp | Bảo vệ hai lớp: NATS TLS cùng trao đổi khóa ECDH để mã hóa P2P. |
| Xác thực thông điệp | Apex giao tiếp với cụm MPC bằng các thông điệp có chữ ký (Ed25519 hoặc Cloud KMS). |

### Lợi ích chính

- **Không có điểm xâm phạm đơn lẻ:** Việc một node bị xâm phạm không làm lộ khóa riêng tư
- **Niềm tin phân tán:** Nhiều bên độc lập phải hợp tác
- **Trong suốt với blockchain:** Chữ ký đầu ra là chữ ký ECDSA/EdDSA tiêu chuẩn
- **Ngưỡng linh hoạt:** Có thể điều chỉnh yêu cầu ký dựa trên giá trị giao dịch
- **Nhật ký kiểm toán:** Mọi phiên ký đều được ghi lại và có thể truy vết

---

## 2. Tạo khóa phân tán (DKG)

Fystack sử dụng **Tạo khóa phân tán** để tạo khóa ví mà không bên nào từng nắm giữ khóa riêng tư hoàn chỉnh.

### Quy trình DKG

**Giai đoạn 1: Cam kết**

- Mỗi bên tạo một đa thức ngẫu nhiên bậc t-1 (trong đó t là ngưỡng)
- Các bên phát quảng bá cam kết cho đa thức của mình
- Các cam kết được xác minh bằng Feldman VSS (Verifiable Secret Sharing)

**Giai đoạn 2: Phân phối phần khóa**

- Mỗi bên tính giá trị đa thức của mình tại các điểm cụ thể
- Các phần được gửi an toàn đến các bên tương ứng qua kênh mã hóa
- Mỗi bên nhận một phần từ mỗi bên còn lại

**Giai đoạn 3: Xác minh**

- Các bên xác minh các phần nhận được so với các cam kết đã quảng bá
- Các phần không hợp lệ được xác định và khiếu nại được ghi nhận
- Giao thức sẽ hủy nếu phát hiện quá nhiều phần không hợp lệ

**Giai đoạn 4: Xây dựng khóa**

- Mỗi bên kết hợp các phần hợp lệ để tạo thành phần khóa của mình
- Khóa công khai được tính từ các cam kết
- Không bên nào biết khóa riêng tư hoàn chỉnh

**Cấu hình DKG**

```yaml
mpc_threshold: 2   # Number of MPC nodes required to sign
```

`mpc_threshold` biểu thị ngưỡng `t` trong lược đồ n-of-t. Với `n` node MPC đang hoạt động, hệ thống bắt buộc `2 ≤ t ≤ n`, chịu được tối đa `(t - 1)` node lỗi hoặc ngoại tuyến mà vẫn tạo được chữ ký. Ví dụ, `n = 3` với `mpc_threshold: 2` tạo thành một cụm 2-of-3: bất kỳ hai node đã xác thực nào cũng có thể ký, nhưng việc xâm phạm một node duy nhất không đủ để khôi phục khóa riêng tư.

Với các giao thức MPC bền vững kiểu GG18/GG20, chúng tôi còn khuyến nghị thêm `t > n / 2`, đảm bảo khả năng chịu lỗi Byzantine: ngay cả khi `f = n - t` node độc hại, ngoại tuyến hoặc thông đồng, các node trung thực vẫn chiếm đa số và có thể ngăn chặn chữ ký giả mạo hoặc việc tái tạo khóa riêng tư.

### Thuộc tính bảo mật

- **Tính bền vững:** Chịu được tối đa n-t bên độc hại
- **Tính có thể xác minh:** Mọi bên đều có thể xác minh tính đúng đắn của các phần khóa
- **Tính riêng tư:** Không có thông tin nào về khóa riêng tư bị rò rỉ
- **Không tương tác:** Sau khi thiết lập, không cần chạy DKG thêm

---

## 3. Ký theo ngưỡng

Ký theo ngưỡng cho phép một tập con các bên (đáp ứng ngưỡng) cùng tạo ra chữ ký hợp lệ mà không cần tái tạo khóa riêng tư.

### Giao thức ký (ECDSA)

**Vòng 1: Giai đoạn cam kết**

**Tạo cam kết**

```text
// Each signer generates commitment
const k_i = randomScalar()
const gamma_i = randomScalar()
const commitment_i = {
  K_i: k_i * G,           // Ephemeral public key
  Gamma_i: gamma_i * G,   // Blinding factor
}
broadcastCommitment(commitment_i)
```

**Vòng 2: Tạo chữ ký thành phần**

**Chữ ký thành phần**

```text
// After receiving all commitments
const R = combineCommitments(allCommitments)
const r = R.x  // x-coordinate of combined point

// Each party computes partial signature
const s_i = k_i + r * keyShare_i * hash(message)
broadcastPartialSignature(s_i)
```

**Vòng 3: Tổng hợp chữ ký**

**Kết hợp chữ ký**

```text
// Combine partial signatures
const s = lagrangeInterpolation(partialSignatures)
const signature = { r, s }

// Verify signature
const valid = ecdsaVerify(signature, publicKey, message)
```

### Quy trình ký

| Bước | Hành động | Kiểm tra bảo mật |
| --- | --- | --- |
| 1. Khởi tạo phiên | Tạo phiên ký với chi tiết giao dịch | Xác minh tính duy nhất của session ID |
| 2. Chọn các bên | Chọn số bên tham gia bằng ngưỡng | Xác minh các bên đang trực tuyến và đã được xác thực |
| 3. Vòng cam kết | Trao đổi cam kết cho các khóa tạm thời | Kiểm tra định dạng và độ mới của cam kết |
| 4. Chữ ký thành phần | Mỗi bên tính toán và chia sẻ chữ ký thành phần | Xác minh tính hợp lệ của chữ ký thành phần |
| 5. Tổng hợp | Kết hợp các chữ ký thành phần thành chữ ký cuối cùng | Xác minh chữ ký cuối cùng bằng khóa công khai |
| 6. Phát sóng | Gửi giao dịch đã ký lên blockchain | Xác nhận giao dịch được chấp nhận |

---

## 4. Bảo mật mạng

### Truyền tải NATS (TLS)

Các node MPC trao đổi dữ liệu qua bus NATS dùng chung được khai báo trong `config.yaml`. Các bản triển khai production yêu cầu endpoint TLS cùng chứng chỉ client được ghim:

**Cấu hình NATS TLS**

```yaml
nats:
  url: tls://nats.example.com:4222
  username: ""
  password: ""
  tls:
    client_cert: "/etc/mpcium/certs/client-cert.pem"
    client_key: "/etc/mpcium/certs/client-key.pem"
    ca_cert: "/etc/mpcium/certs/rootCA.pem"
```

Script `deployments/systemd/setup-config.sh` sẽ từ chối chạy trên production nếu thiếu URL `tls://` và các đường dẫn `nats.tls.*` ở trên, đảm bảo mọi node giao tiếp với NATS qua một đường hầm TLS đã xác thực.

### Bus thông điệp có chữ ký

Trước khi một payload TSS được phát đi, node ký nó bằng định danh Ed25519 của mình (xem `pkg/identity/fileStore`):

**Ký thông điệp TSS**

```go
func (s *fileStore) SignMessage(msg *types.TssMessage) ([]byte, error) {
	msgBytes, err := msg.MarshalForSigning()
	if err != nil {
		return nil, fmt.Errorf("failed to marshal message for signing: %w", err)
	}
	signature := ed25519.Sign(s.privateKey, msgBytes)
	return signature, nil
}
```

Mọi node đều xác minh chữ ký trước khi chấp nhận thông điệp, ngăn chặn peer giả mạo hoặc dữ liệu bị phát lại:

**Xác minh thông điệp TSS**

```go
func (s *fileStore) VerifyMessage(msg *types.TssMessage) error {
	if msg.Signature == nil {
		return fmt.Errorf("message has no signature")
	}
	publicKey, err := s.GetPublicKey(partyIDToNodeID(msg.From))
	if err != nil {
		return fmt.Errorf("failed to get sender's public key: %w", err)
	}
	msgBytes, err := msg.MarshalForSigning()
	if err != nil {
		return fmt.Errorf("failed to marshal message for verification: %w", err)
	}
	if !ed25519.Verify(publicKey, msgBytes, msg.Signature) {
		return fmt.Errorf("invalid signature")
	}
	return nil
}
```

### Mã hóa điểm-điểm

Các node chạy trao đổi ECDH qua các topic NATS chuyên dụng (`pkg/mpc/key_exchange_session.go`) để dẫn xuất khóa đối xứng cho từng peer. Các khóa này được dùng cho mã hóa AES-GCM với mọi payload:

**Mã hóa payload TSS**

```go
func (s *fileStore) EncryptMessage(plaintext []byte, peerID string) ([]byte, error) {
	key, err := s.GetSymmetricKey(peerID)
	if err != nil {
		return nil, err
	}
	if key == nil {
		return nil, fmt.Errorf("no symmetric key for peer %s", peerID)
	}
	return encryption.EncryptAESGCMWithNonceEmbed(plaintext, key)
}
```

### Luồng bắt tay ECDH

Phiên ECDH (`pkg/mpc/key_exchange_session.go`) được xây dựng phía trên bus NATS:

1. Mỗi node tạo một cặp khóa X25519 tạm thời và đăng ký topic dùng chung `ecdh:exchange`.
2. Các node phát quảng bá khóa công khai kèm dấu thời gian, được ký bằng định danh Ed25519 của mình (`SignEcdhMessage`).
3. Bên nhận xác minh chữ ký, thực hiện `ECDH()` bằng khóa riêng của mình và dẫn xuất khóa đối xứng bằng HKDF-SHA256.
4. Khóa 32 byte được dẫn xuất sẽ được lưu đệm theo từng peer qua `identityStore.SetSymmetricKey` và được các hàm hỗ trợ AES-GCM ở trên tái sử dụng.

**Dẫn xuất khóa HKDF**

```go
func (e *ecdhSession) deriveSymmetricKey(secret []byte, peerID string) []byte {
	info := deriveConsistentInfo(e.nodeID, peerID) // stable ordering of IDs
	hkdfReader := hkdf.New(sha256.New, secret, nil, info)
	key := make([]byte, 32) // AES-256 key
	if _, err := hkdfReader.Read(key); err != nil {
		e.errCh <- err
		return nil
	}
	return key
}
```

Nếu một peer ngắt kết nối, `RemovePeer` sẽ xóa khóa đối xứng đã lưu đệm để bắt buộc bắt tay lại khi kết nối lại, giữ cho khóa kênh luôn mang tính tạm thời.

### Cô lập mạng

| Biện pháp kiểm soát | Cách triển khai |
| --- | --- |
| Mạng riêng | Các node MPC giao tiếp qua VPC/VPN riêng |
| Quy tắc tường lửa | Chỉ mở các cổng MPC, giới hạn cho IP của các node đã biết |
| Giới hạn tốc độ | Tốc độ thông điệp tối đa cho mỗi node để ngăn chặn DoS |
| Giám sát kết nối | Mọi kết nối đều được ghi log và giám sát để phát hiện bất thường |

---

## 5. Bảo mật lưu trữ

Các phần khóa được lưu trữ bên trong BadgerDB. Dịch vụ MPC từ chối mở cơ sở dữ liệu nếu không được cung cấp khóa mã hóa (`badger_password`), và khóa đó được đưa vào cơ chế mã hóa AES-256 của Badger thông qua `WithEncryptionKey(...)` (`pkg/kvstore/badger.go`). Bản sao lưu dùng lại cùng định dạng mã hóa, nên cả tệp DB đang hoạt động lẫn các bản lưu trữ snapshot đều không thể đọc được nếu không có mật khẩu.

**Mã hóa Badger**

```go
opts := badger.DefaultOptions(config.DBPath).
  WithEncryptionKey(config.EncryptionKey).
  WithCompression(options.ZSTD)

db, err := badger.Open(opts)
```

---

## 6. Tóm tắt

Triển khai MPC của Fystack loại bỏ các điểm lỗi đơn lẻ thông qua niềm tin phân tán, mật mã ngưỡng và các giao thức đa bên an toàn. Bằng cách chia khóa riêng tư thành nhiều phần và yêu cầu ký cộng tác, chúng tôi đảm bảo không một sự xâm phạm đơn lẻ nào có thể dẫn đến mất tài sản.

**Các tính năng bảo mật chính:**

- **Tạo khóa phân tán** không có điểm tin cậy đơn lẻ
- **Chữ ký ngưỡng** yêu cầu nhiều bên hợp tác
- **Giao tiếp được mã hóa** với TLS + payload AES-GCM dùng khóa dẫn xuất từ ECDH
- **Mã hóa BadgerDB khi lưu trữ** bằng AES-256 với mật khẩu do người vận hành cung cấp
- **Tính toán có thể xác minh** để phát hiện các bên độc hại
