#constant-time #benchmark #constant #crypto

dudect-bencher

DudeCT常时函数测试器的实现

8个版本 (5个破坏性更新)

0.6.0 2023年9月18日
0.5.0 2022年8月26日
0.4.1 2019年9月8日
0.4.0 2019年4月14日
0.1.0 2017年7月7日

#963 in 密码学

每月45次下载

MIT/Apache

33KB
489

dudect-bencher

Version Docs

这个crate实现了测试函数是否为常时函数的DudeCT统计方法。它是基于bencher基准测试框架的。

通常,不可能证明一个函数总是以常时运行。这个工具的目的在于找到存在非常时的情况。这并不容易,需要用户非常仔细地思考非常时可能存在的地方。

导入和功能

要导入此crate,请在您的Cargo.toml文件中添加以下行

dudect-bencher = "0.6"

此crate暴露的功能标志

  • core-hint-black-box(默认)— 启用一个新的最佳努力优化屏障(core::hint::black_box)。如果您使用的Rust版本小于1.66,则无法编译。

使用方法

此框架构建了一个独立的二进制文件。因此,您必须定义一个main.rs文件,或您的src/bin目录中的一个文件,或者一个单独的二进制crate,该crate包含您要测试的库。

在高级上,您通过首先定义两个输入集到函数f,称为Right和Left来测试函数f。您选择这些输入的方式非常主观。您需要已经有一个关于可能引起非常时行为的想法。然后,您填充Left和Right集合,使得(您认为)f(l)f(r)将花费不同的平均时间运行,其中l来自Left,r来自Right。最后,运行基准测试并标记哪个集合是哪个。

以下是一个测试等价函数的例子:v == u,其中vu是相同长度的Vec<u8>。这显然不是一个常数时间函数。我们定义左分配为一个集合(v, u),其中v == u,右分配是集合(v, u),其中v[6] != u[6]

use dudect_bencher::{ctbench_main, BenchRng, Class, CtRunner};
use rand::{Rng, RngCore};

// Return a random vector of length len
fn rand_vec(len: usize, rng: &mut BenchRng) -> Vec<u8> {
    let mut arr = vec![0u8; len];
    rng.fill(arr.as_mut_slice());
    arr
}

// Benchmark for equality of vectors. This does an early return when it finds an
// inequality, so it should be very much not constant-time
fn vec_eq(runner: &mut CtRunner, rng: &mut BenchRng) {
    // Make vectors of size 100
    let vlen = 100;
    let mut inputs: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
    let mut classes = Vec::new();

    // Make 100,000 random pairs of vectors
    for _ in 0..100_000 {
        // Flip a coin. If true, make a pair of vectors that are equal to each
        // other and put it in the Left distribution
        if rng.gen::<bool>() {
            let v1 = rand_vec(vlen, rng);
            let v2 = v1.clone();
            inputs.push((v1, v2));
            classes.push(Class::Left);
        }
        // Otherwise, make a pair of vectors that differ at the 6th element and
        // put it in the right distribution
        else {
            let v1 = rand_vec(vlen, rng);
            let mut v2 = v1.clone();
            v2[5] = 7;
            inputs.push((v1, v2));
            classes.push(Class::Right);
        }
    }

    for (class, (u, v)) in classes.into_iter().zip(inputs.into_iter()) {
        // Now time how long it takes to do a vector comparison
        runner.run_one(class, || u == v);
    }
}

// Crate the main function to include the bench for vec_eq
ctbench_main!(vec_eq);

这是examples/ctbench-foo.rs示例代码的一部分。要运行示例,请执行

cargo run --release --example ctbench-foo

更多命令行参数见下文

基准测试输出

程序输出如下

bench array_eq ... : n == +0.046M, max t = +61.61472, max tau = +0.28863, (5/tau)^2 = 300

解释如下。首先请注意,运行时分布在不同百分位数被裁剪,并进行了大约100次t检验。在这些t检验中,产生最大绝对t值的那个打印为max_t。其他打印的值包括

  • n,表示计算此t值使用的样本数量
  • max_tau,这是根据样本大小缩放的t值(正式上,max_tau = max_t / sqrt(n)
  • (5/tau)^2,表示区分两个分布需要测量的数量,其中t > 5

大于5的t值通常被认为是函数不是常数时间的良好指标。小于5的t值并不一定意味着函数是常数时间,因为在某些输入分布下,函数的行为可能显著不同。

命令行参数

  • --filter运行包含特定字符串的基准测试子集。例如
cargo run --release --example ctbench-foo -- --filter ar

将只运行包含子字符串ar的基准测试,即arith,而不是vec_eq

  • --continuous持续运行基准测试,随着运行收集更多样本。例如
cargo run --release --example ctbench-foo -- --continuous vec_eq

将连续运行vec_eq基准测试。

  • --out以CSV格式输出原始运行时间。例如
cargo run --release --example ctbench-foo -- --out data.csv

将输出所有在ctbench-foo.rs中的基准测试到data.csv

许可证

根据您的选择,许可以下其中之一

依赖项

~2–10MB
~89K SLoC