#sigma #protocols #proof #combinator #traits #hash #random

无std sigma_fun

一个让Sigma协议变得有趣的框架!

14个版本

0.7.0 2024年2月19日
0.6.0 2023年5月8日
0.5.1 2022年12月16日
0.4.1 2022年5月6日
0.1.1 2020年12月18日

673密码学 中排名

Download history 114/week @ 2024-03-13 12/week @ 2024-03-20 20/week @ 2024-03-27 35/week @ 2024-04-03 5/week @ 2024-04-10 8/week @ 2024-04-17 121/week @ 2024-05-22 237/week @ 2024-05-29 73/week @ 2024-06-05 211/week @ 2024-06-12 266/week @ 2024-06-19 46/week @ 2024-06-26

658 每月下载量
用于 ecdsa_fun

0BSD 许可证

165KB
3K SLoC

SigmaFUN! crates_badge docs_badge

一个用于让Sigma协议变得有趣的Rust库!

使用

[dependencies]
# For just the traits and combinators
sigma_fun = {version = "0.6", no-default-features = true, features = ["alloc"]}
# To create secp256k1 non-interactive proofs and serialize them
sigma_fun = { version = "0.6", features = ["secp256k1", "serde", "alloc"] }
# you need a hash function and an rng for non-interactive proofs
rand_chacha = "0.3"
sha2 = "0.10"

应该使用吗?

API和证明的向后兼容性可能随时发生高度实验性和破坏性更改。

尤其是在 ext 模块中更复杂的证明中,很容易出现实现错误!

"Sigma" 协议

Sigma协议是三轮的 诚实验证者零知识协议,是最基本的零知识证明系统之一。由于它们可以通过Fiat-Shamir启发式方法轻松地非交互式化,并且支持各种类型的 组合,因此它们非常有用。Sigma协议可用于构建签名方案、可验证随机函数、身份验证方案、匿名凭证方案以及许多其他奇特的东西。

有关Sigma协议的基本背景,请参阅Shoenmaker的出色讲义的第5节:Shoenmaker

组合

Sigma协议可以安全地组合在一起,形成一个新的Sigma协议。例如,如果您有两个用于证明陈述 AB 的Sigma协议,则可以将它们组合成用于证明 A or B 的协议。生成的协议也将是一个Sigma协议!目前这个库支持以下组合子

  • or(A,B) 证明两个陈述中至少有一个是真的。
  • and(A,B) 证明两个陈述都是真的。
  • eq(A,B) 证明两个陈述具有相同的证据(通常 AB 是相同类型的证明)。
  • all(n,A) 证明了类型为 An 个语句都是真实的。
  • eq-all(n,A) 证明了类型为 An 个语句都具有相同的证明。

我们缺少对泛化证明 t-of-m 语句是否为真的支持(这要复杂得多)。遗憾的是,目前 alleq-all 中的 n 必须在编译时已知。

《Sigma》特质

此库提供了一个 Sigma 特质,可以为任何 Sigma 协议实现,无论其底层证明结构如何。任何实现了 Sigma 的内容都可以与组合子一起使用,以创建更复杂的 Sigma 协议。最后,可以通过实现 serde 序列化特质,将协议非交互化。

我们使用五个主要核心函数定义了 Sigma 特质

  • gen_announce_secret(rng) -> announce_secret:从给定的随机数生成器 rng 生成用于证明的随机秘密值。

  • announce(statement, announce_secret) -> announcement:给定要证明的语句以及之前由 announcement_secret 生成的 announce_secret,返回一个 announcement

  • implied_announcement(statement, challenge, response) -> announcement:确定一个 announcement,使得 (statement, announcement, challenge, response, challenge) 是 sigma 协议的一个有效的转储。

  • sample_response(rng) -> response:从响应空间中均匀抽取响应。

  • respond(witness, statement, announce_secret, announcement, challenge) -> response:计算对 challenge 的有效响应。

每个 Sigma 协议还定义了其 ChallengeLength 作为关联类型。

使用这些算法,交互式 Sigma 协议的执行过程如下

