Skip to content

Commit d420293

Browse files
committed
bitref: bit-level reference types
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is constructable from `&[u8]` but provides slicing at the granularity of individual bits. The name of the crate is a play on `bitvec`, which provides a similar type. However, the implementation in this crate is significantly simpler with a much smaller code surface and minimal use of `unsafe` code. The implementation is a generalization of RustCrypto/formats#2300 which sought to implement a similar data structure as a reference type for representing ASN.1 BIT STRINGs. However, using this approach was deferred because the implementation relies on a conversion which is sound under Tree Borrows (as verified by Miri) but unsound under Stacked Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134 There are several places such a data structure is potentially useful for RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING use case, being able to iterate over bits is useful in many numerical algorithms with applications in cryptography, notably in `crypto-bigint` and for elliptic curves. Elliptic curve scalar multiplication is generally implemented as a loop over the bits of a scalar. Having an iterator type for this purpose avoids problems relating to the endianness of how scalars are serialized when implementing generic scalar multiplication algorithms, e.g. wNAF (see RustCrypto/group#12). Given the current open soundness story, I'm not rushing to use this in `crypto-bigint` until that changes. Where we could use it today though is as an optional dependency to `der`, where it can act as an ASN.1 BIT STRING type, but implement `ToOwned` producing a `der::asn1::BitString` (which, to make `ToOwned` work, needs to impl `Borrow<BitSlice>`). This would make it optionally possible to use `Cow` for copy-on-write BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the preferred default data structure for that purpose as `der::asn1::BitStringRef`, which is a lifetime-parameterized struct that avoids the open soundness questions around `BitSlice`. From there we can see what develops around the soundness story and SB/TB discrepancy, and beyond that new Rust features like custom DSTs which may make expressing structures like this less of a hack.
1 parent 66cb272 commit d420293

13 files changed

Lines changed: 1813 additions & 0 deletions

File tree

.github/workflows/bitref.yml

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
name: bitref
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- ".github/workflows/bitref.yml"
7+
- "bitref/**"
8+
- "Cargo.*"
9+
push:
10+
branches: master
11+
12+
permissions:
13+
contents: read
14+
15+
defaults:
16+
run:
17+
working-directory: bitref
18+
19+
env:
20+
CARGO_INCREMENTAL: 0
21+
RUSTFLAGS: "-Dwarnings"
22+
23+
# Cancels CI jobs when new commits are pushed to a PR branch
24+
concurrency:
25+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
26+
cancel-in-progress: true
27+
28+
jobs:
29+
build-no-std:
30+
strategy:
31+
matrix:
32+
target:
33+
- riscv32i-unknown-none-elf
34+
- thumbv7em-none-eabi
35+
runs-on: ubuntu-latest
36+
steps:
37+
- uses: actions/checkout@v6
38+
- uses: RustCrypto/actions/cargo-cache@master
39+
- uses: dtolnay/rust-toolchain@master
40+
with:
41+
toolchain: stable
42+
targets: ${{ matrix.target }}
43+
- uses: RustCrypto/actions/cargo-hack-install@master
44+
- run: cargo build --target ${{ matrix.target }}
45+
46+
minimal-versions:
47+
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
48+
with:
49+
working-directory: ${{ github.workflow }}
50+
51+
test:
52+
strategy:
53+
matrix:
54+
include:
55+
- rust: 1.85.0 # MSRV
56+
- rust: stable
57+
runs-on: "ubuntu-latest"
58+
steps:
59+
- uses: actions/checkout@v6
60+
- uses: RustCrypto/actions/cargo-cache@master
61+
- uses: dtolnay/rust-toolchain@master
62+
with:
63+
toolchain: ${{ matrix.rust }}
64+
- run: cargo test
65+
66+
# Test using `cargo careful`
67+
test-careful:
68+
runs-on: ubuntu-latest
69+
steps:
70+
- uses: actions/checkout@v6
71+
- uses: dtolnay/rust-toolchain@nightly
72+
- run: cargo install cargo-careful
73+
- run: cargo careful test
74+
75+
# Cross-compiled tests
76+
test-cross:
77+
strategy:
78+
matrix:
79+
include:
80+
# ARM32
81+
- target: armv7-unknown-linux-gnueabi
82+
rust: 1.85.0 # MSRV
83+
- target: armv7-unknown-linux-gnueabi
84+
rust: stable # MSRV
85+
# PPC32
86+
- target: powerpc-unknown-linux-gnu
87+
rust: 1.85.0 # MSRV
88+
- target: powerpc-unknown-linux-gnu
89+
rust: stable
90+
# RISCV64
91+
- target: riscv64gc-unknown-linux-gnu
92+
rust: stable
93+
runs-on: ubuntu-latest
94+
steps:
95+
- uses: actions/checkout@v6
96+
- uses: RustCrypto/actions/cargo-cache@master
97+
- uses: dtolnay/rust-toolchain@master
98+
with:
99+
toolchain: ${{ matrix.rust }}
100+
targets: ${{ matrix.target }}
101+
- uses: RustCrypto/actions/cross-install@master
102+
- run: cross test --target ${{ matrix.target }}
103+
104+
# Test using `cargo miri`
105+
test-miri:
106+
runs-on: ubuntu-latest
107+
env:
108+
MIRIFLAGS: "-Zmiri-tree-borrows -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-backtrace=full"
109+
strategy:
110+
matrix:
111+
target:
112+
- armv7-unknown-linux-gnueabi
113+
- powerpc-unknown-linux-gnu
114+
- riscv64gc-unknown-linux-gnu
115+
- s390x-unknown-linux-gnu
116+
- x86_64-unknown-linux-gnu
117+
steps:
118+
- uses: actions/checkout@v6
119+
- uses: dtolnay/rust-toolchain@nightly
120+
- run: rustup component add miri && cargo miri setup
121+
- run: cargo miri test --target ${{ matrix.target }}
122+
123+
# Test WASM using `wasmtime`
124+
test-wasm:
125+
runs-on: ubuntu-latest
126+
env:
127+
CARGO_TARGET_WASM32_WASIP1_RUNNER: "wasmtime"
128+
steps:
129+
- uses: actions/checkout@v6
130+
- uses: bytecodealliance/actions/wasmtime/setup@v1
131+
- uses: dtolnay/rust-toolchain@master
132+
with:
133+
toolchain: stable
134+
targets: wasm32-wasip1
135+
- run: cargo test --target wasm32-wasip1

0 commit comments

Comments
 (0)