15个稳定版本
1.5.0 | 2023年10月26日 |
---|---|
1.3.2 | 2022年11月20日 |
1.2.1 | 2022年5月31日 |
1.1.1 | 2022年2月22日 |
1.0.0 | 2020年6月30日 |
#1458 in 神奇豆子
286,062每月下载量
用于 588 个crate(51直接使用)
320KB
6K SLoC
ethnum
此crate提供256位整数的实现,这是以太坊中的原生整数类型。这种实现旨在尽可能接近Rust原生整数类型,实现相同的方法和特性。
使用方法
将以下内容添加到您的 Cargo.toml
ethnum = "1"
API尽可能遵循Rust {i,u}N
原生类型。
宏
此crate提供基于 const fn
的宏,用于256位整数字面量。这使得您可以指定大于最大原生整数字面量(对于有符号整数是 i128::MIN 和
i128::MAX
,对于无符号整数是 u128::MAX
)的256位有符号和无符号整数字面量(例如,可以用作 const
)。
int!("-57896044618658097711785492504343953926634992332820282019728792003956564819968");
int!("57896044618658097711785492504343953926634992332820282019728792003956564819967");
uint!("115792089237316195423570985008687907853269984665640564039457584007913129639935");
请注意,这些字面量支持前缀(二进制:0b
,八进制:0o
,十六进制:0x
)以及 _
和空白分隔符。
int!("-0b1010101010101010101010101010101010101010101010101010101010101010
0101010101010101010101010101010101010101010101010101010101010101");
int!("0o 0123 4567");
uint!("0xffff_ffff");
特性
宏
使用 macros
功能原本可以通过过程宏启用 256 位整数字面量。然而,现在这个 crate 使用 const fn
实现这些宏,因此该功能已被弃用,并且宏现在是始终可用的。为了不破坏语义版本控制,该功能仍然存在,但将在版本 2
中被移除。
serde
serde
功能添加了对 serde
序列化和反序列化的支持。默认情况下,256 位整数类型被序列化为带前缀的十六进制字符串。还提供了各种序列化助手,以便更精细地控制序列化的执行方式。
内联函数
256 位整数使用基于两种实现的内联函数
原生 Rust 实现
整数内联函数使用标准 Rust 实现。更复杂的操作,如乘法和除法,是从 C 编译器的内联函数移植过来的,用于在 64 位系统(或 32 位系统上的 64 位操作)上实现等效的 128 位操作。一般来说,这些是从 Clang 的 compiler-rt
支持例程移植过来的。
这是 crate 使用的默认实现,一般来说优化得很好。在使用原生实现时,此 crate 不需要额外的依赖项。
LLVM 生成实现
或者,ethnum
可以使用 LLVM 生成的内联函数来执行基 256 位整数操作。这利用了 LLVM IR 支持任意大小的整数操作(例如,@llvm.uadd.with.overflow.i256
用于溢出无符号加法)。这将产生更优化的汇编代码,例如加法和乘法。
然而,使用 LLVM 生成的内联函数也有一些缺点。首先,需要 Clang 来编译 LLVM IR。此外,Rust 通常在编译和链接 Rust 代码时进行优化(而不是外部链接的代码),这意味着这些内联函数不能内联,这会在某些情况下增加额外的函数调用开销,使得其性能不如原生 Rust 实现,尽管汇编代码更优化。幸运的是,Rust 当前支持链接器插件 LTO,以便在链接步骤中进行优化,使得使用 Clang 编译的 LLVM IR 可以进行优化。
为了使用 LLVM 生成的内联函数,请启用 llvm-intrinsics
功能
ethnum = { version = "1", features = ["llvm-intrinsics"] }
并且,通常最好启用 linker-plugin-lto
以充分利用优化后的汇编代码
RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build
注意,必须使 clang
版本与 rustc
LLVM 版本相匹配。如果不匹配,则在运行 ethnum-intrinsics
构建脚本时可能会遇到错误。您可以使用以下命令验证 rustc
使用的 LLVM 版本
rustc --version --verbose | grep LLVM
特别是,这影响了 macOS,它自带其自己的 clang
二进制文件。ethnum-intrinsics
构建脚本接受一个 CLANG
环境变量来指定要使用的特定 clang
可执行文件路径。使用上述命令中的主要 LLVM 版本
brew install llvm@${LLVM_VERSION}
CLANG=/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin/clang cargo build
API 稳定性
内联函数在 ethnum::intrinsics
下导出。话虽如此,在直接使用这些内联函数时请谨慎。对于这些内联函数中的任何一项,都不能保证语义版本控制的 API 兼容性。
如果您要在项目中使用这些,建议使用严格的版本控制
[dependencies]
ethnum = "=x.y.z"
这将确保如cargo update
之类的命令不会更改ethnum
依赖项的版本。
基准测试
ethnum-bench
crate实现了针对整数内建的criterion
基准测试。
cargo bench -p ethnum-bench
RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo bench -p ethnum-bench --features llvm-intrinsics
模糊测试
ethnum-fuzz
crate实现了AFL模糊测试目标(以及一些用于与cargo afl
一起工作的实用工具)。内部,它将256位有符号整数类型转换为num::BigInt
,并以其操作实现作为参考。
为了开始模糊测试
cargo install --force cargo-afl
cargo run -p ethnum-fuzz --bin init target/fuzz
cargo afl build -p ethnum-fuzz --bin fuzz
cargo afl fuzz -i target/fuzz/in -o target/fuzz/out target/debug/fuzz
为了重放崩溃
cargo run -p ethnum-fuzz --bin dump target/fuzz/out/default/crashes/FILE
依赖项
~175KB