4 releases
new 0.2.0-alpha.0 | Oct 27, 2024 |
---|---|
0.1.1 | Oct 8, 2024 |
0.1.0 | Sep 30, 2024 |
0.1.0-alpha.0 | Sep 27, 2024 |
#284 in Cryptography
518 downloads per month
Used in rustls-graviola
3MB
80K
SLoC
Graviola
Graviola is a compendium of high quality, fast and easy to build cryptography for Rust, aimed at use with rustls.
High quality: Graviola incorporates assembler routines from the s2n-bignum project. These have been formally proven to correctly implement the desired mathematical operation.
Fast: Graviola beats or is competitive with other cryptography libraries for Rust. See performance comparison.
Easy and fast to build: no C compiler, assembler or other tooling needed: just the Rust compiler. Compiles in less than one second.
Status
This project is very new, so exercise due caution. The overriding
goal of this crate is for use with rustls
via rustls-graviola,
but there is also a public API for general-purpose use.
Goals
- Fast and simple compilation
-
cargo build
takes less than one second, and requires only rustc
-
- Competitive performance (with ring, aws-lc-rs, and rustcrypto)
- Uses formally-verified assembler from other projects (where available)
- Intended to provide algorithms in wide use on web
- Intended for use as a rustls
CryptoProvider
, via rustls-graviola.
Limitations
aarch64
and x86_64
architectures only.
aarch64
requiresaes
,sha2
,pmull
, andneon
CPU features. (This notably excludes Raspberry PI 4 and earlier, but covers Raspberry Pi 5.)x86_64
requiresaes
,ssse3
avx
,avx2
,bmi2
, andpclmulqdq
CPU features. (This is most x86_64 CPUs made since around 2013.)
Acknowledgements and Thanks
Graviola incorporates significant code from other open source projects. We are grateful to:
- s2n-bignum: formally verified assembler for
- P256, P384, P521 field arithmetic and group operations
- x25519
- Big integer arithmetic
- wycheproof: collated test vectors for all algorithms.
Algorithms
Public key signatures
- RSA-PSS signature verification
- RSA-PKCS#1 signature verification
- RSA-PSS signing
- RSA-PKCS#1 signing
- ECDSA on P256 w/ SHA2
- ECDSA on P384 w/ SHA2
Hashing
- SHA256
- SHA384 & SHA512
- HMAC
- HMAC-DRBG
Key exchange
- X25519
- P256
- P384
AEADs
- AES-GCM
- chacha20-poly1305
Assorted technical details
RSA
All the arithmetic is provided by s2n-bignum.
The RSA private operation always uses the CRT optimisation.
Modular exponentiation uses 4-bit fixed exponent window, and the term is selected by the exponent bits from the table of base powers in a side-channel-free way. The private operation is always followed by the public operation to verify the result (and the result compared in a side-channel-free way).
Only RSA signing and verification are provided. Our policy on RSA encryption is: "These are not made. They should never be made. We will not make them. We will not help make them."
ECC
All ECC field and scalar arithmetic are provided by s2n-bignum.
P256 base point multiplication uses 7-bit exponent window in wNAF form (this costs a 148KB constant table). Variable point multiplication uses a 5-bit exponent window in wNAF form.
P384 base and variable point multiplication both use a 5-bit exponent window in wNAF form. (This means we're leaving a some P384 base point performance on the table, in exchange for code space. P384 performance seems to be less important than P256.)
ECDSA follows RFC6979 for generation of k
, but adds additional non-critical random input.
We do this to avoid the theoretical fragility of RFC6979 under fault conditions.
This is allowed for by RFC6979, and the HMAC-DRBG that it builds on.
The code is structured such that we pass the RFC6979 test vectors.
The code which selects a term from a table of points is non-verified, and is written in AVX2/Neon intrinsics.
X25519 directly uses the s2n-bignum implementation.
Symmetric cryptography
SHA256 has straightforward implementations using hashing intrinsics (aka "SHA-NI" on x86_64, "sha" extension on aarch64) with runtime fallback on x86_64 to a pure Rust version if needed.
SHA384/SHA512 on x86_64 has an AVX2 by-4 implementation.
AES and GHASH always use intrinsics (there are no fallbacks).
On x86_64, we have a by-8 AES-CTR and a by-8 GHASH (they are not currently interleaved; this is future work.) On aarch64 we have a by-1 AES-CTR and by-8 GHASH (also not interleaved, and I found a by-8 AES-CTR kept spilling registers and was slower.)
Architecture
We have broadly three module layers:
low
: low level primitives. private. platform-specific. unsafe allowed. minimal std and alloc.mid
: constructions, protocols and encodings. private. platform agnostic. no unsafe. minimal std and alloc.high
: high level encodings and operations. public. platform agnostic. no unsafe.
low
code should not refer to mid
, nor mid
to high
.
low
must present the same interface irrespective of platform. To this end,
low::generic
contains pure-rust polyfills for items we don't have assembler-
or intrinsic-based implementations for a certain platform.
License
Graviola incorporates and redistributes code from:
- s2n-bignum: Apache-2.0 OR ISC OR MIT-0
New code written for Graviola is licensed under Apache-2.0 OR ISC OR MIT-0.
Every file has a SPDX-License-Identifier
comment.