Rust in Everything
基于 rustls 0.23.46

套件与密钥交换

主线位置:握手主线的前两步。客户端把 provider 的套件列表和组列表写进 ClientHello,并为第一个组算好密钥共享;服务端用自己的 provider 和这两个列表求交集,选出一个套件和一个组,有对应的密钥共享就直接回 ServerHello,没有就回 HelloRetryRequest。本页讲两个内置 provider 的列表内容、两端怎么从里面挑,以及后量子混合组带来的字节和耗时。
flowchart TB
  ch["ClientHello"] --> suite["按客户端顺序选套件"]
  suite --> grp["按客户端顺序看组"]
  grp --> sup{"服务端支持"}
  sup -->|否| nxt["下一个组"]
  nxt --> sup
  sup -->|全都不支持| fail["NoKxGroupsInCommon"]
  sup -->|是| ks{"带了它的共享"}
  ks -->|是| sh["ServerHello"]
  ks -->|否| hrr["HelloRetryRequest"]

实验在 exp-rustls/crypto-lab(M2 Max、macOS 27、rustc 1.99.0,release)。同一个程序里同时编进 ring 和 aws-lc-rs 两个 provider,客户端和服务端各自用 builder_with_provider 指定,在内存里握手;程序把客户端的第一段字节(明文的 ClientHello 记录)按扩展解析出 supported_groups 和 key_share。证书是 rcgen 生成的 ECDSA P-256 自签证书。是否打开 prefer-post-quantum 分别编译一次。

默认套件

两个 provider 的 DEFAULT_CIPHER_SUITES 内容和顺序一样,ring 的写法最直接(ALL_CIPHER_SUITES,DEFAULT_CIPHER_SUITES 就是它):

pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[
    // TLS1.3 suites
    tls13::TLS13_AES_256_GCM_SHA384,
    tls13::TLS13_AES_128_GCM_SHA256,
    tls13::TLS13_CHACHA20_POLY1305_SHA256,
    // TLS1.2 suites
    #[cfg(feature = "tls12")]
    tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
    // ...
    #[cfg(feature = "tls12")]
    tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
];

TLS 1.3 三个,TLS 1.2 六个(ECDSA 和 RSA 证书各三个),全部是 AEAD,密钥交换全是 ECDHE。没有 CBC、没有 RSA 密钥传输、没有静态 DH。aws-lc-rs 的 DEFAULT_CIPHER_SUITES 多了三处 #[cfg(not(feature = "fips"))]:开 fips 时三个 ChaCha20-Poly1305 套件从默认列表里拿掉,ALL_CIPHER_SUITES 里仍然有。

顺序的理由写在 manual/defaults.rs:AES-256 排在 AES-128 前面是因为它对后量子攻击更保守,「The choice is frankly quite marginal」;AES-GCM 排在 ChaCha20 前面是因为 AES 硬件加速普遍。rustls 不检测 CPU 有没有 AES 指令,顺序是静态的;手册建议明知运行在没有 AES 加速的平台上时,自己把 ChaCha20 调到前面。

每个套件的 CipherSuiteCommon 还带一个 confidentiality_limit:AES-GCM 是 1 << 24 条记录,ChaCha20-Poly1305 是 u64::MAX。记录层按它决定什么时候主动更新密钥,见加密与序列号。

服务端选套件时默认按客户端的顺序:choose_suite_and_kx_group 先用证书的签名算法、协议版本、可用的密钥交换算法把自己的列表筛一遍,然后遍历客户端的列表,取第一个落在筛选结果里的。ServerConfig::ignore_client_order(默认 false)设成 true 才改成按服务端自己的顺序。两个默认 provider 顺序相同,所以默认配置下任意组合都协商出 TLS13_AES_256_GCM_SHA384;实验里把客户端的套件换成 [CHACHA20, AES_128],aws-lc-rs 服务端就选了 TLS13_CHACHA20_POLY1305_SHA256。

默认密钥交换组

ring 只有三个组,DEFAULT_KX_GROUPS 等于 ALL_KX_GROUPS:[X25519, SECP256R1, SECP384R1]。没有 FFDHE,也没有任何后量子算法。

aws-lc-rs 的 DEFAULT_KX_GROUPS 由 prefer-post-quantum 决定混合组排在哪一头:

pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
    #[cfg(feature = "prefer-post-quantum")]
    kx_group::X25519MLKEM768,
    kx_group::X25519,
    kx_group::SECP256R1,
    kx_group::SECP384R1,
    #[cfg(not(feature = "prefer-post-quantum"))]
    kx_group::X25519MLKEM768,
];

prefer-post-quantum 在 rustls 的默认 feature 里(default = ["aws_lc_rs", "logging", "prefer-post-quantum", "std", "tls12"])。所以「用默认 feature 的 rustls」意味着混合组排第一;关了默认 feature 只开 aws_lc_rs,混合组仍在列表里,但排最后。ALL_KX_GROUPS 还多三个不进默认列表的:SECP256R1MLKEM768,以及纯 MLKEM768、MLKEM1024。提交 c7a86ded 的说明解释了纯 ML-KEM 不进默认列表的原因:「out of an abundance of caution -- in case ML-KEM does not fare well in its first years of being (partially) load-bearing for internet traffic」。

X25519 排在 P-256 前面,手册的理由是性能更好,而且「it's much more likely that both peers will have good quality implementations」。aws-lc-rs 的 X25519、P-256、P-384 和 ring 的是同一份 rustls 代码(crypto/ring/kx.rs,aws-lc-rs 用 #[path] 引入),区别只在底下调的库。

客户端发什么

ClientHello 里和组有关的有两个扩展,都在 emit_client_hello_for_retry 里填:

  • supported_groups:kx_groups 里所有对本次提供的协议版本可用的组,按原顺序。混合组的 usable_for_version 只对 TLS 1.3 返回真,只开 TLS 1.2 时它不出现。
  • key_share:initial_key_share 取 kx_groups 的第一个(如果会话缓存里记着上次和这台服务器用的组,就用那个)调 start()。只有这一个组会真的算出密钥。

第一个组如果是混合组,还有一步「白送」的共享:

            if let Some((component_group, component_share)) =
                key_share
                    .hybrid_component()
                    .filter(|(group, _)| {
                        config
                            .find_kx_group(*group, ProtocolVersion::TLSv1_3)
                            .is_some()
                    })
            {
                shares.push(KeyShareEntry::new(component_group, component_share));
            }

ActiveKeyExchange::hybrid_component 返回混合组里经典那一半的组名和公钥。只要这个经典组本身也在 kx_groups 里,客户端就把它作为第二个 key_share 发出去,不另外生成密钥:实验比较了两个共享的字节,混合共享的最后 32 字节和单独的 X25519 共享完全相同。

hybrid share: 1216 B = ML-KEM encaps key 1184 B + X25519 32 B
X25519 half of hybrid == separate X25519 share: true

服务端如果选了经典组,客户端调 complete_hybrid_component,只用 X25519 那一半完成密钥交换,ML-KEM 的那部分丢掉。这一步让「后量子优先」的客户端连不支持后量子的服务端时不需要 HelloRetryRequest。

服务端怎么选组

还是 choose_suite_and_kx_group。它遍历的是客户端的 supported_groups,对每一项在自己的 kx_groups 里找同名的组,选出第一个找得到、又和已选套件的密钥交换算法匹配的:

        let maybe_skxg = supported_groups
            .iter()
            .find_map(|maybe_skxg| match maybe_skxg {
                Some(skxg) => suite
                    .usable_for_kx_algorithm(skxg.name().key_exchange_algorithm())
                    .then_some(*skxg),
                None => None,
            });

服务端 kx_groups 的顺序在这里只用来回答「支不支持」,不决定偏好,也没有 ignore_client_order 那样的开关。选定之后,TLS 1.3 的服务端在客户端的 key_share 里找这个组的共享(server/tls13.rs 的 chosen_share_and_kxg):找到就用它,找不到就调 emit_hello_retry_request 要求客户端为这个组重发 ClientHello。客户端列出的组服务端一个都不支持时,报 PeerIncompatible::NoKxGroupsInCommon。

📝NOTE
没有蠢问题

问: 服务端用的是默认 feature 的 aws-lc-rs,X25519MLKEM768 排在它自己列表的第一位;客户端关了 prefer-post-quantum,但列表里也有 X25519MLKEM768。两边都支持后量子,为什么协商出来的是 X25519?

