cuPQC 使用#

本文档全面概述了 NVIDIA® CUDA® 后量子密码学库 cuPQC。cuPQC 旨在利用 NVIDIA GPU 的并行处理能力,提供后量子密码算法的高性能、批量化和安全实现。具体来说,该库包括 NIST 标准化的两种后量子密码算法:ML-KEM 和 ML-DSA。

cuPQC 的基本用法#

使用 cuPQC 的第一步是定义我们希望执行的 PQC 操作。我们通过将 cuPQC 运算符 相加来指定我们的操作,从而形成PQC 描述符。一个定义良好的 cuPQC 描述符必须包括算法安全类别密码学函数块维度

作为一个例子,我们说明如何为 ML-KEM-512 的密钥生成函数构建 cuPQC 描述符。

//cuPQC header
#include <cupqc.hpp>

//cuPQC descriptor
// ML KEM 512 Key Generation with 128 threads
using MLKEM512Key = decltype(ML_KEM_512()
                           + Function<function::Keygen>()
                           + Block()
                           + BlockDim<128>());

执行 cuPQC#

这些 cuPQC 描述符类型在用户内核内部实例化为对象。形成此对象没有计算成本,应作为句柄使用。cuPQC 描述符对象提供了一个计算方法,execute(...) 此函数执行请求的 PQC 函数。此方法的参数取决于 PQC 函数和 PQC 算法,请参阅 方法 API 参考

为了演示 cuPQC 的执行,我们将继续之前的示例,并编写一个用于批量密钥生成操作的内核——每个线程块将计算一个公钥和私钥

//cuPQC header
#include <cupqc.hpp>

//cuPQC descriptor
// ML KEM 512 Key Generation with 128 threads
using MLKEM512Key = decltype(ML_KEM_512()
                           + Function<function::Keygen>()
                           + Block()
                           + BlockDim<128>());

__global__ void keygen_kernel(uint8_t* public_keys, uint8_t* secret_keys, uint8_t* workspace, uint8_t* randombytes)
{
   // These functions require a fixed amount of shared memory, for which the API provides a trait
    __shared__ uint8_t smem_ptr[MLKEM512Key::shared_memory_size];
    int block = blockIdx.x;
    auto public_key = public_keys + block * MLKEM512Key::public_key_size;
    auto secret_key = secret_keys + block * MLKEM512Key::secret_key_size;
    auto entropy    = randombytes + block * MLKEM512Key::entropy_size;
    auto work       = workspace   + block * MLKEM512Key::workspace_size;

    MLKEM512Key().execute(public_key, secret_key, entropy, work, smem_ptr);
}

keygen_kernel 中,每个块计算一个 public_keysecret_key。许多 cuPQC 算法需要构建额外的全局内存工作区,以及预填充的密码学熵缓冲区。下一节将介绍分配这些变量的技术。

启动 cuPQC 内核#

为了在内部启动带有 cuPQC API 的内核,我们需要知道块大小和所需的全局内存工作区大小。这些由我们之前构建的 cuPQC 描述符固定。在主机代码中,我们有 API 函数 调用,这些调用从 cuPQC 描述符模板化而来,这些 API 调用提供了全局内存工作区以及熵变量。

void ml_kem_keygen(std::vector<uint8_t> public_keys, std::vector<uint8_t> secret_keys, const unsigned int batch)
{
    /*
     * Set up for utilizing cuPQC ML-KEM Keygen.
     * Allocates device workspace for computing
     */
    auto length_public_key = MLKEM512Key::public_key_size;
    auto length_secret_key = MLKEM512Key::secret_key_size;

    auto workspace         = make_workspace<MLKEM512Key>(batch);
    auto randombytes       = get_entropy<MLKEM512Key>(batch);
    /*
     * Allocate device memory for public and secret keys
     */
    uint8_t* d_public_key = nullptr;
    uint8_t* d_secret_key = nullptr;

    cudaMalloc(d_public_key, length_public_key * batch); //These are uint8_t so length and batch are in bytes
    cudaMalloc(d_secret_key, length_secret_key * batch);

    keygen_kernel<<<batch, MLKEM512Key::BlockDim>>>(d_public_key, d_secret_key, workspace, randombytes);

    /*
     * Transfer generated keys to the host for communication or storage
     */
    cudaMemcpy(public_keys.data(), d_public_key, length_public_key * batch, cudaMemcpyDeviceToHost);
    cudaMemcpy(secret_keys.data(), d_secret_key, length_secret_key * batch, cudaMemcpyDeviceToHost);

    /*
     * Delete device memory associated with the cryptograpic process.
     */
    cudaFree(d_public_key);
    cudaFree(d_secret_key);
    destroy_workspace(workspace);
    release_entropy(randombytes);
}

编译#

为了编译包含 cupqc.hpp 以及 cuPQC API 的程序,用户需要传递 cuPQC 标头的位置,并链接提供的静态库。有关如何在您的项目中使用 cuPQC 的详细信息,请参阅 快速安装指南。cuPQC API 利用了 NVIDIA 的链接时优化 (LTO),因此我们需要在编译时使用适当的标志。

nvcc -std=c++17 -dlto -arch=sm_80 -L<path_to_static_lib> -lcupqc -I<path_to_cupqc_include> -I<path_to_commondx> -o intro_example

有关当前支持的功能的更多信息,请参阅要求和功能