7个版本 (4个重大更新)
新 0.5.0 | 2024年8月14日 |
---|---|
0.4.0 | 2024年5月22日 |
0.3.0 | 2024年4月24日 |
0.2.2 | 2024年4月11日 |
0.1.0 | 2024年1月8日 |
#342 in 密码学
每月 170 次下载
在 4 个crate中使用 (3个直接使用)
75KB
893 代码行
jubjub-schnorr
此crate提供了JubJub椭圆曲线组的Schnorr签名方案的Rust实现,使用Poseidon哈希函数。此实现由Dusk团队设计。
关于
Schnorr签名方案,以其创建者Claus Schnorr的名字命名,是一种以简单著称的数字签名方案。该方案提供了一种创建短签名的简单方法。
该实现使用了jubjub
椭圆曲线和Poseidon
哈希函数,其论文可在此处找到。
签名方案是在Phoenix事务模型中实现的,基于Schnorr Sigma协议,并编译了Fiat–Shamir变换,作为非交互式签名方案。具体来说,Phoenix协议使用了一种变体,该变体利用双Schnorr签名,可以使用双公钥进行验证,从而在协议的后期阶段实现计算过程的委托。
该仓库还包括了此处描述的基于Schnorr的SpeedyMuSig多签名方案的实现(第19页)。它允许多个签名者创建一个签名,该签名证明消息是由他们所有人签署的,前提是他们提供了公钥。该签名可以使用用于标准Schnorr签名的相同函数进行验证,使用所有签名者的公钥之和。
库结构
该库分为以下组件
- 密钥:包含用于签名消息的私钥结构,以及用于验证的公钥和双公钥结构。
- 签名:包含标准签名和双签名结构,以及验证Schnorr签名和双Schnorr签名的函数。
- 小工具:包含用于电路中验证Schnorr签名和双Schnorr签名的Plonk小工具。
签名方案描述
符号表示
以下
- 一个点$P$乘以标量$s$表示将$P$加到自身$s$次。
- $\mathbb{F}_q$是阶为$q$的素数有限域
- 对于素数$q$:$\mathbb{F}_q^× = \mathbb{F}_q \setminus 0$包含$\mathbb{F}_q$中的所有非零元素。
单签名
设置
在此库中,我们实现了基于 jubjub 椭圆曲线的 Schnorr 签名方案,具体来说,我们有
- 一个有限域$\mathbb{F}_q$,其上的素数为$q$,在此实现中,此域对应于椭圆曲线BLS12-381的标量域
- 一个椭圆曲线$E / \mathbb{F}_q$,在我们的情况下,这是 jubjub 椭圆曲线
- 一个曲线点子群$\mathbb{G} \in E(\mathbb{F}_q)$,其阶为素数$p$
- 一个固定生成点$G \in \mathbb{G}$
- 一个加密哈希函数$H : {0 , 1}^∗ \rightarrow \mathbb{F}_p$,其中$\mathbb{F}_p$是 jubjub 椭圆曲线的标量域。
密钥生成
- 选择一个私钥签名密钥$sk \in \mathbb{F}_p^×$。
- 公钥验证密钥是$PK = skG \in \mathbb{G}$。
签名
要对消息$m \in \mathbb{F}_q^×$进行签名
- 选择一个随机的私钥随机数$r \in \mathbb{F}_p^×$。
- 计算随机数点$R = rG \in \mathbb{G}$。
- 计算挑战哈希$c = H(R \parallel PK \parallel m) \in \mathbb{F}_p$,其中$\parallel$表示连接,$R$表示为一个位字符串。
- 计算$u = r − sk \cdot c \in \mathbb{F}_p$。
签名是元组$(u, R) \in \mathbb{F}_p \times \mathbb{G}$。
验证
- 计算挑战哈希$c = H(R \parallel PK \parallel m) \in \mathbb{F}_p$。
- 验证$uG + cPK = R$。
如果签名是用与$PK$对应的秘密密钥签名的,这将成立,因为
$$ uG + cPK = (r - sk\cdot c)G + (sk\cdot c)G = (r - sk\cdot c + sk\cdot c)G = rG = R $$
双签名
设置
与上面的单签名相同,增加了一个不同的生成点$G' \in \mathbb{G}$,该点不同于$G$,且其与$G$的离散对数关系未知。
密钥生成
- 选择一个私钥签名密钥$sk \in \mathbb{F}_p^×$。
- 公钥验证密钥是元组$(PK, PK')$,其中$PK = skG \in \mathbb{G}$,$PK' = skG' \in \mathbb{G}$。
签名
要对消息$m \in \mathbb{F}_q^×$进行签名
- 选择一个随机的私钥随机数$r \in \mathbb{F}_p^×$。
- 计算随机数点$R = rG \in \mathbb{G}$和$R' = rG' \in \mathbb{G}$。
- 计算挑战哈希$c = H(R \parallel R' \parallel PK \parallel m) \in \mathbb{F}_p$,其中$\parallel$表示连接,$R, R'$表示为位字符串。
- 计算$u = r − sk \cdot c \in \mathbb{F}_p$。
签名是元组$(u, R, R') \in \mathbb{F}_p \times \mathbb{G} \times \mathbb{G}$。
验证
- 计算挑战哈希$c = H(R \parallel R' \parallel PK \parallel m) \in \mathbb{F}_p$。
- 验证$rG + cPK = R$和$uG' + cPK' = R'$。
如果签名是用正确的私钥签名的,这应该成立,因为
$$ uG + cPK = (r - sk\cdot c)G + (sk\cdot c)G = (r - sk\cdot c + sk\cdot c)G = rG = R $$
和
$$ uG' + cPK' = (r - sk\cdot c)G' + (sk\cdot c)G' = (r - sk\cdot c + sk\cdot c)G' = rG' = R' $$
关于安全和实现的注释
在随机预言模型下,该签名方案在选言攻击下是存在性不可伪造的,前提是离散对数问题的困难性。这一性质在 Katz 和 Lindell 的《现代密码学导论》第12.5.1节中有详细说明。
虽然基本的 Schnorr 签名方案是一个广泛认可的构造,但 Phoenix 所采用的双密钥变体是一个新颖的引入。在交易协议的背景下,这允许在不泄露签名者秘密密钥的机密性的情况下委派证明计算。
使用
要将 jubjub-schnorr
包集成到您的项目中,请使用以下命令
cargo add jubjub-schnorr
一个基本示例,演示如何生成和验证Schnorr签名
use dusk_bls12_381::BlsScalar;
use jubjub_schnorr::{SecretKey};
use rand::rngs::StdRng;
use rand::SeedableRng;
use ff::Field;
fn main() {
// Setup
let mut rng = StdRng::seed_from_u64(1234u64);
let message = BlsScalar::random(&mut rng);
// Key generation
let sk = SecretKey::random(&mut rng);
// Standard Schnorr signature scheme:
use jubjub_schnorr::PublicKey;
let pk = PublicKey::from(&sk);
let signature = sk.sign(&mut rng, message);
assert!(pk.verify(&signature, message).is_ok(), "The signature should be valid.");
// Double Dusk-Schnorr signature scheme:
use jubjub_schnorr::PublicKeyDouble;
let pk = PublicKeyDouble::from(&sk);
let signature = sk.sign_double(&mut rng, message);
assert!(pk.verify(&signature, message).is_ok(), "The signature should be valid.");
// Dusk-Schnorr signature scheme with variable generator:
use dusk_jubjub::{GENERATOR_EXTENDED, JubJubScalar};
use jubjub_schnorr::PublicKeyVarGen;
let generator = GENERATOR_EXTENDED * JubJubScalar::from(42u64);
let sk = sk.with_variable_generator(generator);
let pk = PublicKeyVarGen::from(&sk);
let signature = sk.sign(&mut rng, message);
assert!(pk.verify(&signature, message).is_ok(), "The signature should be valid.");
}
许可
此源代码形式受Mozilla公共许可证第2.0版条款约束。如果此文件未附带Mozilla公共许可证副本,您可以在http://mozilla.org/MPL/2.0/获取一份。
版权(c)DUSK NETWORK。保留所有权利。
依赖项
~4.5MB
~100K SLoC