From a6b473fa2566b60ebae20f1398537d942f72e745 Mon Sep 17 00:00:00 2001 From: myl7 Date: Tue, 30 Jul 2024 19:25:56 +0800 Subject: [PATCH] Support stable Rust with features Update CI to test in stable Rust. --- .github/workflows/ci.yaml | 13 +++++--- Cargo.lock | 26 +++++++++++++++ Cargo.toml | 5 +-- rust-toolchain.toml | 2 -- src/lib.rs | 2 +- src/utils.rs | 70 ++++++++++++++++++++++++++++++--------- 6 files changed, 93 insertions(+), 25 deletions(-) delete mode 100644 rust-toolchain.toml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7f7d989..e34831c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,16 +8,19 @@ jobs: test: name: Test runs-on: ubuntu-latest + strategy: + matrix: + toolchain: ['nightly', 'stable'] + feat_multi_thread: ['', 'multi-thread'] steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/rust-toolchain@master with: + toolchain: ${{ matrix.toolchain }} components: rustfmt, clippy - name: Format run: cargo fmt --check - name: Lint run: cargo clippy --no-deps -- -Dwarnings - - name: Test with multithreading - run: cargo test - - name: Test without multithreading - run: cargo test --no-default-features -F prg + - name: Test + run: cargo test --no-default-features -F prg,${{ matrix.feat_multi_thread }},$(if [ "${{ matrix.toolchain }}" = "stable" ]; then echo "stable"; fi) diff --git a/Cargo.lock b/Cargo.lock index 65ce35e..f0cffe9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" + [[package]] name = "cast" version = "0.3.0" @@ -249,6 +255,7 @@ dependencies = [ "criterion", "rand", "rayon", + "wide", ] [[package]] @@ -520,6 +527,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "safe_arch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -685,6 +701,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wide" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901e8597c777fa042e9e245bd56c0dc4418c5db3f845b6ff94fbac732c6a0692" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi-util" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index 6000516..e69586b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,16 +21,17 @@ keywords = ["crypto", "fss", "dcf", "dpf"] categories = ["cryptography"] [features] -default = ["full"] -full = ["prg", "multi-thread"] +default = ["prg", "multi-thread"] prg = ["aes"] multi-thread = ["rayon"] +stable = ["wide"] int-be = [] [dependencies] bitvec = "1.0.1" aes = { version = "0.8.3", optional = true } rayon = { version = "1.7.0", optional = true } +wide = { version = "0.7.26", optional = true } [dev-dependencies] rand = { version = "0.8.5", features = ["std", "std_rng"] } diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 5d56faf..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" diff --git a/src/lib.rs b/src/lib.rs index d6a5365..8bbcccd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ //! Many variable names and the LaTeX math expressions in the doc comment are from the paper _Function Secret Sharing for Mixed-Mode and Fixed-Point Secure Computation_. -#![feature(portable_simd)] +#![cfg_attr(not(feature = "stable"), feature(portable_simd))] use group::Group; diff --git a/src/utils.rs b/src/utils.rs index 45244f4..96b574e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2023 Yulong Ming (myl7) -use std::simd::{u8x16, u8x32, u8x64}; +#[cfg(not(feature = "stable"))] +use std::simd::{u8x16, u8x32}; +#[cfg(feature = "stable")] +use wide::{i8x32, u8x16}; pub fn xor(xs: &[&[u8; BLEN]]) -> [u8; BLEN] { let mut res = [0; BLEN]; @@ -9,28 +12,65 @@ pub fn xor(xs: &[&[u8; BLEN]]) -> [u8; BLEN] { res } +/// # Safety +/// +/// Unsafe casting here is safe because: +/// +/// - Sizes of `u8` and `i8` are the same. +/// - Rust arrays are compact and contiguous in memory. +/// - Array lengths match here by slicing. pub fn xor_inplace(lhs: &mut [u8; BLEN], rhss: &[&[u8; BLEN]]) { rhss.iter().fold(lhs, |lhs, &rhs| { assert_eq!(lhs.len(), rhs.len()); let mut i = 0; while i < BLEN { let left = BLEN - i; - if left >= 64 { - let lhs_simd = u8x64::from_slice(&lhs[i..i + 64]); - let rhs_simd = u8x64::from_slice(&rhs[i..i + 64]); - lhs[i..i + 64].copy_from_slice((lhs_simd ^ rhs_simd).as_array()); - i += 64; - } else if left >= 32 { - let lhs_simd = u8x32::from_slice(&lhs[i..i + 32]); - let rhs_simd = u8x32::from_slice(&rhs[i..i + 32]); - lhs[i..i + 32].copy_from_slice((lhs_simd ^ rhs_simd).as_array()); + // if left >= 64 { + // let lhs_simd = u8x64::from_slice(&lhs[i..i + 64]); + // let rhs_simd = u8x64::from_slice(&rhs[i..i + 64]); + // lhs[i..i + 64].copy_from_slice((lhs_simd ^ rhs_simd).as_array()); + // i += 64; + // continue; + // } + if left >= 32 { + #[cfg(not(feature = "stable"))] + { + let lhs_simd = u8x32::from_slice(&lhs[i..i + 32]); + let rhs_simd = u8x32::from_slice(&rhs[i..i + 32]); + lhs[i..i + 32].copy_from_slice((lhs_simd ^ rhs_simd).as_array()); + } + #[cfg(feature = "stable")] + { + let lhs_simd = + i8x32::from(unsafe { &*(&lhs[i..i + 32] as *const [u8] as *const [i8]) }); + let rhs_simd = + i8x32::from(unsafe { &*(&rhs[i..i + 32] as *const [u8] as *const [i8]) }); + let res_simd = lhs_simd ^ rhs_simd; + lhs[i..i + 32].copy_from_slice(unsafe { + &*(res_simd.as_array_ref() as *const [i8] as *const [u8]) + }); + } i += 32; - } else if left >= 16 { - let lhs_simd = u8x16::from_slice(&lhs[i..i + 16]); - let rhs_simd = u8x16::from_slice(&rhs[i..i + 16]); - lhs[i..i + 16].copy_from_slice((lhs_simd ^ rhs_simd).as_array()); + continue; + } + if left >= 16 { + #[cfg(not(feature = "stable"))] + { + let lhs_simd = u8x16::from_slice(&lhs[i..i + 16]); + let rhs_simd = u8x16::from_slice(&rhs[i..i + 16]); + lhs[i..i + 16].copy_from_slice((lhs_simd ^ rhs_simd).as_array()); + } + #[cfg(feature = "stable")] + { + let lhs_simd = u8x16::from(&lhs[i..i + 16]); + let rhs_simd = u8x16::from(&rhs[i..i + 16]); + let res_simd = lhs_simd ^ rhs_simd; + lhs[i..i + 16].copy_from_slice(res_simd.as_array_ref()); + } i += 16; - } else { + continue; + } + { // Since a AES block is 16 bytes, and we usually use AES to construct the PRG, // no need to specially handle the case where OUT_BLEN % 16 != 0. // So we just xor them one by one in case wired situations make the program enter here.