5个版本
0.1.4 | 2024年6月2日 |
---|---|
0.1.3 | 2023年5月8日 |
0.1.2 | 2023年4月19日 |
0.1.1 | 2023年4月19日 |
0.1.0 | 2023年4月16日 |
#37 in 密码学
175,361 每月下载量
在 339 个crate中使用 (3直接使用)
205KB
3K SLoC
bls
Boneh-Lynn-Shacham (BLS)签名具有慢速签名、非常慢的验证速度、需要慢速且安全性较低的配对友好曲线,并且容易受到危险的模态影响。然而,BLS允许比任何其他已知签名方案更多的签名聚合选项,这使得BLS成为共识算法中投票和门限签名的首选方案。
在这个crate中,我们采用了对BLS签名聚合技术和验证器优化的大致统一方法:我们通过Arkworks traits支持BLS12-381和BLS12-377(Barreto-Lynn-Scott)曲线,但抽象化配对,以便开发者可以选择他们喜欢的BLS签名方向。我们提供了基于消息唯一性、占位证明和反线化的聚合技术,尽管我们并没有提供所有已知反线化的优化。
我们提供了基于Schnorr签名生成和验证占位证明的实现,这比使用BLS签名本身进行此任务更快。
我们无法宣称这些抽象提供了误用抵抗,但它们至少结构化了问题,提供了一些指导,并最大化了文档中存在的警告的相关性。
文档
您首先像平常一样将bls
crate引入到您的项目中。
use w3f_bls::{Keypair,ZBLS,Message,Signed};
let mut keypair = Keypair::<ZBLS>::generate(::rand::thread_rng());
let message = Message::new(b"Some context",b"Some message");
let sig = keypair.sign(&message);
assert!( sig.verify(&message,&keypair.public) );
在这个例子中,sig
是一个只包含签名的Signature<ZBLS>
,可以使用Keypair::signed_message
方法,该方法返回一个包含消息哈希、签名者的公钥以及当然签名的SignedMessage
结构,但通常应该将这些组成部分解耦以适应网络格式。
聚合签名和盲签名几乎是人们考虑使用BLS签名的主要原因,因此我们在此重点关注聚合签名。为了简化,我们假设sigs
是一个SignedMessage
数组的实例,就像人们可能构建的那样:
通常,需要不同消息的聚合仍然需要每个消息一个Miller循环步骤,因此聚合签名的验证时间相对较慢。但您仍然可以实现非常小的签名大小,例如:
#[cfg(feature = "experimental")]
use w3f_bls::{distinct::DistinctMessages, Keypair, Message, Signed, ZBLS};
#[cfg(feature = "experimental")]
{
let mut keypairs = [
Keypair::<ZBLS>::generate(::rand::thread_rng()),
Keypair::<ZBLS>::generate(::rand::thread_rng()),
];
let msgs = [
"The ships",
"hung in the sky",
"in much the same way",
"that bricks don’t.",
]
.iter()
.map(|m| Message::new(b"Some context", m.as_bytes()))
.collect::<Vec<_>>();
let sigs = msgs
.iter()
.zip(keypairs.iter_mut())
.map(|(m, k)| k.signed_message(m))
.collect::<Vec<_>>();
let dms = sigs
.iter()
.try_fold(DistinctMessages::<ZBLS>::new(), |dm, sig| dm.add(sig))
.unwrap();
let signature = <&DistinctMessages<ZBLS> as Signed>::signature(&&dms);
let publickeys = keypairs.iter().map(|k| k.public).collect::<Vec<_>>();
let mut dms = msgs
.into_iter()
.zip(publickeys)
.try_fold(
DistinctMessages::<ZBLS>::new(),
|dm, (message, publickey)| dm.add_message_n_publickey(message, publickey),
)
.unwrap();
dms.add_signature(&signature);
assert!(dms.verify())
}
任何收到已聚合签名、消息列表和公钥的人都可以像上面示例中那样重建签名。
我们主要推荐使用这种不同消息聚合方法来验证持有证明,这意味着检查大量密钥的自我证书。
假设您已经拥有持有证明,那么您将希望使用BitPoPSignedMessage
或针对您的用例调整的变体进行聚合。我们建议在使用SignatureAggregatorAssumingPoP
时要更加小心,因为它不提供检查持有证明表的机制。
该库提供了基于BLS和Schnorr签名生成和验证持有证明的方法,后者比使用BLS签名本身作为持有证明更快。以下示例演示了如何生成和验证持有证明,然后使用SignatureAggregatorAssumingPoP
批量验证多个BLS签名。
use w3f_bls::{Keypair,PublicKey,ZBLS,Message,Signed, ProofOfPossessionGenerator, ProofOfPossession, schnorr_pop::{SchnorrPoP}, multi_pop_aggregator::MultiMessageSignatureAggregatorAssumingPoP};
use sha2::Sha256;
let mut keypairs = [Keypair::<ZBLS>::generate(::rand::thread_rng()), Keypair::<ZBLS>::generate(::rand::thread_rng())];
let msgs = ["The ships", "hung in the sky", "in much the same way", "that bricks don’t."].iter().map(|m| Message::new(b"Some context", m.as_bytes())).collect::<Vec<_>>();
let sigs = msgs.iter().zip(keypairs.iter_mut()).map(|(m,k)| k.sign(m)).collect::<Vec<_>>();
let publickeys = keypairs.iter().map(|k|k.public.clone()).collect::<Vec<_>>();
let pops = keypairs.iter_mut().map(|k|(ProofOfPossessionGenerator::<ZBLS, Sha256, PublicKey<ZBLS>, SchnorrPoP<ZBLS>>::generate_pok(k))).collect::<Vec<_>>();
//first make sure public keys have valid pop
let publickeys = publickeys.iter().zip(pops.iter()).map(|(publickey, pop) | {assert!(ProofOfPossession::<ZBLS, Sha256, PublicKey<ZBLS>>::verify(pop,publickey)); publickey}).collect::<Vec<_>>();
let batch_poped = msgs.iter().zip(publickeys).zip(sigs).fold(
MultiMessageSignatureAggregatorAssumingPoP::<ZBLS>::new(),
|mut bpop,((message, publickey),sig)| { bpop.add_message_n_publickey(message, &publickey); bpop.add_signature(&sig); bpop }
);
assert!(batch_poped.verify())
如果您缺乏持有证明,则可以在delinear
模块中提供非线化方法,但这些方案可能需要更定制化的方法。但是请注意,目前只维护基于持有证明的聚合,其他策略是实验性的。
基于Chaum-Pedersen证明的高效可聚合BLS签名
我们在我们最近的论文
中介绍的计划在chaum_pederson_signature.rs
中实现,使用ChaumPedersonSigner
和ChaumPedersonVerifier
特质,并在pop.rs
中使用add_auxiliary_public_key
和verify_using_aggregated_auxiliary_public_keys
函数进行演示。
use sha2::Sha256;
use ark_bls12_377::Bls12_377;
use ark_ff::Zero;
use rand::thread_rng;
use w3f_bls::{
single_pop_aggregator::SignatureAggregatorAssumingPoP, DoublePublicKeyScheme, EngineBLS, Keypair, Message, PublicKey, PublicKeyInSignatureGroup, Signed, TinyBLS, TinyBLS377,
};
let message = Message::new(b"ctx", b"I'd far rather be happy than right any day.");
let mut keypairs: Vec<_> = (0..3)
.into_iter()
.map(|_| Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(thread_rng()))
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| k.into_public_key_in_signature_group())
.collect();
let mut prover_aggregator =
SignatureAggregatorAssumingPoP::<TinyBLS377>::new(message.clone());
let mut aggregated_public_key =
PublicKey::<TinyBLS377>(<TinyBLS377 as EngineBLS>::PublicKeyGroup::zero());
//sign and aggegate
let _ = keypairs
.iter_mut()
.map(|k| {
prover_aggregator.add_signature(&k.sign(&message));
aggregated_public_key.0 += k.public.0;
})
.count();
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new(message);
verifier_aggregator.add_signature(&(&prover_aggregator).signature());
//aggregate public keys in signature group
verifier_aggregator.add_publickey(&aggregated_public_key);
pub_keys_in_sig_grp.iter().for_each(|pk| {verifier_aggregator.add_auxiliary_public_key(pk);});
assert!(
verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifying with honest auxilary public key should pass"
);
散列到曲线
为了对消息进行签名,库需要将消息散列为签名曲线上的一个点。尽管BLSEngine
特质对MapToSignatureCurve
方法不敏感,但我们BLS12-381(ZBLS
)和BLS12-377(BLS377
)的实现专门使用Wahby和Boneh散列到曲线方法,该方法在https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/的第6.6.3节中描述。
安全警告
此库不对恒等时间操作、内存访问模式或对旁路攻击的抵抗力做出任何保证。
许可
根据您的选择,许可如下:
- Apache License,版本2.0(LICENSE-APACHE或https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT或http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义的,您有意提交以包含在您的工作中的任何贡献,均应如上双许可,而不附加任何额外条款或条件。
依赖
~7.5MB
~125K SLoC