此翻译是使用机器学习生成的,可能不是100%准确。 查看英文版本

PQ 混合 NTCP2

使用 ML-KEM 的 NTCP2 传输协议的后量子混合变体

状态

Beta 版本 2026 年第一季度,正式发布 2026 年第二季度

概述

这是 NTCP2 传输协议的混合后量子变体,按照提案 169 的设计。有关更多背景信息,请参阅该提案。

PQ 混合 NTCP2 只能在与标准 NTCP2 相同的地址和端口上定义。不允许在不同端口上运行,或者在没有标准 NTCP2 支持的情况下运行,并且在未来几年内都不会允许,直到标准 NTCP2 被弃用。

本规范仅记录了标准 NTCP2 支持 PQ Hybrid 所需的更改。有关基线实现详细信息,请参阅 NTCP2 规范。

设计

我们支持 NIST FIPS 203 和 204 标准 FIPS 203 FIPS 204 ,这些标准基于但不兼容 CRYSTALS-Kyber 和 CRYSTALS-Dilithium(版本 3.1、3 及更早版本)。

密钥交换

PQ KEM 仅提供临时密钥,不直接支持静态密钥握手(如 Noise XK 和 IK)。加密类型与 PQ Hybrid Ratchet 中使用的相同,在通用结构文档 /docs/specs/common-structures/ 中定义,如 FIPS 203 所述。混合类型仅与 X25519 结合定义。

加密类型包括:

类型代码
MLKEM512_X255195
MLKEM768_X255196
MLKEM1024_X255197

合法组合

新的加密类型在RouterAddresses中指示。密钥证书中的加密类型将继续为类型4。

规范

握手模式

握手使用 Noise Protocol 握手模式。

使用以下字母映射:

  • e = 一次性临时密钥
  • s = 静态密钥
  • p = 消息载荷
  • e1 = 一次性临时 PQ 密钥,从 Alice 发送到 Bob
  • ekem1 = KEM 密文,从 Bob 发送到 Alice

以下对 XK 和 IK 的混合前向保密(hfs)修改是按照 Noise HFS spec 第 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)

e1 模式的定义如下,按照 Noise HFS spec 第 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)

ekem1 模式定义如下,具体规范见 Noise HFS spec 第 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 握手密钥派生函数

概述

混合握手在Noise HFS规范 中定义。第一条消息从Alice发送给Bob,在消息载荷之前包含e1(封装密钥)。这被视为额外的静态密钥;对其调用EncryptAndHash()(作为Alice)或DecryptAndHash()(作为Bob)。然后像往常一样处理消息载荷。

第二条消息,从 Bob 到 Alice,在消息负载之前包含 ekem1(密文)。这被视为一个额外的静态密钥;对其调用 EncryptAndHash()(作为 Bob)或 DecryptAndHash()(作为 Alice)。然后,计算 kem_shared_key 并调用 MixKey(kem_shared_key)。接着像往常一样处理消息负载。

定义的 ML-KEM 操作

我们定义以下函数,对应于 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.

请注意,encap_key 和密文都在 Noise 握手消息 1 和 2 的 ChaCha/Poly 块内进行加密。它们将作为握手过程的一部分被解密。

kem_shared_key 通过 MixHash() 混合到链式密钥中。详细信息请参见下文。

Alice KDF 用于消息 1

在’es’消息模式之后和载荷之前,添加:

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 消息 1 的 KDF

在 ’es’ 消息模式之后和载荷之前,添加:

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 在消息 2 中的密钥派生函数

对于 XK:在 ’ee’ 消息模式之后和载荷之前,添加:

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 在消息 2 中的 KDF

在 ’ee’ 消息模式之后,添加:

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.

消息 3 的 KDF(仅限 XK)

未更改

split() 的密钥派生函数 (KDF)

未更改

握手详情

噪声标识符

  • “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

变更:当前的 NTCP2 仅包含 ChaCha 部分中的选项。使用 ML-KEM 后,ChaCha 部分还将包含加密的 PQ 公钥。

为了在同一个 router 地址和端口上同时支持 PQ 和非 PQ NTCP2,我们使用 X 值(X25519 临时公钥)的最高有效位来标记这是一个 PQ 连接。对于非 PQ 连接,此位始终为未设置状态。

对于Alice,在消息被Noise加密之后,但在对X进行AES混淆之前,设置X[31] |= 0x7f。

对于 Bob,在对 X 进行 AES 去混淆后,测试 X[31] & 0x80。如果该位被设置,则通过 X[31] &= 0x7f 清除它,并通过 Noise 作为 PQ 连接进行解密。如果该位未设置,则像往常一样通过 Noise 作为非 PQ 连接进行解密。

对于在不同router地址和端口上发布的PQ NTCP2,这不是必需的。

更多信息请参阅下面的"已发布地址"部分。

原始内容:

  +----+----+----+----+----+----+----+----+
  |        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

未加密数据(未显示 Poly1305 认证标签):

  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                   X                   |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |           ML-KEM encap_key            |
  +      (see table below for length)     +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |               options                 |
  +              (16 bytes)               +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     unencrypted authenticated         |
  +         padding (optional)            +
  |     length defined in options block   |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

注意:消息1选项块中的版本字段必须设置为2,即使对于PQ连接也是如此。

大小:

