Skip to content

crypto-intrinsics #730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/crypto-intrinsics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: crypto-intrinsics

on:
pull_request:
paths:
- "crypto-intrinsics/**"
- "Cargo.*"
push:
branches: master

defaults:
run:
working-directory: crypto-intrinsics

env:
CARGO_INCREMENTAL: 0
RUSTFLAGS: "-Dwarnings"

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.59.0 # MSRV
target:
- thumbv7em-none-eabi
- wasm32-unknown-unknown
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
override: true
- run: cargo build --target ${{ matrix.target }} --release

test:
strategy:
matrix:
include:
# 32-bit Linux
- target: i686-unknown-linux-gnu
platform: ubuntu-latest
rust: 1.59.0 # MSRV
deps: sudo apt update && sudo apt install gcc-multilib

# 64-bit Linux
- target: x86_64-unknown-linux-gnu
platform: ubuntu-latest
rust: 1.59.0 # MSRV

# 64-bit Windows
- target: x86_64-pc-windows-msvc
platform: windows-latest
rust: 1.59.0 # MSRV

runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
profile: minimal
override: true
- run: ${{ matrix.deps }}
- run: cargo test --release
2 changes: 1 addition & 1 deletion .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: RustCrypto/actions/cargo-cache@master
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.51.0 # Highest MSRV in repo
toolchain: 1.59.0 # Highest MSRV in repo
components: clippy
override: true
profile: minimal
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"block-buffer",
"collectable",
"cpufeatures",
"crypto-intrinsics",
"dbl",
"hex-literal",
"opaque-debug",
Expand Down
21 changes: 21 additions & 0 deletions crypto-intrinsics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "crypto-intrinsics"
description = """
High-level wrappers for architecture-specific CPU intrinsics which are relevant
to cryptographic use cases, such as the CMOV family, implemented using stable
inline assembly
"""
version = "0.0.0"
authors = ["RustCrypto Developers"]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/RustCrypto/utils/tree/master/crypto-intrinsics"
categories = ["cryptography"]
keywords = ["crypto", "cmov", "intrinsics"]
readme = "README.md"
edition = "2018" # Can't bump to 2021 due to pre-1.56 MSRV crates in the same workspace
rust-version = "1.59"
Copy link
Member

@newpavlov newpavlov Feb 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to use 2021 edition and the separate workspace trick for now? It's already done for the inout crate.

Copy link
Member Author

