#后量子密码学 #加密密钥 #后量子 #解码 #pqc

无std classic-mceliece-rust

Classic McEliece后量子密码方案的纯Rust实现

7个稳定版本

3.0.0 2023年1月26日
2.0.2 2023年1月29日
2.0.1 2022年9月8日
1.1.0 2022年9月5日
1.0.1 2022年4月12日

#97 in 密码学

Download history 5053/week @ 2024-03-14 7310/week @ 2024-03-21 3436/week @ 2024-03-28 4646/week @ 2024-04-04 5377/week @ 2024-04-11 3656/week @ 2024-04-18 4017/week @ 2024-04-25 4039/week @ 2024-05-02 4121/week @ 2024-05-09 5772/week @ 2024-05-16 4728/week @ 2024-05-23 3800/week @ 2024-05-30 3447/week @ 2024-06-06 4391/week @ 2024-06-13 4495/week @ 2024-06-20 2800/week @ 2024-06-27

15,889 每月下载量
用于 rgp

MIT 许可证

240KB
5K SLoC

classic-mceliece-rust

这是一个纯Rust safe-rust实现的Classic McEliece后量子方案。

  • Classic McEliece是一种基于码的密钥封装机制(KEM)
  • 该实现基于NIST第4轮的Classic McEliece参考实现
  • 实现没有使用任何并发技术(SIMD/线程/…,除了可能在CPU上自动向量化)
  • 它依赖于sha3作为SHA-3实现,以及aes作为AES分组密码实现(用作RNG)
  • 它通过了C参考实现的100个测试用例
  • 它实现了Classic McEliece KEM的所有10种变体
  • 实现运行在现代计算机上需要100毫秒(mceliece348864)到500毫秒(mceliece8192128f
  • 在软件指令级别上实现为常数时间
  • 随机数生成器基于AES256计数模式
  • 首次在1978年描述,这个密码方案在安全性分析方面有着丰富的历史。然而,其大的公钥大小通常限制了其采用。

这10种变体有以下指定的标识符

  • mceliece348864
  • mceliece348864f
  • mceliece460896
  • mceliece460896f
  • mceliece6688128
  • mceliece6688128f
  • mceliece6960119
  • mceliece6960119f
  • mceliece8192128
  • mceliece8192128f

谁应该使用它?

任何想要使用Classic McEliece在双方之间协商密钥的人。

如何使用它来在堆上存储密钥(默认功能alloc)?

将以下内容添加到您的Cargo.toml

[dependencies]
classic-mceliece-rust = "3.0"

要使用特定的Classic McEliece变体,您需要使用相应的功能标志导入它

[dependencies]
classic-mceliece-rust = { version = "3.0", features = ["mceliece6960119"] }

假设此依赖项,使用堆分配密钥和*_boxed KEM步骤函数是使用库的最简单和最便捷的方法。首先,我们导入它们

#[cfg(feature = "alloc")]
use classic_mceliece_rust::{keypair_boxed, encapsulate_boxed, decapsulate_boxed};

接下来,我们运行KEM并提供相应的密钥。这里,我们考虑了一个在单独的线程中运行它的例子(请注意,该示例也依赖于rand crate)

#[cfg(feature = "alloc")] {
  use classic_mceliece_rust::{keypair_boxed, encapsulate_boxed, decapsulate_boxed};

  fn run_kem() {
    let mut rng = rand::thread_rng();

    // Alice computes the keypair
    let (public_key, secret_key) = keypair_boxed(&mut rng);

    // Send `secret_key` over to Bob.
    // Bob computes the shared secret and a ciphertext
    let (ciphertext, shared_secret_bob) = encapsulate_boxed(&public_key, &mut rng);

    // Send `ciphertext` back to Alice.
    // Alice decapsulates the ciphertext...
    let shared_secret_alice = decapsulate_boxed(&ciphertext, &secret_key);

    // ... and ends up with the same key material as Bob.
    assert_eq!(shared_secret_bob.as_array(), shared_secret_alice.as_array());
  }

  fn main() {
    std::thread::Builder::new()
      // This library needs quite a lot of stack space to work
      .stack_size(2 * 1024 * 1024)
      .spawn(run_kem)
      .unwrap()
      .join()
      .unwrap();
  }
}