类型类型代码X 长度消息 1 长度消息 1 加密长度消息 1 解密长度PQ 密钥长度可选长度
X2551943264+pad3216--16
MLKEM512_X25519532880+pad84881680016
MLKEM768_X255196321264+pad12321200118416
MLKEM1024_X255197321648+pad16161584156816

注意:类型代码仅供内部使用。Router 将保持类型 4,支持情况将在 router 地址中指示。

2) SessionCreated

原始内容:

  +----+----+----+----+----+----+----+----+
  |                                       |
  +        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

未加密数据(未显示 Poly1305 认证标签):

  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                  Y                    |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |           ML-KEM Ciphertext           |
  +      (see table below for length)     +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |               options                 |
  +              (16 bytes)               +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     unencrypted authenticated         |
  +         padding (optional)            +
  |     length defined in options block   |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

大小:

类型类型代码Y 长度消息 2 长度消息 2 加密长度消息 2 解密长度PQ CT 长度可选长度
X2551943264+pad3216--16
MLKEM512_X25519532848+pad81678476816
MLKEM768_X255196321136+pad11041104108816
MLKEM1024_X255197321616+pad15841584156816

注意:类型代码仅供内部使用。Router 将保持类型 4,支持情况将在 router 地址中标明。

3) SessionConfirmed

未更改

密钥派生函数 (KDF)(用于数据阶段)

未更改

已发布地址

在所有情况下,像往常一样使用 NTCP2 传输名称。

使用与非PQ、非防火墙相同的地址/端口。仅支持一种PQ变体。在router地址中,发布v=2(如常)和新参数pq=[3|4|5]来指示MLKEM 512/768/1024。Alice在会话请求中设置临时密钥的MSB(key[31] & 0x80)来指示这是一个混合连接。见上文。较旧的router将忽略pq参数并照常进行非pq连接。

不支持使用与非PQ不同的地址/端口,或仅PQ、非防火墙的配置。这在几年后非PQ NTCP2被禁用之前不会被实现。当非PQ被禁用时,可能会支持多个PQ变体,但每个地址只能有一个。当支持时,在router地址中,发布v=[3|4|5]来指示MLKEM 512/768/1024。Alice不设置临时密钥的MSB。较旧的router将检查v参数并跳过此地址,视为不支持。

防火墙地址(未发布IP):在router地址中,发布v=2(如常)。无需发布pq参数。

Alice 可以使用 Bob 发布的 PQ 变体连接到 PQ Bob,无论 Alice 是否在其 router 信息中宣传 pq 支持,或者她是否宣传相同的变体。

最大填充

在当前规范中,消息1和消息2被定义为具有"合理"的填充量,建议范围为0-31字节,未指定最大值。

在 API 0.9.68(版本 2.11.0)之前,Java I2P 为非 PQ 连接实现了最大 256 字节的填充,但这之前并未记录在文档中。从 API 0.9.69(版本 2.12.0)开始,Java I2P 为非 PQ 连接实现了与 MLKEM-512 相同的最大填充。请参见下表。

使用定义的消息大小作为最大填充,也就是说,最大填充将使 PQ 连接的消息大小翻倍,如下所示:

消息最大填充非后量子(至 0.9.68)非后量子(自 0.9.69 起)MLKEM-512MLKEM-768MLKEM-1024
Session Request25688088012641648
Session Created25684884811361616

开销分析

密钥交换

大小增加(字节):

类型公钥 (消息 1)密文 (消息 2)
MLKEM512_X25519+816+784
MLKEM768_X25519+1200+1104
MLKEM1024_X25519+1584+1584

安全分析

NIST安全类别在NIST演示文稿 第10页有总结。初步标准:我们的最低NIST安全类别对于混合协议应为2级,对于仅PQ协议应为3级。

类别安全级别相当于
1AES128
2SHA256
3AES192
4SHA384
5AES256

握手

这些都是混合协议。实现应该优先选择 MLKEM768;MLKEM512 不够安全。

NIST 安全类别 FIPS 203

算法安全类别
MLKEM5121
MLKEM7683
MLKEM10245

实现说明

库支持

Bouncycastle、BoringSSL 和 WolfSSL 库现在已支持 MLKEM 和 MLDSA。OpenSSL 的支持将在 2025 年 4 月 8 日发布的 3.5 版本中提供 OpenSSL

入站流量识别

我们在会话请求中设置临时密钥的最高位(key[31] & 0x80)来表示这是一个混合连接。这允许我们在同一端口上同时运行标准 NTCP 和混合 NTCP。入站连接只支持一种混合变体,并在 router 地址中进行广告。例如,pq=3 或 pq=4。

混淆

作为 Alice,对于 PQ 连接,在混淆之前,设置 X[31] |= 0x80。这使得 X 成为一个无效的 X25519 公钥。混淆后,AES-CBC 会将其随机化。混淆后 X 的最高有效位将是随机的。

作为 Bob,在去混淆后测试 (X[31] & 0x80) != 0。如果是,则这是一个 PQ 连接。

支持 NTCP2-PQ 所需的最低 router 版本待定。

注意:类型代码仅供内部使用。Router 将保持类型 4,支持情况将在 router 地址中指示。

Router 兼容性

传输协议名称

在所有情况下,像往常一样使用 NTCP2 传输名称。较旧的 router 将忽略 pq 参数并像往常一样使用标准 NTCP2 进行连接。

参考文献

Was this page helpful?