@tarcieri tarcieri Feb 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That approach is really annoying from a maintenance perspective, since each crate gets its own Cargo.lock and therefore needs its own dependabot config (although that's admittedly not really a problem here).

I'd rather attempt the "delete the toplevel Cargo.toml" trick if we were to do that, but this crate is so simple it doesn't really derive any benefits from being 2021 edition.


[package.metadata.docs.rs]
all-features = true
all-targets = true
rustdoc-args = ["--cfg", "docsrs"]
75 changes: 75 additions & 0 deletions crypto-intrinsics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# [RustCrypto]: CPU Intrinsics

[![Crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
![Apache 2.0/MIT Licensed][license-image]
![MSRV][rustc-image]
[![Build Status][build-image]][build-link]

High-level wrappers for architecture-specific CPU intrinsics which are not
yet provided via [`core::arch`], implemented using inline assembly.

[Documentation]

## About

Certain CPU instructions which are important for cryptographic applications
are difficult to emit from LLVM due to various complicating factors.

This crate provides high-level architecture-specific wrappers for these
instructions built on stable inline assembly. No attempts at abstraction
are made, just raw access to specific CPU instructions which are guaranteed
to be emitted verbatim and not optimized away or otherwise rewritten by the
compiler.

## Supported Instructions

### `x86` (32-bit)

- `cmovz` (a.k.a. `cmove`)
- `cmovnz` (a.k.a. `cmovne`)

### `x86_64`

- `cmovz` (a.k.a. `cmove`)
- `cmovnz` (a.k.a. `cmovne`)

## Minimum Supported Rust Version

Rust **1.59** or newer.

In the future, we reserve the right to change MSRV (i.e. MSRV is out-of-scope
for this crate's SemVer guarantees), however when we do it will be accompanied by
a minor version bump.

## License

Licensed under either of:

* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* [MIT license](http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

[//]: # (badges)

[crate-image]: https://img.shields.io/crates/v/crypto-intrinsics.svg
[crate-link]: https://crates.io/crates/crypto-intrinsics
[docs-image]: https://docs.rs/crypto-intrinsics/badge.svg
[docs-link]: https://docs.rs/crypto-intrinsics/
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.51+-blue.svg
[build-image]: https://github.com/RustCrypto/utils/actions/workflows/crypto-intrinsics.yml/badge.svg
[build-link]: https://github.com/RustCrypto/utils/actions/workflows/crypto-intrinsics.yml

[//]: # (general links)

[RustCrypto]: https://github.com/RustCrypto
[Documentation]: https://docs.rs/crypto-intrinsics
[`core::arch`]: https://doc.rust-lang.org/core/arch/index.html
16 changes: 16 additions & 0 deletions crypto-intrinsics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]

#[cfg(target_arch = "x86")]
#[cfg_attr(docsrs, doc(cfg(target_arch = "x86")))]
pub mod x86;

#[cfg(target_arch = "x86_64")]
#[cfg_attr(docsrs, doc(cfg(target_arch = "x86_64")))]
pub mod x86_64;
62 changes: 62 additions & 0 deletions crypto-intrinsics/src/x86.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//! `x86` intrinsics (32-bit)

use core::arch::asm;

/// Move if zero.
///
/// Uses a `test` instruction to check if the given `condition` value is
/// equal to zero, then calls `cmovz` (a.k.a. `cmove`) to conditionally move
/// `src` to `dst` when `condition` is equal to zero.
#[inline(always)]
pub fn cmovz(condition: u32, src: u32, dst: &mut u32) {
unsafe {
asm! {
"test {0}, {0}",
"cmovz {1}, {2}",
in(reg) condition,
inlateout(reg) *dst,
in(reg) src
};
}
}

/// Move if not zero.
///
/// Uses a `test` instruction to check if the given `condition` value is not
/// equal to zero, then calls `cmovnz` (a.k.a. `cmovne`) to conditionally move
/// `src` to `dst` when `condition` is nonzero.
#[inline(always)]
pub fn cmovnz(condition: u32, src: u32, dst: &mut u32) {
unsafe {
asm! {
"test {0}, {0}",
"cmovnz {1}, {2}",
in(reg) condition,
inlateout(reg) *dst,
in(reg) src
};
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn cmovz_works() {
let mut n = 24;
cmovz(42, 42, &mut n);
assert_eq!(n, 24);
cmovz(0, 42, &mut n);
assert_eq!(n, 42);
}

#[test]
fn cmovnz_works() {
let mut n = 24;
cmovnz(0, 42, &mut n);
assert_eq!(n, 24);
cmovnz(42, 42, &mut n);
assert_eq!(n, 42);
}
}
62 changes: 62 additions & 0 deletions crypto-intrinsics/src/x86_64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//! `x86_64` intrinsics

use core::arch::asm;

/// Move if zero.
///
/// Uses a `test` instruction to check if the given `condition` value is
/// equal to zero, then calls `cmovz` (a.k.a. `cmove`) to conditionally move
/// `src` to `dst` when `condition` is equal to zero.
#[inline(always)]
pub fn cmovz(condition: u64, src: u64, dst: &mut u64) {
unsafe {
asm! {
"test {0}, {0}",
"cmovz {1}, {2}",
in(reg) condition,
inlateout(reg) *dst,
in(reg) src
};
}
}

/// Move if not zero.
///
/// Uses a `test` instruction to check if the given `condition` value is not
/// equal to zero, then calls `cmovnz` (a.k.a. `cmovne`) to conditionally move
/// `src` to `dst` when `condition` is nonzero.
#[inline(always)]
pub fn cmovnz(condition: u64, src: u64, dst: &mut u64) {
unsafe {
asm! {
"test {0}, {0}",
"cmovnz {1}, {2}",
in(reg) condition,
inlateout(reg) *dst,
in(reg) src
};
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn cmovz_works() {
let mut n = 24;
cmovz(42, 42, &mut n);
assert_eq!(n, 24);
cmovz(0, 42, &mut n);
assert_eq!(n, 42);
}

#[test]
fn cmovnz_works() {
let mut n = 24;
cmovnz(0, 42, &mut n);
assert_eq!(n, 24);
cmovnz(42, 42, &mut n);
assert_eq!(n, 42);
}
}
2 changes: 2 additions & 0 deletions dbl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ pub trait Dbl {
/// `block<<1`, otherwise `(block<<1)^C`, where `C` is the non-leading
/// coefficients of the lexicographically first irreducible degree-b binary
/// polynomial with the minimal number of ones.
#[must_use]
fn dbl(self) -> Self;

/// Reverse double block. (alternatively: divbide block by x)
///
/// If least significant bit of the block equals to zero will return
/// `block>>1`, otherwise `(block>>1)^(1<<n)^(C>>1)`
#[must_use]
fn inv_dbl(self) -> Self;
}

Expand Down
1 change: 1 addition & 0 deletions wycheproof2blb/src/aes_siv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct TestSuite {

#[derive(Debug, Deserialize)]
struct TestGroup {
#[allow(dead_code)]
#[serde(flatten)]
pub group: wycheproof::Group,
#[serde(rename = "keySize")]
Expand Down
4 changes: 4 additions & 0 deletions wycheproof2blb/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ struct TestSuite {

#[derive(Debug, Deserialize)]
struct TestGroup {
#[allow(dead_code)]
#[serde(flatten)]
pub group: wycheproof::Group,
#[allow(dead_code)]
#[serde(rename = "keyDer")]
pub key_der: String,
#[allow(dead_code)]
#[serde(rename = "keyPem")]
pub key_pem: String,
pub sha: String,
Expand All @@ -27,6 +30,7 @@ struct TestGroup {
#[derive(Debug, Deserialize)]
struct TestKey {
curve: String,
#[allow(dead_code)]
#[serde(rename = "type")]
key_type: String,
#[serde(with = "hex_string")]
Expand Down
3 changes: 3 additions & 0 deletions wycheproof2blb/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ struct TestSuite {

#[derive(Debug, Deserialize)]
struct TestGroup {
#[allow(dead_code)]
#[serde(flatten)]
pub group: wycheproof::Group,
#[allow(dead_code)]
#[serde(rename = "keyDer")]
pub key_der: String,
#[allow(dead_code)]
#[serde(rename = "keyPem")]
pub key_pem: String,
pub key: TestKey,
Expand Down
Loading