请注意,Classic McEliece中的公钥非常大(介于255 KB和1.3 MB之间)。因此,运行该算法需要大量内存。您需要考虑在哪里存储它。在这个API中,优点是……

  • 您不需要手动处理内存
  • 在Windows上,对keypair的调用比默认提供的堆栈要大。可以通过堆分配API避免这种堆栈大小限制(请参阅下面的Windows说明)。

如果禁用了分配功能(alloc,这是一个禁用的功能),如何使用它来存储堆栈上的密钥?

另一个选项是不使用堆分配API,而使用提供的堆栈分配API。其优点是

  • 堆栈分配在no_std环境中也有效。
  • 在一些微控制器平台上,没有可用的堆。
  • 通常,堆栈(解)分配比堆(解)分配要快

因此,在本节中,我们想向您展示如何在没有堆的情况下使用此API。为此,您需要禁用默认启用的功能alloc(此行保留了默认功能zeroize,但删除了默认功能alloc

classic-mceliece-rust = { version = "3.0", default-features = false, features = ["zeroize"] }

那么如何使用API呢(请注意,该示例也依赖于rand crate)?

use classic_mceliece_rust::{keypair, encapsulate, decapsulate};
use classic_mceliece_rust::{CRYPTO_BYTES, CRYPTO_PUBLICKEYBYTES, CRYPTO_SECRETKEYBYTES};

fn main() {
  let mut rng = rand::thread_rng();

  // Please mind that `public_key_buf` is very large.
  let mut public_key_buf = [0u8; CRYPTO_PUBLICKEYBYTES];
  let mut secret_key_buf = [0u8; CRYPTO_SECRETKEYBYTES];
  let (public_key, secret_key) = keypair(&mut public_key_buf, &mut secret_key_buf, &mut rng);

  let mut shared_secret_bob_buf = [0u8; CRYPTO_BYTES];
  let (ciphertext, shared_secret_bob) = encapsulate(&public_key, &mut shared_secret_bob_buf, &mut rng);

  let mut shared_secret_alice_buf = [0u8; CRYPTO_BYTES];
  let shared_secret_alice = decapsulate(&ciphertext, &secret_key, &mut shared_secret_alice_buf);

  assert_eq!(shared_secret_bob.as_array(), shared_secret_alice.as_array());
}

在这里,您可以看到密钥是如何显式分配的。

关于Windows的说明

如果您希望您的程序可以与堆栈分配兼容并且不会意外崩溃,您可能需要在具有足够大的堆栈大小的专用线程中运行整个密钥交换。此代码片段显示了这一思路

std::thread::Builder::new()
    .stack_size(4 * 1024 * 1024)
    .spawn(|| {/* Run the KEM here */})
    .unwrap();

功能kem:RustCrypto API

如果启用了kem功能,密钥封装和解封装也可以通过kem crate中的标准特质来完成。

功能zeroize:从内存中清除秘密

如果启用了zeroize功能(默认情况下是启用的),则包含任何秘密内容的所有密钥类型都实现了ZeroizeZeroizeOnDrop。这使得它们在超出作用域时清除内存,从而降低了秘密密钥材料以某种方式泄露的风险。

请注意,这当然使得您传递给库的任何缓冲区对读取密钥都无用了。而不是尝试从您传入的缓冲区中检索密钥材料,请从as_array方法中获取。

#[cfg(not(windows))] {
    use classic_mceliece_rust::keypair;
    use classic_mceliece_rust::{CRYPTO_PUBLICKEYBYTES, CRYPTO_SECRETKEYBYTES};

    let mut rng = rand::thread_rng();

    let mut pk_buf = [0u8; CRYPTO_PUBLICKEYBYTES];
    // Initialize to non-zero to show that it has been set to zero by the drop later
    let mut sk_buf = [255u8; CRYPTO_SECRETKEYBYTES];

    // This is the WRONG way of accessing your keys. The buffer will
    // be cleared once the `PrivateKey` returned from `keypair` goes out of scope.
    // You should not rely on that array for anything except providing a temporary storage
    // location to this library.
    #[cfg(feature = "zeroize")]
    {
        let (_, secret_key) = keypair(&mut pk_buf, &mut sk_buf, &mut rng);
        drop(secret_key);
        // Ouch! The array only has zeroes now.
        assert_eq!(sk_buf, [0; CRYPTO_SECRETKEYBYTES]);
    }

    // Correct way of getting the secret key bytes if you do need them. However,
    // if you want the secrets to stay secret, you should try to not read them out of their
    // storage at all
    {
        let (_, secret_key) = keypair(&mut pk_buf, &mut sk_buf, &mut rng);
        assert_ne!(secret_key.as_array(), &[0; CRYPTO_SECRETKEYBYTES]);
    }
}

