如何将C编写的Python扩展模块导入C++项目实现无缝调用?
实现方案
你提到的Dilithium实现核心逻辑为纯C编写,外层仅通过Python C API做了语言绑定,只要剥离绑定层就可以直接在C++项目中无缝调用,不需要依赖Python环境。
方案1:剥离Python绑定层直接复用核心源码(推荐,无额外依赖)
这是最符合你预期使用方式的方案,操作步骤如下:
- 提取核心算法文件:进入对应源码目录,筛除所有包含Python C API调用的封装文件(特征是代码中存在
PyObject、PyMODINIT_FUNC、PyArg_ParseTuple这类Python专属标识符),剩下的.c、.h文件就是无依赖的Dilithium算法原生实现,直接拷贝到你的C++项目目录中即可。 - 处理C/C符号兼容:C编译时会对符号名做改编,引入C实现的头文件时需要用
extern "C"包裹,避免链接时找不到符号:
#ifdef __cplusplus extern "C" { #endif // 引入算法核心头文件 #include "dilithium/api.h" #ifdef __cplusplus } #endif
- 直接调用原生接口:该参考实现遵循NIST后量子密码算法的标准API规范,核心功能直接调用三个对应函数即可:
crypto_sign_keypair(unsigned char *pk, unsigned char *sk):生成密钥对,pk为写入公钥的缓冲区,sk为写入私钥的缓冲区,缓冲区长度直接使用头文件中定义的CRYPTO_PUBLICKEYBYTES(公钥长度)、CRYPTO_SECRETKEYBYTES(私钥长度)宏。crypto_sign(unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen, const unsigned char *sk):签名接口。crypto_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk):验签接口。
你预期的公钥生成调用示例代码如下:
#include <iostream> #include <vector> #ifdef __cplusplus extern "C" { #endif #include "dilithium/api.h" #ifdef __cplusplus } #endif int main() { // 按算法规定长度分配公钥、私钥字节容器 std::vector<unsigned char> public_key(CRYPTO_PUBLICKEYBYTES); std::vector<unsigned char> secret_key(CRYPTO_SECRETKEYBYTES); // 调用C接口生成密钥对 int res = crypto_sign_keypair(public_key.data(), secret_key.data()); if (res != 0) { std::cerr << "密钥生成失败" << std::endl; return 1; } // 此时public_key中存储的就是字节格式的公钥,可直接使用 std::cout << "公钥生成完成,长度为" << public_key.size() << "字节" << std::endl; return 0; }
编译时把你拷贝过来的所有核心算法.c文件加入编译列表即可,不需要链接额外依赖。
方案2:不剥离源码的替代方案
如果你不想手动筛选剥离源码,可以选择以下两种方式,但都存在明显缺陷:
- 嵌入Python解释器调用:在C++项目中初始化Python运行时,通过Python C API加载该扩展模块,再调用对应功能。该方案会让你的程序强制依赖完整Python运行时,程序体积、启动开销都会明显上升,不推荐。
- 编译动态库导出接口:直接把整个目录的源码编译为动态库,手动写导出声明绕开Python模块初始化逻辑。该方案操作量和剥离核心源码差不多,还容易残留Python相关的未定义符号,性价比很低。
注意:该目录下的代码是Dilithium的参考实现,没有做编译优化和跨平台适配,如果用于生产环境,建议替换为对应平台的官方优化版实现,二者API完全兼容,不需要修改上层调用代码。
内容的提问来源于stack exchange,提问作者user19316228
相关产品推荐
相关产品推荐