答: 服务端按客户端的顺序挑。这个客户端的 supported_groups 是 [X25519, secp256r1, secp384r1, X25519MLKEM768],第一项 X25519 服务端就支持,客户端也带了它的共享,于是直接选定。服务端自己把混合组排第一,只影响它作为客户端时发什么。想让这对组合用上后量子,要改客户端的顺序。下面矩阵的第四行就是这种情况。

实测:provider 组合矩阵

不开 prefer-post-quantum(aws-lc-rs 默认组为 [X25519, secp256r1, secp384r1, X25519MLKEM768])。「轮次」一列是每一轮客户端发、服务端回的字节数,第二轮服务端回的 184 字节是两张会话票据:

客户端 → 服务端ClientHellokey_share轮次结果
ring → ring236 BX25519 32 B(236, 664), (80, 184)TLS13_AES_256_GCM_SHA384 / X25519
ring → aws-lc-rs236 BX25519 32 B(236, 665), (80, 184)同上
aws-lc-rs → ring246 BX25519 32 B(246, 665), (80, 184)同上
aws-lc-rs → aws-lc-rs246 BX25519 32 B(246, 664), (80, 184)同上
aws-lc-rs → 只有混合组的服务端246 BX25519 32 B见动脑筋见动脑筋
ring,ChaCha20 优先 → aws-lc-rs214 BX25519 32 B(214, 647), (64, 184)TLS13_CHACHA20_POLY1305_SHA256 / X25519
ring → 只有混合组的服务端236 BX25519 32 B—服务端 PeerIncompatible(NoKxGroupsInCommon)

打开 prefer-post-quantum(aws-lc-rs 默认组为 [X25519MLKEM768, X25519, secp256r1, secp384r1]):

客户端 → 服务端ClientHellokey_share轮次结果
ring → ring236 BX25519 32 B(236, 662), (80, 184)TLS13_AES_256_GCM_SHA384 / X25519
ring → aws-lc-rs236 BX25519 32 B(236, 662), (80, 184)同上
aws-lc-rs → ring1466 BX25519MLKEM768 1216 B、X25519 32 B(1466, 661), (80, 184)TLS13_AES_256_GCM_SHA384 / X25519
aws-lc-rs → aws-lc-rs1466 B同上(1466, 1751), (80, 184)TLS13_AES_256_GCM_SHA384 / X25519MLKEM768
aws-lc-rs → 只有混合组的服务端1466 B同上(1466, 1750), (80, 184)同上

(「只有混合组的服务端」是 aws-lc-rs 的默认 provider,把 kx_groups 换成只剩 X25519MLKEM768。服务端第一轮的字节数在 661 到 665 之间浮动,是 ECDSA 签名的 DER 编码长度不固定。)

能读出的几件事:

  • 默认 feature 的 rustls 客户端连 ring 服务端(例如本站的 sqlx、lettre 用的那种只开 ring 的 rustls),仍然一轮完成,协商出 X25519,靠的就是上一节的第二个共享。
  • ring 和 aws-lc-rs 的 ClientHello 差 10 字节:supported_groups 多一个 X25519MLKEM768(2 字节),signature_algorithms 多四个方案(8 字节:aws-lc-rs 的签名校验表比 ring 多 ECDSA_NISTP521_SHA512 和 ML-DSA 的三个级别,客户端把 SUPPORTED_SIG_ALGS 的 mapping 原样发出去)。
  • 换成 ChaCha20 优先的客户端,记录变短:TLS 1.3 的 ChaCha20 套件用 SHA-256,Finished 的 verify_data 是 32 字节而不是 48 字节,第二轮客户端只发 64 字节。

X25519MLKEM768

X25519MLKEM768 是一个 Hybrid:经典的一半是 aws-lc-rs provider 的 X25519,后量子的一半是 ML-KEM-768(aws-lc-rs 的 kem 模块)。线上的字节由 Layout 描述:

ML-KEM-768X25519合计
客户端共享封装公钥 1184 B公钥 32 B1216 B
服务端共享密文 1088 B公钥 32 B1120 B
共享秘密32 B32 B64 B,拼接后进 HKDF