如何运行它?

本库附带两个示例

$ cargo run --example basic

输出使用Alice/Bob对消息进行注释,以说明哪些数据由哪一方处理。《katkem》示例实现了NIST PQC框架的一部分经典请求/响应文件结构。

$ cargo run --example katkem PQCkemKAT_935.req PQCkemKAT_935.rsp
$ cargo run --example katkem PQCkemKAT_935.rsp

可以通过功能标志启用不同的变体

$ cargo run --example katkem --features mceliece6960119 -- PQCkemKAT_1450.req PQCkemKAT_1450.rsp

mceliece348864是默认变体。您不能同时启用两个变体。

它有多快?

所有数据都使用时钟周期作为单位(越小越好)。v2.0.0的rust实现产生了以下运行时结果

完整的KEM密钥对加密解密
mceliece348864460,062,191439,682,143222,42442,046,357
mceliece348864f244,943,900203,564,820215,97141,648,773
mceliece4608961,326,425,7841,434,864,061487,522111,547,716
mceliece460896f789,636,856652,117,200553,301106,521,703
mceliece66881283,188,205,2662,596,052,574785,763202,774,928
mceliece6688128f1,236,809,0201,059,087,715826,899203,907,226
mceliece69601192,639,852,5732,532,146,1263,864,285203,959,009
mceliece6960119f1,165,079,187965,134,5463,416,795197,089,546
mceliece81921283,129,183,2622,754,933,130965,822247,083,745
mceliece8192128f1,342,438,4511,150,297,5951,068,317242,545,160

C参考实现产生了以下运行时结果

完整的KEM密钥对加密解密
mceliece348864434,103,000437,187,000187,55773,801,300
mceliece348864f252,423,000180,235,000189,52273,668,000
mceliece460896760,993,000894,497,000298,041154,507,000
mceliece460896f606,225,00044,906,000297,743154,013,000
mceliece66881281,568,900,0001,780,660,000425,50429,575,000
mceliece6688128f109,471,000760,298,000414,358298,173,000
mceliece69601193,405,730,0001,694,410,000840,598287,154,000
mceliece6960119f1,311,130,000942,987,000984,660303,543,000
mceliece81921281,635,550,000760,619,000428,112361,999,000
mceliece8192128f1,772,530,0001,222,720,000534,503392,729,000

测试是在联想Thinkpad x260(Intel Core i5-6200U CPU @ 2.30GHz)上进行的。对于rust,使用了在benches/中给出的criterion 0.3.5,对于C,使用了具有PFM支持的Google的benchmark和禁用CPU频率缩放的选项。您可以使用bench子命令运行基准测试套件,并可选地添加一些变体功能标志

$ cargo bench --features mceliece348864

为了获得最佳的基准测试结果,您可以使用以下命令运行Rust基准测试,并使用CPU优化:RUSTFLAGS="-C target-cpu=native",将Cargo基准优化配置为opt-level = 3,并将链接时间优化设置为lto = "fat"。有关Cargo基准配置的更多信息,请参阅官方的cargo基准配置文档

这是正确的吗?

是的,除了通过单元测试(由C实现派生)外,生成的KAT KEM测试文件还具有等效的MD5散列。具体如下…

变体预期的MD5散列
mceliece34886411fd67ba1e2b93cceaec6f5e6fe4ddd1
mceliece348864f7a6f5262fa013fe7eedda0765a625789
mceliece460896c9acefa82aa705cd324f12df532744c2
mceliece460896fcb08e0e3f2122c62692111d684f1cbe7
mceliece66881287e300cc0990b05f5edca3219ac769023
mceliece6688128f6d959c2bf54f7d3576a8e49475a74df5
mceliece6960119b4960a35e249d55fd48371f793608aa5
mceliece6960119f2f5d759cb579c6f85c1ee1306082ffdf
mceliece819212826a47e6d01eec28e91abfdbdf19c3067
mceliece8192128fa4cd676dc2c774d644f18de05762c51c

源代码在哪里?

github上。

内容的许可是什么?

MIT许可证

变更日志

请参阅变更日志

我可以在哪里要求您修复一个错误?

github上。

依赖项

~1.5MB
~15K SLoC