Trạng thái
Beta Q1 2026, phát hành Q2 2026
Tổng quan
Đây là biến thể lai lượng tử hậu (hybrid post-quantum) của giao thức truyền tải NTCP2, được thiết kế trong Đề xuất 169. Xem đề xuất đó để có thêm thông tin nền.
PQ Hybrid NTCP2 chỉ được định nghĩa trên cùng địa chỉ và cổng với NTCP2 tiêu chuẩn. Việc hoạt động trên cổng khác, hoặc không có hỗ trợ NTCP2 tiêu chuẩn, là không được phép và sẽ không được cho phép trong vài năm tới, khi NTCP2 tiêu chuẩn bị loại bỏ.
Đặc tả này chỉ ghi lại những thay đổi cần thiết đối với NTCP2 tiêu chuẩn để hỗ trợ PQ Hybrid. Xem đặc tả NTCP2 để biết chi tiết triển khai cơ bản.
Thiết kế
Chúng tôi hỗ trợ các tiêu chuẩn NIST FIPS 203 và 204 FIPS 203 FIPS 204 được dựa trên, nhưng KHÔNG tương thích với, CRYSTALS-Kyber và CRYSTALS-Dilithium (phiên bản 3.1, 3, và các phiên bản cũ hơn).
Trao đổi khóa
PQ KEM chỉ cung cấp các khóa tạm thời và không hỗ trợ trực tiếp các handshake khóa tĩnh như Noise XK và IK. Các loại mã hóa giống như được sử dụng trong PQ Hybrid Ratchet và được định nghĩa trong tài liệu cấu trúc chung /docs/specs/common-structures/ , như trong FIPS 203 , các loại Hybrid chỉ được định nghĩa kết hợp với X25519.
Các loại mã hóa là:
| Type | Code |
|---|---|
| MLKEM512_X25519 | 5 |
| MLKEM768_X25519 | 6 |
| MLKEM1024_X25519 | 7 |
Các Kết Hợp Hợp Pháp
Các loại mã hóa mới được chỉ định trong RouterAddresses. Loại mã hóa trong key certificate sẽ tiếp tục là loại 4.
Đặc tả
Các Mẫu Bắt Tay
Quá trình bắt tay sử dụng các mẫu bắt tay của Noise Protocol .
Ánh xạ chữ cái sau đây được sử dụng:
- e = khóa tạm thời một lần
- s = khóa tĩnh
- p = tải trọng thông điệp
- e1 = khóa PQ tạm thời một lần, được gửi từ Alice đến Bob
- ekem1 = bản mã KEM, được gửi từ Bob đến Alice
Các sửa đổi sau đây đối với XK và IK để có tính bí mật chuyển tiếp lai (hybrid forward secrecy - hfs) được chỉ định trong Noise HFS spec mục 5:
XK: XKhfs:
<- s <- s
... ...
-> e, es, p -> e, es, e1, p
<- e, ee, p <- e, ee, ekem1, p
-> s, se -> s, se
<- p <- p
p -> p ->
e1 and ekem1 are encrypted. See pattern definitions below.
NOTE: e1 and ekem1 are different sizes (unlike X25519)
Mẫu e1 được định nghĩa như sau, theo quy định trong đặc tả Noise HFS phần 4:
For Alice:
(encap_key, decap_key) = PQ_KEYGEN()
// EncryptAndHash(encap_key)
ciphertext = ENCRYPT(k, n, encap_key, ad)
n++
MixHash(ciphertext)
For Bob:
// DecryptAndHash(ciphertext)
encap_key = DECRYPT(k, n, ciphertext, ad)
n++
MixHash(ciphertext)
Mẫu ekem1 được định nghĩa như sau, theo quy định trong Noise HFS spec mục 4:
For Bob:
(kem_ciphertext, kem_shared_key) = ENCAPS(encap_key)
// EncryptAndHash(kem_ciphertext)
ciphertext = ENCRYPT(k, n, kem_ciphertext, ad)
MixHash(ciphertext)
// MixKey
MixKey(kem_shared_key)
For Alice:
// DecryptAndHash(ciphertext)
kem_ciphertext = DECRYPT(k, n, ciphertext, ad)
MixHash(ciphertext)
// MixKey
kem_shared_key = DECAPS(kem_ciphertext, decap_key)
MixKey(kem_shared_key)
Noise Handshake KDF
Tổng quan
Handshake lai được định nghĩa trong đặc tả Noise HFS . Tin nhắn đầu tiên, từ Alice đến Bob, chứa e1, encapsulation key, trước payload của tin nhắn. Điều này được coi là một static key bổ sung; gọi EncryptAndHash() trên nó (với Alice) hoặc DecryptAndHash() (với Bob). Sau đó xử lý payload tin nhắn như bình thường.
Thông báo thứ hai, từ Bob gửi đến Alice, chứa ekem1, bản mã hóa, trước payload của thông báo. Điều này được xem như một khóa tĩnh bổ sung; gọi EncryptAndHash() trên nó (với Bob) hoặc DecryptAndHash() (với Alice). Sau đó, tính toán kem_shared_key và gọi MixKey(kem_shared_key). Tiếp theo xử lý payload của thông báo như bình thường.
Các Thao Tác ML-KEM Được Định Nghĩa
Chúng tôi định nghĩa các hàm sau tương ứng với các khối xây dựng mật mã được sử dụng như được định nghĩa trong FIPS 203 .
(encap_key, decap_key) = PQ_KEYGEN()
Alice creates the encapsulation and decapsulation keys
The encapsulation key is sent in message 1.
encap_key and decap_key sizes vary based on ML-KEM variant.
(ciphertext, kem_shared_key) = ENCAPS(encap_key)
Bob calculates the ciphertext and shared key,
using the ciphertext received in message 1.
The ciphertext is sent in message 2.
ciphertext size varies based on ML-KEM variant.
The kem_shared_key is always 32 bytes.
kem_shared_key = DECAPS(ciphertext, decap_key)
Alice calculates the shared key,
using the ciphertext received in message 2.
The kem_shared_key is always 32 bytes.
Lưu ý rằng cả encap_key và ciphertext đều được mã hóa bên trong các khối ChaCha/Poly trong các thông điệp bắt tay Noise 1 và 2. Chúng sẽ được giải mã như một phần của quá trình bắt tay.
kem_shared_key được trộn vào chaining key bằng MixHash(). Xem chi tiết bên dưới.
Alice KDF cho Message 1
Sau mẫu thông điệp ’es’ và trước payload, thêm:
This is the "e1" message pattern:
(encap_key, decap_key) = PQ_KEYGEN()
// EncryptAndHash(encap_key)
// AEAD parameters
k = keydata[32:63]
n = 0
ad = h
ciphertext = ENCRYPT(k, n, encap_key, ad)
n++
// MixHash(ciphertext)
h = SHA256(h || ciphertext)
End of "e1" message pattern.
NOTE: For the next section (payload for XK or static key for IK),
the keydata and chain key remain the same,
and n now equals 1 (instead of 0 for non-hybrid).
Bob KDF cho Message 1
Sau mẫu thông điệp ’es’ và trước payload, thêm:
This is the "e1" message pattern:
// DecryptAndHash(encap_key_section)
// AEAD parameters
k = keydata[32:63]
n = 0
ad = h
encap_key = DECRYPT(k, n, encap_key_section, ad)
n++
// MixHash(encap_key_section)
h = SHA256(h || encap_key_section)
End of "e1" message pattern.
NOTE: For the next section (payload for XK or static key for IK),
the keydata and chain key remain the same,
and n now equals 1 (instead of 0 for non-hybrid).
Bob KDF cho Message 2
Đối với XK: Sau pattern thông điệp ’ee’ và trước payload, thêm:
This is the "ekem1" message pattern:
(kem_ciphertext, kem_shared_key) = ENCAPS(encap_key)
// EncryptAndHash(kem_ciphertext)
// AEAD parameters
k = keydata[32:63]
n = 0
ad = h
ciphertext = ENCRYPT(k, n, kem_ciphertext, ad)
// MixHash(ciphertext)
h = SHA256(h || ciphertext)
// MixKey(kem_shared_key)
keydata = HKDF(chainKey, kem_shared_key, "", 64)
chainKey = keydata[0:31]
End of "ekem1" message pattern.
Alice KDF cho Message 2
Sau pattern tin nhắn ’ee’, thêm:
This is the "ekem1" message pattern:
// DecryptAndHash(kem_ciphertext_section)
// AEAD parameters
k = keydata[32:63]
n = 0
ad = h
kem_ciphertext = DECRYPT(k, n, kem_ciphertext_section, ad)
// MixHash(kem_ciphertext_section)
h = SHA256(h || kem_ciphertext_section)
// MixKey(kem_shared_key)
kem_shared_key = DECAPS(kem_ciphertext, decap_key)
keydata = HKDF(chainKey, kem_shared_key, "", 64)
chainKey = keydata[0:31]
End of "ekem1" message pattern.
KDF cho Thông điệp 3 (chỉ XK)
không thay đổi
KDF cho split()
không thay đổi
Chi tiết Handshake
Định danh Noise
- “Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM512_ChaChaPoly_SHA256”
- “Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM768_ChaChaPoly_SHA256”
- “Noise_XKhfsaesobfse+hs2+hs3_25519+MLKEM1024_ChaChaPoly_SHA256”
1) SessionRequest
Thay đổi: NTCP2 hiện tại chỉ chứa các tùy chọn trong phần ChaCha. Với ML-KEM, phần ChaCha cũng sẽ chứa khóa công khai PQ được mã hóa.
Để PQ và NTCP2 không phải PQ có thể được hỗ trợ trên cùng một địa chỉ router và cổng, chúng ta sử dụng bit quan trọng nhất của giá trị X (khóa công khai tạm thời X25519) để đánh dấu rằng đó là kết nối PQ. Bit này luôn được bỏ đặt cho các kết nối không phải PQ.
Đối với Alice, sau khi thông điệp được mã hóa bằng Noise, nhưng trước khi thực hiện AES obfuscation của X, đặt X[31] |= 0x7f.
Đối với Bob, sau khi giải mã obfuscation AES của X, kiểm tra X[31] & 0x80. Nếu bit được đặt, xóa nó bằng X[31] &= 0x7f, và giải mã qua Noise như một kết nối PQ. Nếu bit bị xóa, giải mã qua Noise như một kết nối không-PQ như thường lệ.
Đối với PQ NTCP2 được quảng cáo trên địa chỉ router và cổng khác, điều này không bắt buộc.
Để biết thêm thông tin, xem phần Địa chỉ Đã xuất bản bên dưới.
Nội dung thô:
+----+----+----+----+----+----+----+----+
| MS bit set to 1 and then |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted X |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| ChaChaPoly frame (MLKEM) |
+ (see table below for length) +
| k defined in KDF for message 1 |
+ n = 0 +
| see KDF for associated data |
~ n = 0 ~
+----+----+----+----+----+----+----+----+
| |
+ +
| ChaChaPoly frame (options) |
+ 32 bytes +
| k defined in KDF for message 1 |
+ n = 0 +
| see KDF for associated data |
+----+----+----+----+----+----+----+----+
| unencrypted authenticated |
~ padding (optional) ~
| length defined in options block |
+----+----+----+----+----+----+----+----+
Same as current specification except add a second ChaChaPoly frame
Dữ liệu không được mã hóa (thẻ xác thực Poly1305 không được hiển thị):
+----+----+----+----+----+----+----+----+
| |
+ +
| X |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| ML-KEM encap_key |
+ (see table below for length) +
| |
+----+----+----+----+----+----+----+----+
| options |
+ (16 bytes) +
| |
+----+----+----+----+----+----+----+----+
| unencrypted authenticated |
+ padding (optional) +
| length defined in options block |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Lưu ý: trường phiên bản trong khối tùy chọn thông điệp 1 phải được đặt thành 2, ngay cả đối với các kết nối PQ.
Kích thước:
| Loại | Mã Loại | Độ dài X | Độ dài Msg 1 | Độ dài Msg 1 mã hóa | Độ dài Msg 1 giải mã | Độ dài khóa PQ | Độ dài tùy chọn |
|---|---|---|---|---|---|---|---|
| X25519 | 4 | 32 | 64+pad | 32 | 16 | -- | 16 |
| MLKEM512_X25519 | 5 | 32 | 880+pad | 848 | 816 | 800 | 16 |
| MLKEM768_X25519 | 6 | 32 | 1264+pad | 1232 | 1200 | 1184 | 16 |
| MLKEM1024_X25519 | 7 | 32 | 1648+pad | 1616 | 1584 | 1568 | 16 |
Lưu ý: Các mã loại chỉ dành cho sử dụng nội bộ. Các router sẽ vẫn là loại 4, và hỗ trợ sẽ được chỉ ra trong các địa chỉ router.
2) SessionCreated
Nội dung thô:
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted Y |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| ChaChaPoly frame (MLKEM) |
+ Encrypted and authenticated data +
- (see table below for length) -
+ k defined in KDF for message 2 +
| n = 0; see KDF for associated data |
+ +
| |
+----+----+----+----+----+----+----+----+
| ChaChaPoly frame (options) |
+ Encrypted and authenticated data +
- 32 bytes -
+ k defined in KDF for message 2 +
| n = 0; see KDF for associated data |
+ +
| |
+----+----+----+----+----+----+----+----+
| unencrypted authenticated |
+ padding (optional) +
| length defined in options block |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Same as current specification except add a second ChaChaPoly frame
Dữ liệu không mã hóa (không hiển thị thẻ xác thực Poly1305):
+----+----+----+----+----+----+----+----+
| |
+ +
| Y |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| ML-KEM Ciphertext |
+ (see table below for length) +
| |
+----+----+----+----+----+----+----+----+
| options |
+ (16 bytes) +
| |
+----+----+----+----+----+----+----+----+
| unencrypted authenticated |
+ padding (optional) +
| length defined in options block |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Kích thước:
| Loại | Mã Loại | Độ dài Y | Độ dài Msg 2 | Độ dài Msg 2 Enc | Độ dài Msg 2 Dec | Độ dài PQ CT | Độ dài opt |
|---|---|---|---|---|---|---|---|
| X25519 | 4 | 32 | 64+pad | 32 | 16 | -- | 16 |
| MLKEM512_X25519 | 5 | 32 | 848+pad | 816 | 784 | 768 | 16 |
| MLKEM768_X25519 | 6 | 32 | 1136+pad | 1104 | 1104 | 1088 | 16 |
| MLKEM1024_X25519 | 7 | 32 | 1616+pad | 1584 | 1584 | 1568 | 16 |
Lưu ý: Các mã loại chỉ dành cho sử dụng nội bộ. Các router sẽ vẫn là loại 4, và việc hỗ trợ sẽ được chỉ ra trong địa chỉ router.
3) SessionConfirmed
Không thay đổi
Hàm Tạo Khóa (KDF) (cho giai đoạn dữ liệu)
Không thay đổi
Địa chỉ Đã công bố
Trong tất cả các trường hợp, hãy sử dụng tên transport NTCP2 như thường lệ.
Sử dụng cùng địa chỉ/cổng như non-PQ, non-firewalled. Chỉ hỗ trợ một biến thể PQ. Trong địa chỉ router, xuất bản v=2 (như thường lệ) và tham số mới pq=[3|4|5] để chỉ ra MLKEM 512/768/1024. Alice đặt MSB của ephemeral key (key[31] & 0x80) trong session request để chỉ ra rằng đây là kết nối hybrid. Xem ở trên. Các router cũ sẽ bỏ qua tham số pq và kết nối non-pq như thường lệ.
Địa chỉ/cổng khác với non-PQ, hoặc chỉ PQ, không có tường lửa KHÔNG được hỗ trợ. Điều này sẽ không được triển khai cho đến khi non-PQ NTCP2 bị vô hiệu hóa, vài năm nữa. Khi non-PQ bị vô hiệu hóa, nhiều biến thể PQ có thể được hỗ trợ, nhưng chỉ một biến thể trên mỗi địa chỉ. Khi được hỗ trợ, trong địa chỉ router, xuất bản v=[3|4|5] để chỉ ra MLKEM 512/768/1024. Alice không đặt MSB của khóa ephemeral. Các router cũ sẽ kiểm tra tham số v và bỏ qua địa chỉ này vì không được hỗ trợ.
Địa chỉ bị firewall (không công bố IP): Trong địa chỉ router, công bố v=2 (như thường lệ). Không cần thiết phải công bố tham số pq.
Alice có thể kết nối đến PQ Bob bằng cách sử dụng biến thể PQ mà Bob công bố, bất kể Alice có quảng cáo hỗ trợ pq trong router info của mình hay không, hoặc liệu cô ấy có quảng cáo cùng một biến thể.
Đệm Tối Đa
Trong đặc tả hiện tại, các thông điệp 1 và 2 được định nghĩa có một lượng padding “hợp lý”, với khoảng 0-31 byte được khuyến nghị và không có giới hạn tối đa được chỉ định.
Từ API 0.9.68 (phiên bản 2.11.0), Java I2P đã triển khai tối đa 256 byte padding cho các kết nối không phải PQ, tuy nhiên điều này trước đây không được ghi lại. Kể từ API 0.9.69 (phiên bản 2.12.0), Java I2P triển khai cùng mức padding tối đa cho các kết nối không phải PQ như đối với MLKEM-512. Xem bảng bên dưới.
Sử dụng kích thước thông điệp đã định nghĩa làm padding tối đa, tức là padding tối đa sẽ tăng gấp đôi kích thước thông điệp cho các kết nối PQ, như sau:
| Message Max Padding | non-PQ (thru 0.9.68) | non-PQ (as of 0.9.69) | MLKEM-512 | MLKEM-768 | MLKEM-1024 |
|---|---|---|---|---|---|
| Session Request | 256 | 880 | 880 | 1264 | 1648 |
| Session Created | 256 | 848 | 848 | 1136 | 1616 |
Phân Tích Chi Phí Hoạt Động
Trao Đổi Khóa
Tăng kích thước (byte):
| Loại | Pubkey (Msg 1) | Cipertext (Msg 2) |
|---|---|---|
| MLKEM512_X25519 | +816 | +784 |
| MLKEM768_X25519 | +1200 | +1104 |
| MLKEM1024_X25519 | +1584 | +1584 |
Phân tích Bảo mật
Các danh mục bảo mật NIST được tóm tắt trong bài thuyết trình NIST slide 10. Tiêu chí sơ bộ: Danh mục bảo mật NIST tối thiểu của chúng ta nên là 2 cho các giao thức hybrid và 3 cho PQ-only.
| Danh mục | Bảo mật tương đương |
|---|---|
| 1 | AES128 |
| 2 | SHA256 |
| 3 | AES192 |
| 4 | SHA384 |
| 5 | AES256 |
Bắt tay
Đây đều là các giao thức kết hợp. Các triển khai nên ưu tiên MLKEM768; MLKEM512 không đủ bảo mật.
Các danh mục bảo mật NIST FIPS 203 :
| Thuật toán | Danh mục Bảo mật |
|---|---|
| MLKEM512 | 1 |
| MLKEM768 | 3 |
| MLKEM1024 | 5 |
Ghi chú Triển khai
Hỗ trợ Thư viện
Các thư viện Bouncycastle, BoringSSL, và WolfSSL hiện đã hỗ trợ MLKEM và MLDSA. Hỗ trợ OpenSSL sẽ có trong phiên bản 3.5 của họ vào ngày 8 tháng 4 năm 2025 OpenSSL .
Xác định Lưu lượng Đến
Chúng ta đặt MSB của khóa tạm thời (key[31] & 0x80) trong session request để chỉ ra rằng đây là kết nối hybrid. Điều này cho phép chúng ta chạy cả NTCP tiêu chuẩn và NTCP hybrid trên cùng một cổng. Chỉ một biến thể hybrid được hỗ trợ cho kết nối đến, và được quảng cáo trong địa chỉ router. Ví dụ, pq=3 hoặc pq=4.
Làm rối
Với tư cách là Alice, đối với kết nối PQ, trước khi obfuscation, đặt X[31] |= 0x80. Điều này làm cho X trở thành một public key X25519 không hợp lệ. Sau obfuscation, AES-CBC sẽ làm ngẫu nhiên hóa nó. MSB của X sẽ là ngẫu nhiên sau obfuscation.
Với vai trò Bob, kiểm tra xem (X[31] & 0x80) != 0 sau khi de-obfuscation. Nếu đúng, đây là kết nối PQ.
Phiên bản router tối thiểu cần thiết cho NTCP2-PQ sẽ được xác định sau.
Lưu ý: Mã loại chỉ dành cho sử dụng nội bộ. Các router sẽ vẫn là loại 4, và hỗ trợ sẽ được chỉ ra trong địa chỉ router.
Khả năng tương thích Router
Tên Transport
Trong tất cả các trường hợp, sử dụng tên giao thức NTCP2 như thông thường. Các router cũ sẽ bỏ qua tham số pq và kết nối với NTCP2 tiêu chuẩn như bình thường.