post_quantum_first: true:X25519MLKEM768 里 ML-KEM 在前、X25519 在后,SECP256R1MLKEM768 反过来,Layout 的注释说这是「For dismal and unprincipled reasons」。ML-KEM 不是 Diffie-Hellman,服务端的那一半依赖客户端的公钥(封装),所以 Hybrid 覆盖了 start_and_complete,服务端一步完成封装和拼接,而不是像 DH 那样先 start 再 complete。

字节上的代价,按上面的矩阵:

  • ClientHello 从 246 字节到 1466 字节,多 1220 字节,正好是 1216 字节的混合共享加 4 字节的条目头(组号 2 字节、长度 2 字节)。supported_groups 只是换了顺序,长度不变。1466 字节仍是一条记录,但加上 TCP 和 IP 头已经超过以太网常见的 1500 字节 MTU,ClientHello 要跨两个 TCP 段。手册的后量子一节提醒可能遇到「unexpected connection failures」,并以 tldr.fail 为例。
  • 服务端协商出混合组时,第一轮的回复从 664 字节到 1751 字节,多出的约 1088 字节是 ML-KEM 密文。
  • 服务端是 ring 时,只多付了客户端那 1220 字节,协商结果和不开后量子一样。

只开 ring 时没有任何后量子组:ring 0.17 没有 ML-KEM,rustls 的 crypto/ring/ 下也没有 pq 模块。在 ring 之外再打开 prefer-post-quantum,不会让 ring 获得后量子能力,只会把 aws-lc-rs 也编进来(这个 feature 写作 prefer-post-quantum = ["aws_lc_rs"]):显式用 ring::default_provider() 的配置不受影响,ClientHello 还是 236 字节;走 ClientConfig::builder() 的代码则因为两个 provider 都在而 panic,原文和复现见 CryptoProvider。

📝NOTE
冷知识:后量子组进默认列表分了两步

c7a86ded(「Add post-quantum key exchange algorithm to defaults」,首次进入 0.23.22)把原本在独立 crate rustls-post-quantum 里的混合组搬进核心库,同时新增 prefer-post-quantum feature。提交说明写的是:设了这个 feature,X25519MLKEM768 是 DEFAULT_KX_GROUPS 里「the most preferred algorithm」,否则「it is least preferred」。当时 feature 默认不开,lib.rs 里写着「We expect to add this feature to the default set in a future minor release」。1b64a92c(「Add prefer-post-quantum to default features」,首次进入 0.23.27)兑现了这句话:「This enables, for dependents who use default-features, X25519MLKEM768 as the most-preferred key exchange」。因此同样是 0.23 的 rustls,0.23.22 之前的 aws-lc-rs 客户端根本不提混合组,0.23.22 到 0.23.26 提了但排最后(本页第一张表),0.23.27 起默认排第一、ClientHello 多出 1220 字节(第二张表)。

fips feature 改了什么

Cargo.toml 里 fips = ["aws_lc_rs", "aws-lc-rs?/fips", "webpki/aws-lc-rs-fips"]:打开 aws-lc-rs,把它切到 FIPS 构建(aws-lc-rs 的 fips feature 依赖 aws-lc-fips-sys 而不是 aws-lc-sys),rustls-webpki 那边也一起切。在 rustls 的代码里(不算测试),#[cfg(feature = "fips")] 只出现在 crypto/mod.rs、crypto/aws_lc_rs/mod.rs 和 crypto/aws_lc_rs/hpke.rs 三个文件:

位置开 fips 之后
aws-lc-rs DEFAULT_CIPHER_SUITES去掉三个 ChaCha20-Poly1305 套件,剩 TLS 1.3 两个、TLS 1.2 四个
aws-lc-rs default_kx_groupsDEFAULT_KX_GROUPS 过滤掉 fips() 为假的组
aws-lc-rs hpke::ALL_SUPPORTED_SUITESECH 用的 HPKE 套件去掉 ChaCha20 和 X25519 的
default_fips_provider()出现;它就是 aws_lc_rs::default_provider(),存在的意义是 feature 没开时编译不过

另外两处不靠 cfg,靠运行时的 fips():ClientConfig 和 ServerConfig 构建时 require_ems = self.provider.fips(),即 provider 处于 FIPS 模式时 TLS 1.2 默认要求扩展主密钥(extended master secret);ClientConfig::fips() 和 ServerConfig::fips() 在 CryptoProvider::fips() 之外再要求 require_ems(客户端还要求 ECH 配置也是 FIPS 的)。rustls 里 aws-lc-rs provider 各组件的 fips() 最终都落到模块里的 fips(),即 aws_lc_rs::try_fips_mode().is_ok(),ring 的一律是 false。

