jedisct1/c-sigma
GitHub: jedisct1/c-sigma
基于 libsodium 和 Ristretto255 的 C 语言 Sigma 协议实现,提供 Schnorr、DLEQ、Pedersen 等零知识证明原语。
Stars: 17 | Forks: 0
# C 语言 Sigma 协议实现
使用 Ristretto255 完整实现 [draft-irtf-cfrg-sigma-protocols-00](https://datatracker.ietf.org/doc/draft-irtf-cfrg-sigma-protocols/)。
## 功能特性
### 协议实现
- Schnorr 协议:证明离散对数知识
- DLEQ 协议:证明离散对数相等(也称为 Chaum-Pedersen)
- Pedersen 承诺:证明承诺开启知识
- 通用框架:通过简化的 API 构建任意线性关系证明
### 能力
- 非交互式证明:使用 SHAKE128 的 Fiat-Shamir 变换
- 简单和通用框架接口
- 序列化:支持完整的编码/解码及验证
- 安全:基于 libsodium 的 Ristretto255 群运算
- 规范合规:完整实现 IETF 草案规范
## 快速开始
```
#include
#include "sigma.h"
// Initialize libsodium
sodium_init();
// Prove knowledge of private key
uint8_t private_key[CSIGMA_SCALAR_BYTES];
uint8_t public_key[CSIGMA_POINT_BYTES];
uint8_t proof[CSIGMA_SCHNORR_PROOF_SIZE];
crypto_core_ristretto255_scalar_random(private_key);
crypto_scalarmult_ristretto255_base(public_key, private_key);
uint8_t message[] = "Hello";
csigma_schnorr_prove(proof, private_key, public_key, message, sizeof(message));
bool valid = csigma_schnorr_verify(proof, public_key, message, sizeof(message));
```
## 构建
前置条件:
- C 编译器(clang 或 gcc)
- libsodium 开发库
```
# 安装 libsodium (Ubuntu/Debian)
sudo apt-get install libsodium-dev
# 安装 libsodium (macOS)
brew install libsodium
# 构建所有可执行文件
make
# 运行所有测试
make check
```
## API 参考
### 常量
```
#define CSIGMA_SCALAR_BYTES 32 // Scalar size
#define CSIGMA_POINT_BYTES 32 // Group element size
#define CSIGMA_SCHNORR_PROOF_SIZE 64 // Schnorr proof size
#define CSIGMA_DLEQ_PROOF_SIZE 96 // DLEQ proof size
#define CSIGMA_PEDERSEN_PROOF_SIZE 96 // Pedersen proof size
```
### Schnorr 协议
证明知道满足 Y = x*G 的 x(G 是生成元)。
```
// Create proof
int csigma_schnorr_prove(
uint8_t proof[CSIGMA_SCHNORR_PROOF_SIZE], // Output: 64-byte proof
const uint8_t witness[CSIGMA_SCALAR_BYTES], // Secret x
const uint8_t public_key[CSIGMA_POINT_BYTES], // Public Y = x*G
const uint8_t *message, // Message to bind
size_t message_len
);
// Returns: 0 on success, -1 on error
// Verify proof
bool csigma_schnorr_verify(
const uint8_t proof[CSIGMA_SCHNORR_PROOF_SIZE],
const uint8_t public_key[CSIGMA_POINT_BYTES],
const uint8_t *message,
size_t message_len
);
// Returns: true if valid, false otherwise
```
### DLEQ 协议
在不泄露指数的情况下证明 log_g1(h1) = log_g2(h2)。
```
// Create proof
int csigma_dleq_prove(
uint8_t proof[CSIGMA_DLEQ_PROOF_SIZE], // Output: 96-byte proof
const uint8_t witness[CSIGMA_SCALAR_BYTES], // Secret x where h1=g1^x, h2=g2^x
const uint8_t g1[CSIGMA_POINT_BYTES], const uint8_t h1[CSIGMA_POINT_BYTES],
const uint8_t g2[CSIGMA_POINT_BYTES], const uint8_t h2[CSIGMA_POINT_BYTES],
const uint8_t *message,
size_t message_len
);
// Returns: 0 on success, -1 on error
// Verify proof
bool csigma_dleq_verify(
const uint8_t proof[CSIGMA_DLEQ_PROOF_SIZE],
const uint8_t g1[CSIGMA_POINT_BYTES], const uint8_t h1[CSIGMA_POINT_BYTES],
const uint8_t g2[CSIGMA_POINT_BYTES], const uint8_t h2[CSIGMA_POINT_BYTES],
const uint8_t *message,
size_t message_len
);
// Returns: true if valid, false otherwise
```
### Pedersen 承诺
```
// Create commitment C = x*G + r*H
int csigma_pedersen_commit(
uint8_t commitment[CSIGMA_POINT_BYTES],
const uint8_t value[CSIGMA_SCALAR_BYTES],
const uint8_t randomness[CSIGMA_SCALAR_BYTES],
const uint8_t G[CSIGMA_POINT_BYTES],
const uint8_t H[CSIGMA_POINT_BYTES]
);
// Prove knowledge of opening
int csigma_pedersen_prove(
uint8_t proof[CSIGMA_PEDERSEN_PROOF_SIZE],
const uint8_t value[CSIGMA_SCALAR_BYTES],
const uint8_t randomness[CSIGMA_SCALAR_BYTES],
const uint8_t G[CSIGMA_POINT_BYTES],
const uint8_t H[CSIGMA_POINT_BYTES],
const uint8_t C[CSIGMA_POINT_BYTES],
const uint8_t *message,
size_t message_len
);
// Verify proof
bool csigma_pedersen_verify(
const uint8_t proof[CSIGMA_PEDERSEN_PROOF_SIZE],
const uint8_t G[CSIGMA_POINT_BYTES],
const uint8_t H[CSIGMA_POINT_BYTES],
const uint8_t C[CSIGMA_POINT_BYTES],
const uint8_t *message,
size_t message_len
);
```
## 何时使用各个协议
### Schnorr 协议
证明内容:在不泄露秘密值(离散对数)的情况下证明知道该值。
数学属性:证明“我知道满足 Y = x*G 的 x”,其中 G 是生成元,Y 是公开的。
用途:
- 数字签名:证明你拥有与公钥对应的私钥
- 身份验证:登录服务而无需传输密码
- 加密货币钱包:在不泄露私钥的情况下证明资金所有权
- 访问控制:在不暴露凭证的情况下证明你拥有凭证
- 密码认证密钥交换 (PAKE):基于密码建立安全通道
示例场景:Alice 想要证明她拥有一个比特币地址。她使用 Schnorr 协议证明她知道与该公开地址对应的私钥,而无需泄露私钥本身。
### DLEQ 协议
证明内容:在不泄露公共指数的情况下,证明两个离散对数相等。
数学属性:证明“log_g1(h1) = log_g2(h2)”或等价地证明存在某个秘密 x 满足“h1 = g1^x 且 h2 = g2^x”。
用途:
- 可验证加密:证明密文加密了特定值而无需解密
- 匿名凭证:证明两个凭证属于同一用户而不泄露身份
- 混合网络:在隐私协议中证明正确重加密
- 跨链原子交换:证明多笔交易中使用了同一秘密
- 可验证洗牌:证明列表被正确置换而不泄露置换方式
- 盲签名:证明盲化和非盲化值之间的一致性
示例场景:投票系统需要证明在混合阶段加密的选票被正确重加密(相同选票,不同随机性),而无需泄露实际选票。
## 协议对比
| 方面 | Schnorr | DLEQ (Chaum-Pedersen) |
| ------------- | --------------------------- | ----------------------------- |
| 证明大小 | 64 字节 | 96 字节 |
| 证明内容 | 知道一个秘密值 | 两个离散对数相等 |
| 复杂度 | 较简单 | 较复杂 |
| 计算量 | 验证需 2 次指数运算 | 验证需 4 次指数运算 |
| 主要用途 | 认证、签名 | 可验证加密、DLEQ |
## API 层级
### 简单 API
用于常见协议的便捷函数(推荐大多数用户使用):
- `csigma_schnorr_prove()` / `csigma_schnorr_verify()`
- `csigma_dleq_prove()` / `csigma_dleq_verify()`
- `csigma_pedersen_prove()` / `csigma_pedersen_verify()`
### 框架 API - 简化构建器(推荐)
使用易于使用的辅助工具构建任意线性关系证明:
```
// Add elements and scalars in one step
int G = csigma_relation_add_element(&relation, generator);
int X = csigma_relation_add_element(&relation, public_key);
int x = csigma_relation_add_scalar(&relation);
// Add equation with single term (covers 80% of use cases)
csigma_relation_add_equation_simple(&relation, X, x, G);
// Prove and verify
csigma_prover_commit(&relation, witness, commitment, &state);
csigma_prover_response(&state, challenge, response);
bool valid = csigma_verify(&relation, commitment, challenge, response);
```
### 框架 API - 通用(用于复杂多项式方程)
用于形如 C = x*G + r*H 的方程:
```
// Allocate multiple scalars/elements at once
int x = csigma_relation_allocate_scalars(&relation, 1);
int r = csigma_relation_allocate_scalars(&relation, 1);
// Add elements
int G = csigma_relation_add_element(&relation, G_value);
int H = csigma_relation_add_element(&relation, H_value);
// Multi-term equation
int scalar_indices[] = {x, r};
int element_indices[] = {G, H};
csigma_relation_add_equation(&relation, C, scalar_indices, element_indices, 2);
```
### 序列化 API
```
// Serialize proof
int csigma_serialize_proof(
uint8_t *output,
const uint8_t *commitment,
size_t num_commitment_elements,
const uint8_t *response,
size_t num_response_scalars
);
// Deserialize proof (with validation)
int csigma_deserialize_proof(
uint8_t *commitment,
size_t num_commitment_elements,
uint8_t *response,
size_t num_response_scalars,
const uint8_t *data,
size_t data_len
);
// Calculate expected proof size
size_t csigma_proof_size(size_t num_commitment_elements, size_t num_response_scalars);
```
有关使用简化 API 的框架完整示例,请参见 `tests/test_framework.c`。
## 实现细节
- 椭圆曲线群:Ristretto255(通过 libsodium)
- 哈希函数:用于 Fiat-Shamir 挑战的 SHAKE128
- 证明大小:
- Schnorr:64 字节(1 个承诺 + 1 个响应)
- DLEQ:96 字节(2 个承诺 + 1 个响应)
- Pedersen:96 字节(1 个承诺 + 2 个响应)
- 安全性:128 位安全级别
- 命名空间:所有公开函数均以 `csigma_` 为前缀
- 错误处理:
- Prove/create 函数成功时返回 0,错误时返回 -1
- Verify 函数有效时返回 true,否则返回 false
## 示例
请参阅以下文件以获取完整的工作示例:
- `example.c` - 简单 API 演示
- `tests/test_framework.c` - 简化框架 API 用法
- `tests/test_sigma.c` - Schnorr 和 DLEQ 测试
- `tests/test_pedersen.c` - Pedersen 承诺测试
标签:DLEQ, Fiat-Shamir变换, IETF标准, libsodium, Pedersen承诺, Ristretto255, Schnorr协议, SHAKE128, Sigma协议, 加密库, 客户端加密, 密码学, 手动系统调用, 椭圆曲线, 离散对数, 网络安全, 隐私保护, 零知识证明, 非交互式证明