#secret-sharing #fss #crypto #dcf #dpf

nightly fss-rs

Function secret sharing including distributed comparison & point functions

4 releases

new 0.4.3 Apr 10, 2024
0.4.2 Apr 9, 2024
0.4.1 Jan 28, 2024
0.4.0 Jan 27, 2024

#298 in Cryptography

Download history 3/week @ 2024-01-26 10/week @ 2024-02-16 17/week @ 2024-02-23 4/week @ 2024-03-01 26/week @ 2024-03-29 154/week @ 2024-04-05

180 downloads per month




Crates.io docs.rs

Function secret sharing including distributed comparison & point functions

Get started

First add the crate as a dependency:

# Run in your project directory
cargo add fss-rs

By default the embedded PRG and multi-threading are included. You can disable the default feature to select by yourself. If you are on ARM machines, see the Performance section for hardware acceleration.

Then construct a PRG implementing the corresponding Prg trait, and construct an impl DcfImpl or DpfImpl to use the PRG. Check the doc comment for the meanings of the generic parameters.

use rand::prelude::*;

use fss_rs::dcf::prg::Aes256HirosePrg;
use fss_rs::dcf::{Dcf, DcfImpl};

let keys: [[u8; 32]; 2] = thread_rng().gen();
let prg = Aes256HirosePrg::<16, 2>::new(std::array::from_fn(|i| &keys[i]));
// DCF for example
let dcf = DcfImpl::<16, 16, _>::new(prg);

Finally, for key generation, construct the function to be shared together with 2 init keys, and call gen:

use fss_rs::dcf::{BoundState, CmpFn};
use fss_rs::group::byte::ByteGroup;
use fss_rs::group::Group;

let s0s: [[u8; 16]; 2] = thread_rng().gen();
let f = CmpFn {
  alpha: thread_rng().gen(),
  // `ByteGroup` for example
  beta: ByteGroup(thread_rng().gen()),
  bound: BoundState::LtBeta,
let keys = dcf.gen(&f, [&s0s[0], &s0s[1]]);

See the doc comment of the returned Share for how to split it into 2 shares. The 2 shares are combined like this because they share many fields.

And for evaluation, construct the evaluated points, reverse the output buffer, and call eval:

let x: [u8; 16] = thread_rng().gen();
let mut y = ByteGroup::zero();
// The 2 parties use `true` / `false` to evaluate independently
dcf.eval(false, &k, &[&x], &mut [&mut y]);

For full domain evaluation, use full_eval instead. While similar to eval, full_eval does not accept a vector of x, and instead expect a vector of y whose length is 2 ** (N * 8) to store all evaluated y.

More examples are available as benchmarks in the benches dir



The hot path of the project is PRG and xor operations. We use Rust std SIMD for xor operations and the aes crate of RustCrypto for PRG.

For PRG, enabling archtecture-specified CPU intrinsics can largely boost the performance. The aes crate by default performs runtime detection of CPU intrinsics and uses them if available.

For x86/x86_64 (i686/x86_64 in targets), AES-NI is used if available, which works out-of-the-box.

For ARMv8 (aarch64 in targets), while ARMv8 Cryptography Extensions is supported, to use it, in addition to the above, you need to set some flags to enable it. See the doc of the aes crate for details We also quote the section here:

From https://docs.rs/aes/0.8.3/aes/#armv8-intrinsics-rust-161

ARMv8 intrinsics (Rust 1.61+)

On aarch64 targets including aarch64-apple-darwin (Apple M1) and Linux targets such as aarch64-unknown-linux-gnu and aarch64-unknown-linux-musl, support for using AES intrinsics provided by the ARMv8 Cryptography Extensions is available when using Rust 1.61 or above, and can be enabled using the aes_armv8 configuration flag.

On Linux and macOS, when the aes_armv8 flag is enabled support for AES intrinsics is autodetected at runtime. On other platforms the aes target feature must be enabled via RUSTFLAGS.


We use Criterion.rs for benchmarking. Criterion.rs reports criterion.tar.zst are included in releases.

We use a (my) laptop as the benchmarking machine. It is charged to 100% with the power plugged in when benchmarking. Its CPU is AMD Ryzen 7 5800H with Radeon Graphics, which is 8C16T. We use rayon as the data-parallelism library, which establishes 16 threads when benchmarking with multithreading. We ensure that its memory is enough for benchmarking, which is 16GB and has more than 5GB left when benchmarking. Notice that we do not close all other programs as many as possible to reduce scheduling, though we do avoid doing any other thing at the same time.


crate::dcf::prg::Aes256HirosePrg (enabled by default by the prg feature, and only this one) has wrong implementation. It is fixed in version 0.4.3 of crate fss-rs, versions 0.5.1 and 0.6.2 of crate dcf, and version 0.5.1 of crate dpf-fss.


Copyright (C) myl7

SPDX-License-Identifier: Apache-2.0


~31K SLoC