过滤组时有两个判断值得看。X25519 写的是 fips_allowed: false,注释引了 NIST 的说法:Curve25519 不在 SP 800-56Arev3 里。混合组的 fips() 按 SP 800-56C 的规则看排在前面的那一半:X25519MLKEM768 看 ML-KEM,SECP256R1MLKEM768 看 P-256。于是在 fips 加默认的 prefer-post-quantum 下,默认组应当是 [X25519MLKEM768, secp256r1, secp384r1]:混合组还在,单独的 X25519 没了。ML-KEM 的 fips() 有一段写给审计者的注释:写代码时 AWS-LC 的 ML-KEM 还处于「FIPS-pending」,rustls 采取宽松解释,只要底层库在 FIPS 模式就返回真。

本机没法验证真正的 FIPS 构建:aws-lc-fips-sys 不在 cargo 缓存里,离线解析依赖就失败(只要 Cargo.toml 里出现了打开 rustls/fips 的 feature,哪怕这次没启用,cargo 也会去解析它):

error: no matching package named `aws-lc-fips-sys` found
location searched: crates.io index
required by package `aws-lc-rs v1.19.0`
    ... which satisfies dependency `aws-lc-rs = "^1.18"` (locked to 1.19.0) of package `rustls v0.23.46`
    ... which satisfies dependency `rustls = "=0.23.46"` (locked to 0.23.46) of package `crypto-fips v0.1.0 (~/exp-rustls/crypto-fips)`
note: offline mode (via `--offline`) can sometimes cause surprising resolution failures

在非 FIPS 构建里,fips() 全是假:实测 ring 和 aws-lc-rs 的默认 provider 都是 provider.fips()=false、require_ems=false。退而求其次,实验在普通构建里手工拼了一个和上面推断一致的 provider(组 [X25519MLKEM768, secp256r1, secp384r1],套件去掉 ChaCha20),看它的行为:

fips-like client -> aws server
  ClientHello 1422 B; groups ["X25519MLKEM768", "secp256r1", "secp384r1"]; key_share ["X25519MLKEM768:1216B"]
  rounds [(1422, 1751), (80, 184)] => TLS13_AES_256_GCM_SHA384 / X25519MLKEM768 / Full
fips-like client -> ring server
  ClientHello 1422 B; groups ["X25519MLKEM768", "secp256r1", "secp384r1"]; key_share ["X25519MLKEM768:1216B"]
  rounds [(1422, 99), (277, 691), (74, 184)] => TLS13_AES_256_GCM_SHA384 / secp256r1 / FullWithHelloRetryRequest

因为 X25519 不在列表里,hybrid_component 那一步找不到经典组,客户端只发一个混合共享。连 ring 服务端时,服务端按客户端顺序选到 secp256r1,客户端没带它的共享,于是多一轮 HelloRetryRequest。这是手工模拟,不是 FIPS 构建的实测。

握手耗时

同一个进程里三种配置轮流握手(客户端和服务端用同一个 provider,单线程,内存里收发,含证书校验和 ECDSA P-256 签名),每种 2000 次,先预热 200 次,取最小值和中位数。连跑三次,机器负载(uptime 的 1 分钟值)约 11,其他写手在并行跑任务:

配置最小值(三次)中位数(三次)
ring,X25519130.7 / 124.3 / 124.7 µs135.2 / 130.7 / 132.2 µs
aws-lc-rs,X25519127.8 / 121.5 / 121.9 µs132.4 / 128.1 / 129.3 µs
aws-lc-rs,X25519MLKEM768165.8 / 157.8 / 157.9 µs172.2 / 166.2 / 167.9 µs

经典密钥交换下两个 provider 差 3 µs 左右,在噪声量级。打开后量子混合组,一次握手(两端合计)多约 36 µs,约多 30%。拆开看密钥交换本身(每项 5000 次取最小值,「客户端 complete」是 start + complete 减去 start 得到的近似值):

