27次发布
0.10.0 | 2024年2月19日 |
---|---|
0.9.1 | 2023年7月12日 |
0.9.0 | 2023年5月8日 |
0.8.2 | 2022年12月16日 |
0.1.5 | 2020年7月29日 |
#1332 in 魔豆
13,432 每月下载量
用于 4 crates
330KB
6K SLoC
secp256kFUN!
这是一个中级Rust secp256k1椭圆曲线密码学库,针对娱乐进行了优化!这里的“娱乐”意味着
- 类型安全:使用其他API时通常必须处理的错误情况,通过Rust的类型系统在编译时就被排除了。
- 抽象化:该库公开了两个简单的抽象 点 和 标量,以便您可以干净地实现加密。
- 不可优化:在群上表达某种操作的最直接方式也是最有效的方式。
- 文档化:我们试图为每个函数制作工作示例并对其进行文档化。
娱乐并不意味着(目前还没有 — 请帮助!)
- 未经过充分审查:这里的实现尚未得到很多审查。
- 抵抗侧信道攻击:尚未对是否该库或其底层的算术(来自 k256)抵抗时间攻击等进行实证研究。《strong>没有尝试在释放内存时“归零”秘密。
- 性能:该库在总体上不如 libsecp256k1。
本库的目标是让研究人员能够实验想法,让他们在比特币上工作,并享受这个过程!像 rust-secp256k1 这样的 高级 库使得正确和高效地实现异构加密方案变得困难。而像 parity/libsecp256k1 这样的 低级 库虽然可行,但生成的代码往往容易出错且难以阅读。
使用
[dependencies]
secp256kfun = "0.10"
应该使用?
只要你的目标是制造有趣和娱乐性的东西,这个库就适用于生产。如果你想设计一些稳定的东西,很多人会依赖它,那么这个库可能是一个风险选择。以下是一些替代方案
- rust-secp256k1 - Bitcoin 本身使用的 libsecp256k1 的 rust 绑定
- k256 - 该库的算术默认基于此库。
- ristretto - 如果你不需要使用 secp256k1
文档
特性
以下是本库的显著特性。
零元素
secp256k1 点和标量都有一个概念上的 零 元素。不幸的是,在围绕比特币的东西中,零标量和零点在大多数情况下都是非法值。《secp256kfun》通过使用 标记类型 解决这些困难。点和标量在编译时用 Zero
或 NonZero
标记(默认为 NonZero
)。因此,如果你用 NonZero
类型声明你的函数,传递一个 Zero
类型将会在编译时出错,如下所示
use secp256kfun::{marker::*, Scalar, Point,G,g};
// a randomly selected Scalar will never be zero (statistically unreachable)
let x = Scalar::random(&mut rand::thread_rng());
dbg!(&x); // Scalar<.., NonZero>
// Multiplying a NonZero scalar by G (which is also NonZero) results in a NonZero point
let X = g!(x * G);
dbg!(&X) // Point<..,NonZero>
let Y = g!(-x * G)
// An addition **can** lead to a zero so the result is marked Zero
let sum = g!(X + Y);
dbg!(&sum); // Point<.., Zero>
// Now let's say I naively decide to use this value as my public key...
let public_key = sum.normalize();
// BOOM! This is a compile time Error! 🎉
send_pubkey_to_bob(&public_key);
fn send_pubkey_to_bob(public_key: &Point) {
unimplemented!()
}
这给了我们
error[E0308]: mismatched types
--> src/lib.rs:77:20
|
17 | send_pubkey_to_bob(&public_key);
| ^^^^^^^^^^^ expected struct `secp256kfun::marker::NonZero`, found struct `secp256kfun::marker::Zero`
为了解决这个问题,库会强制你手动将值标记为 NonZero
,然后处理它为零的情况。
match sum.normalize().non_zero() {
Some(public_key) => send_pubkey_to_bob(&public_key), // it was actually NonZero
None => .. // deal with the case it is Zero
}
变量时间还是常数时间?
注意:从 v0.7.0
版本开始,由于我们更改了算术后端到 k256,因此 Secret
和 Public
标记几乎不起作用,因为 k256 没有变量时间算法。然而,这种情况可能在未来的版本中有所改善。
如果加密函数的执行时间应该与其秘密输入无关。否则,有关这些输入的信息可能会泄露给任何能够测量其执行时间的人。
在 secp256kfun 中,我们试图通过允许你将不同的输入标记为 Public
或 Secret
来解决这个问题。根据标记,rust 编译器可能会选择不同的底层操作。为 Public
输入选择更快的但变量时间操作,为标记为 Secret
的事物选择更慢但更安全的常数时间操作。换句话说,调用者可以决定哪些输入是
例如,以下是一个 pedersen_commitment
函数,它由提交方用秘密值调用,并由验证方在最终揭示秘密值时调用。请注意,我们只需要编写一次函数,而调用者通过标记来决定该函数是否应以常数时间或变量时间运行。
use secp256kfun::{marker::*, Point, Scalar, g};
/// commit to a secret value x with publicly known A and B.
fn pedersen_commit(
A: &Point<impl PointType>, // Accept any kind of Point
B: &Point<impl PointType>,
r: &Scalar<impl Secrecy>, // Accept a Secret or Public Scalar
x: &Scalar<impl Secrecy, Zero>, // Allow commitment to Zero
) -> Point {
// Make the commitment
g!(r * A + x * B)
.normalize()
// If the result is zero we could easily compute the discrete
// logarithm of B with respect to A. Since this is meant to be unknown
// this is computionally unreachable.
.non_zero().expect("computationally unreachable")
}
// public setup
let A = secp256kfun::G; // use the standard basepoint for one of the points
let B = Point::random(&mut rand::thread_rng());
// Alice commits to her secret value x with randomness r
let r = Scalar::random(&mut rand::thread_rng());
let x = Scalar::<Secret, Zero>::from(42);
let commitment = pedersen_commit(A, &B, &r, &x);
// Imagine Later on, Bob receives the public opening (r,x) for commitment. He
// doesn't care about leaking these values via execution time so he marks them
// as public.
let r = r.public();
let x = x.public();
// Now he'll compute the commitment in faster variable time and check it
// against the original
assert_eq!(commitment, pedersen_commit(A, &B, &r, &x));
特性
- 内置类型安全的“仅 x”点压缩和解压缩。
- 用于清晰表达群操作的算术表达式宏
g!
和s!
(如上所示)。 - nonce 导出 API,以帮助避免出错。
no_std
支持(仅禁用默认的std
功能)- 功能标志
serde
序列化和反序列化二进制和十六进制(十六进制解码需要alloc
功能)bincode
直接实现了bincode
的Encode
/Decode
/BorrowDecode
特性libsecp_compat
为 rust-secp256k1 类型添加了从和到From
的实现。- 使用
proptest
特性实现核心类型
MSRV
最低支持的 Rust 版本是 v1.63
。
许可协议
代码在 0BSD
许可下发布,但 secp256kfun/src/vendor
目录下的代码除外,在那里您可以找到供应商代码的许可协议。
依赖项
~0.4–2MB
~31K SLoC