Prover(witness, statement, rng)                                                 Verifier(statement)
======
announce_secret = gen_announce_secret(rng)
announcement = announce(statement, announce_secret)
                                                      announcement
                                                  +------------------->
                                                       challenge         *uniformly sample ChallengeLength bytes*
                                                  <-------------------+
response = respond(witness, statement,
                   announce_secret, announcement,
                   challenge)

                                                       response
                                                  +------------------->
                                                                                            check
                                                                        implied_announcement(statement, challenge, response)
                                                                                              ==
                                                                                         announcement

非交互式证明

使 Sigma 协议非交互式的一种标准技巧是从哈希函数中生成上图中的 challenge。这被称为 Fiat-Shamir 启发式,在 随机预言机模型 中是安全的。验证者只需检查哈希是否正确计算以及响应是否正确。

示例

佩德森承诺的形式为 C = r * G + c * H,其中 c 是对 h 的一个值所做的承诺,且 H = h * G 对承诺者来说是未知的。关于佩德森承诺的背景,请参阅 Shoenmaker 第 3.2.2 节。假设我们想向只知道 C 的人证明 c 要么为 0 要么为 1,我们可以通过展示我们知道 r 使得 C = r * GC - H = r * G 来构造一个非交互式证明。

use std::string::ToString;
use sigma_fun::{ typenum::U16, FiatShamir, HashTranscript, Either, Or, secp256k1::{ self, fun::{Point, Scalar, G, marker::*, g}}};
use sha2::Sha256;
use rand_chacha::ChaCha20Rng;

// Pretend to choose H securely in a public setup
let H = Point::random(&mut rand::thread_rng());
// our commitment will be to 1
let c = Scalar::<Secret, _>::from(1u32);
// We use a 16-byte (128-bit) challenge length
type L = U16;

let (C,r) = {
    // make a pedersen commitment
    let r = Scalar::random(&mut rand::thread_rng());
    let C = g!(r * G + c * H).normalize().non_zero().expect("zero is computationally unreachable");
    (C,r)
};

// Our strategy is to prove that we know r such that either C = r * G or C - H = r * G using
// an OR composition between two standard knowledge of discrete logarithm proofs.
let statement = (C, g!(C - H).normalize().non_zero().expect("computationally unreachable"));
// since we are commiting to 1 we know the witness for the right hand side statement.
let witness =  Either::Right(r);

// Our prover is going to prove knowledge of one of two point to the base G (either C or C - H).
type Protocol = Or::<secp256k1::DLG<L>, secp256k1::DLG<L>>;

// Every protocol has an unambiguous name which is hashed into the transcript for protocol separation purposes.
assert_eq!(Protocol::default().to_string(), "or(DLG(secp256k1),DLG(secp256k1))");
// we want a non-interactive proof system so we apply the Fiat-Shamir transform with Sha256 as the challenge hash.
// We use ChaCha20Rng to help produce our announcement.
let proof_system  = FiatShamir::<Protocol, HashTranscript<Sha256, ChaCha20Rng>>::default();

// Make the non-interactive proof -- pass in a system rng to make the proof more robust.
let proof = proof_system.prove(&witness, &statement, Some(&mut rand::thread_rng()));

// The verifier gets sent (C, proof)
{
    // The verifier's proof system doesn't need the rng
    let proof_system = FiatShamir::<Protocol, HashTranscript<Sha256>>::default();
    // They recreate the statement
    let statement = (C, g!(C - H).normalize().non_zero().expect("bogus commitment"));
    // and verify it against the proof
    assert!(proof_system.verify(&statement, &proof));
    // The verifier is convinced of the statement and nothing else
}

功能标志

  • ed25519:启用 ed25519 离散对数证明
  • secp256k1:启用 secp256k1 离散对数证明(使用 [secp256kfun])

另请参阅

  • ZKP — 该库受到该库的启发,并且发展得更好。 zkp 对散列函数(sha3)和群(ristretto)有看法,并且只支持 eqand 类型组合。

依赖关系

~0.3–1.7MB
~28K SLoC