min of 5000
ring X25519            client start   10.9 us  server start_and_complete   38.7 us  client complete ~  27.7 us  share 32 B / reply 32 B
ring secp256r1         client start   10.4 us  server start_and_complete   47.7 us  client complete ~  37.2 us  share 65 B / reply 65 B
aws  X25519            client start    7.6 us  server start_and_complete   24.5 us  client complete ~  17.0 us  share 32 B / reply 32 B
aws  secp256r1         client start    9.8 us  server start_and_complete   42.0 us  client complete ~  32.1 us  share 65 B / reply 65 B
aws  X25519MLKEM768    client start   17.6 us  server start_and_complete   35.6 us  client complete ~  27.4 us  share 1216 B / reply 1120 B

aws-lc-rs 的 X25519 比 ring 的快(三项合计约 49 µs 对 77 µs),但整次握手两者几乎相等,说明差距被握手里的其他部分(签名、证书校验、哈希和 AEAD)抵消了;这里没有再往下拆。混合组的三项合计约 81 µs,比 aws-lc-rs 的 X25519 多约 32 µs,和整次握手多出的 36 µs 基本吻合。

❗IMPORTANT
动脑筋:不开 prefer-post-quantum 的 aws-lc-rs 客户端,连一个只支持 X25519MLKEM768 的服务端。握手要几轮?第二个 ClientHello 多大?

客户端的 supported_groups 里有 X25519MLKEM768(排最后),但第一个 ClientHello 只带了 X25519 的共享。程序和上面的矩阵相同。答案在文末。

动脑筋答案

aws client -> pq-only server
  ClientHello 246 B; supported_groups ["X25519", "secp256r1", "secp384r1", "X25519MLKEM768"]
  key_share ["X25519:32B"]
  rounds [(246, 99), (1436, 1746), (74, 184)]
  => TLS13_AES_256_GCM_SHA384 / X25519MLKEM768 / FullWithHelloRetryRequest

三轮。服务端按客户端顺序看组:X25519、secp256r1、secp384r1 它都不支持,到 X25519MLKEM768 才选定;客户端没带这个组的共享,服务端回 99 字节:HelloRetryRequest 加一条兼容用的 ChangeCipherSpec。第二轮客户端发 1436 字节:先是一条 6 字节的兼容用 ChangeCipherSpec(emit_client_hello_for_retry 在重发 ClientHello 之前发它),再是重发的 ClientHello,只带一个 1216 字节的混合共享(HelloRetryRequest 指定了组,按上文那段代码的条件不再附带经典共享)。重发的 ClientHello 记录是 1430 字节:比第一个少了 X25519 共享的 36 字节(条目头 4 加公钥 32),多了混合共享的 1220 字节,246 − 36 + 1220 = 1430,再加 6 字节的 ChangeCipherSpec 就是 1436。服务端这才回出完整的第一个飞行(1746 字节,含 1120 字节的服务端混合共享)。第三轮客户端只发 74 字节,比一轮握手时的 80 少了 6 字节,因为兼容用的 ChangeCipherSpec 已经在第二轮发过。和开了 prefer-post-quantum 的同一组合(两轮,1466 + 80 字节)相比,多一个往返,客户端还多算了一次 X25519。

小结

  • 两个内置 provider 的默认套件相同:TLS 1.3 三个、TLS 1.2 六个,AES-256-GCM 优先;服务端默认按客户端的套件顺序选。
  • ring 的组是 [X25519, secp256r1, secp384r1];aws-lc-rs 多一个 X25519MLKEM768,默认 feature 下排第一,关掉 prefer-post-quantum 排最后。
  • 服务端按客户端的 supported_groups 顺序选组,自己的顺序只决定支不支持;没有对应共享就 HelloRetryRequest。
  • 混合组排第一时,客户端顺带发出它的 X25519 那一半,ring 服务端也能一轮完成;ClientHello 多 1220 字节,协商出混合组时服务端多约 1088 字节。
  • 只开 ring 没有后量子;prefer-post-quantum 会把 aws-lc-rs 拉进来。
  • fips 去掉 ChaCha20 套件和 X25519,让 require_ems 默认为真;本机离线无法构建 FIPS 版的 aws-lc。
  • 本机内存握手:ring 约 124 µs,aws-lc-rs 约 122 µs,aws-lc-rs 加后量子约 158 µs(最小值)。

💬 关联讨论

发起讨论
加载中...