Skip to main content

Crate reallyme_crypto

Crate reallyme_crypto 

Source
Expand description

§reallyme-crypto

Umbrella crate that re-exports the ReallyMe cryptographic primitives, dispatch and signer abstractions behind one dependency and a consistent feature set.

§Platform lanes

Rust exposes two backend lanes selected by Cargo feature and target: native (portable Rust) and wasm (package-owned Rust compiled for WebAssembly with target-appropriate entropy support). Swift and Kotlin provider selection lives in their package facades; those facades call this Rust workspace through FFI/JNI only for algorithms whose provider policy explicitly selects Rust. A lane never silently falls back to another backend.

The canonical contract is not the Rust API by itself. It is the shared set of protobuf/enums, package algorithm identifiers, typed error taxonomy, provider manifest, and conformance vectors. Rust is the reference implementation and the shared implementation for selected primitives; native platform routes are interchangeable only when vectors and typed-error tests prove identical input, output, failure, and edge-case behavior.

§Security posture

#![forbid(unsafe_code)] here; secret material is returned in zeroizing wrappers; signature verification fails closed; and cross-implementation conformance vectors pin the Rust output against an independent oracle. See SECURITY.md and SECURITY_MEMORY_MODEL.md at the repository root.

Compile-checked usage examples live in the crate README so tests remain separate from production implementation files.

§reallyme-crypto

Code Checks reallyme-crypto npm Maven Central Security Policy License

ReallyMe Crypto is the Rust facade for a cross-platform cryptography workspace spanning Rust, Swift, Kotlin, Android, and TypeScript. It exposes typed operation owners, explicit provider routing, and the package surfaces used by the native and WASM adapters.

The protobuf schema is the source of truth for executable structured requests, responses, algorithm identifiers, and wire errors. Generated bindings feed a single Rust operation boundary. provider_manifest.json fixes the provider selected for each SDK lane, and positive and negative vectors prove the byte and failure contract. Missing providers and unsupported algorithms fail closed.

§Why

Modern cryptography APIs differ across platforms. Algorithms are exposed differently, key formats vary, providers have different capabilities, and error behavior is inconsistent.

ReallyMe Crypto makes platform differences explicit while preserving consistent algorithm identifiers, encodings, errors, and verification semantics for every supported route. Provider selection is deterministic and unavailable routes return typed errors instead of switching implementations.

§Packages

LanguagePackageNotes
Rustreallyme-cryptoUmbrella crate for cryptographic APIs.
SwiftReallyMeCryptoSwift Package at the repository root, with native Apple providers and Rust C ABI routes where needed.
Kotlin/JVMme.really:cryptoJVM package with explicit JCA/JCE, BouncyCastle, and Rust-backed routes.
Androidme.really:crypto-androidAndroid AAR with jniLibs Rust provider packaging and the published me.really:codec-android dependency.
TypeScript@reallyme/cryptonpm package for Node, browsers, and WASM-backed primitives.
Protobufreallyme/crypto/v1/crypto.protoCanonical structured operation, algorithm identifier, and typed wire-error contract.

General-purpose encoding, serialization, and multiformat codec APIs live in github.com/reallyme/codec.

§Supported Algorithms

CategoryAlgorithms
AEAD and key wrapAES-128/192/256-GCM, AES-256-GCM-SIV, AES-128/192/256-KW, ChaCha20-Poly1305, XChaCha20-Poly1305
Hash, MAC, and KDFSHA-2, SHA-3, HMAC-SHA-256/384/512, HKDF-SHA256/384, KMAC256 KDF, JWA Concat KDF (ECDH-ES), PBKDF2-HMAC-SHA-256/512, Argon2id
SignaturesEd25519, ECDSA P-256/P-384/P-521, secp256k1 ECDSA, BIP-340 Schnorr, RSA verification, ML-DSA-44/65/87, SLH-DSA-SHA2-128s
Key agreement and KEMX25519, P-256/P-384/P-521 ECDH, ML-KEM-512/768/1024, X-Wing-768
ProtocolsHPKE
Key and wire envelopesJWK and public-key multikey bindings used by the crypto facades

X-Wing-768 follows the IETF CFRG Internet-Draft draft-connolly-cfrg-xwing-kem, which defines a hybrid KEM built from X25519 and ML-KEM-768.

The ML-KEM and X-Wing deterministic key-derivation and encapsulation helpers are expert conformance APIs. They consume caller-supplied seed or encapsulation randomness and therefore must not replace randomized key generation or encapsulation in production protocols. Their public contract is gated by the same committed known-answer vectors used across supported SDK lanes.

Availability varies by SDK lane. The exact provider and support map lives in PROVIDER_POLICY.md. For each language lane, an algorithm is either handled by its declared provider or rejected with a typed unsupported-algorithm error.

§HPKE Profiles

The cross-platform SDK facade exposes two RFC 9180 Base-mode profiles:

ProfileKEMKDFAEAD
DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCMDHKEM(P-256, HKDF-SHA256)HKDF-SHA256AES-256-GCM
DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305DHKEM(X25519, HKDF-SHA256)HKDF-SHA256ChaCha20-Poly1305

The Rust native operation contract also supports reviewed classical, post-quantum, and hybrid HPKE components. See the protobuf contract for the executable component set and operation-level constraints.

Every provider route must implement identical input validation and normalization, output encodings, typed failure semantics, and edge-case behavior. Security-sensitive composition, canonical serialization, deterministic signatures, post-quantum primitives, memory-hard KDFs, and provider-ambiguous algorithms default to the ReallyMe Rust implementation through FFI, JNI, or WASM unless a native route is explicitly proven equivalent.

RSA support is intentionally verification-only for historical X.509 and eMRTD PKI interoperability. The package does not generate RSA keys, sign with RSA private keys, or provide RSA encryption/decryption APIs.

§Install

§Rust

cargo add reallyme-crypto --features native,dispatch,ed25519

The Rust crates require Rust 1.96.0 or newer. That MSRV is intentional: ReallyMe Crypto tracks current stable Rust so the public packages can use the compiler, dependency, lint, and target support expected by the conformance wall.

When default features are disabled, enable one backend lane and each algorithm surface your crate calls:

reallyme-crypto = { version = "0.3.0", default-features = false, features = [
  "native",
  "ed25519",
  "p256",
  "secp256k1",
  "sha2",
] }

Messaging-focused consumers can use the narrow primitive bundle instead of the default feature set:

reallyme-crypto = { version = "0.3.0", default-features = false, features = [
  "native",
  "messaging-primitives",
] }

messaging-primitives enables only ChaCha20-Poly1305/XChaCha20-Poly1305, HKDF, HMAC, ML-KEM-768, SHA-2, and X25519. The ML-KEM-768 and X25519 algorithm features require the typed router, so this bundle also enables dispatch; it does not enable signer.

Dispatch and signer surfaces are feature-gated by algorithm, so enabling the router does not pull in unrelated primitives unless the matching algorithm feature is also selected.

The native and wasm features select the Rust backend lane. They do not, by themselves, enable every primitive. Algorithm features such as ed25519, p256, or sha2 enable the root modules and re-exports. This keeps no-default consumers from pulling unused cryptography while still forwarding the selected backend into every enabled primitive crate. The wasm lane is for wasm32 builds; host builds should use native.

Some Rust helper APIs are intentionally lane-scoped. P-256 raw scalar import is available in both native and wasm lanes through p256::generate_p256_keypair_from_secret_key; it validates an existing private scalar and is not random key generation. P-384 and P-521 ECDH are native Rust APIs today; the Swift, Kotlin, and TypeScript package facades expose their own provider-backed P-384/P-521 ECDH surfaces.

The Swift package also includes a P-256 ECDH Secure Enclave / Keychain API for applications that need non-exportable private-key residency, such as JOSE/JWE decryption with platform-held keys. That API uses explicit handles and is separate from raw private-key bytes.

§Swift

.package(
    url: "https://github.com/reallyme/crypto",
    from: "0.3.0"
)
.product(name: "ReallyMeCrypto", package: "crypto")

§Kotlin

dependencies {
    implementation("me.really:crypto:0.3.0")
}

§TypeScript

npm install @reallyme/crypto

For production deployments, pin exact package versions, release tags, or Git revisions so cryptographic behavior and conformance vectors remain identical across all language lanes.

§Quick Start

Rust:

// This example requires the `ed25519` feature.
use reallyme_crypto::Algorithm;
use reallyme_crypto::operations::signature::{generate_key_pair, sign, verify};

let key_pair = generate_key_pair(Algorithm::Ed25519)?;
let signature = sign(Algorithm::Ed25519, &key_pair.secret_key, b"message")?;
verify(Algorithm::Ed25519, &key_pair.public_key, b"message", &signature)?;

BIP-340 uses an x-only secp256k1 public key and requires callers to provide a 32-byte message representative and 32 bytes of auxiliary randomness explicitly:

// This example requires the `secp256k1` feature.
use reallyme_crypto::operations::signature::{
    generate_bip340_key_pair, sign_bip340, verify_bip340,
};

let key_pair = generate_bip340_key_pair()?;
let message32 = [0x42u8; 32];
let aux_rand32 = [0x24u8; 32];
let signature = sign_bip340(&key_pair.secret_key, &message32, &aux_rand32)?;
verify_bip340(&signature, &message32, &key_pair.public_key)?;

Hashing is owned by the semantic operation layer. Adapters should call this surface instead of selecting a primitive independently:

// This example requires the `sha2` feature.
use reallyme_crypto::HashAlgorithm;
use reallyme_crypto::operations::hash;

let digest = hash::digest(HashAlgorithm::Sha2_256, b"abc")?;
assert_eq!(
    digest,
    [
        0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
        0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
        0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
        0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad,
    ],
);

HMAC authentication and fail-closed verification share the same semantic operation owner across Rust, structured protobuf, and C ABI adapters:

// This example requires the `hmac` feature.
use reallyme_crypto::MacAlgorithm;
use reallyme_crypto::operations::mac;

let key = [0x42u8; 32];
let message = b"authenticated message";
let tag = mac::authenticate(MacAlgorithm::HmacSha256, &key, message)?;
mac::verify(MacAlgorithm::HmacSha256, &key, message, &tag)?;

Authenticated encryption uses the same operation owner for algorithm selection, typed failures, and zeroizing recovered plaintext:

// This example requires the `aes` feature.
use reallyme_crypto::operations::aead;
use reallyme_crypto::AeadAlgorithm;

let key = [0x42u8; 32];
let nonce = [0x24u8; 12];
let plaintext = b"authenticated plaintext";
let ciphertext = aead::seal(
    AeadAlgorithm::Aes256Gcm,
    &key,
    &nonce,
    b"context",
    plaintext,
)?;
let opened = aead::open(
    AeadAlgorithm::Aes256Gcm,
    &key,
    &nonce,
    b"context",
    &ciphertext,
)?;
assert_eq!(opened.as_slice(), plaintext);

MLS and HPKE derive nonces from their protocol key schedules. The focused AES-256-GCM facade therefore accepts an explicit typed nonce and deliberately does not offer a random-nonce overload:

// This example requires the `aes` feature.
use reallyme_crypto::aes256_gcm::{
    aes256_gcm_decrypt, aes256_gcm_encrypt, Aes256GcmKey, Aes256GcmNonce,
};

let key = Aes256GcmKey::from_slice(&[0x42; 32])?;
// In MLS or HPKE, this value comes from the protocol key schedule.
let nonce = Aes256GcmNonce::from_slice(&[0x24; 12])?;
let ciphertext = aes256_gcm_encrypt(&key, nonce, b"context", b"payload")?;
let plaintext = aes256_gcm_decrypt(&key, nonce, b"context", &ciphertext)?;
assert_eq!(plaintext, b"payload");

The HPKE facade exposes explicit registry identifiers and derives its nonce internally; seal/open requests have no caller-supplied nonce field:

// This example requires the `hpke` and `native` features.
use reallyme_crypto::hpke::{
    derive_keypair, open_base, seal_base, HpkeOpenRequest, HpkeSealRequest,
    HPKE_DHKEM_P256_HKDF_SHA256_AES256GCM,
};

let suite = HPKE_DHKEM_P256_HKDF_SHA256_AES256GCM;
let recipient = derive_keypair(suite, &[0x5a; 32])?;
let sealed = seal_base(&HpkeSealRequest {
    suite,
    recipient_public_key: &recipient.public_key,
    info: b"reallyme/example/v0.3",
    aad: b"message metadata",
    plaintext: b"confidential payload",
})?;
let opened = open_base(&HpkeOpenRequest {
    suite,
    encapsulated_key: &sealed.encapsulated_key,
    recipient_private_key: recipient.private_key(),
    info: b"reallyme/example/v0.3",
    aad: b"message metadata",
    ciphertext: &sealed.ciphertext,
})?;
assert_eq!(opened.plaintext.as_slice(), b"confidential payload");

AES-KW uses the operation owner for suite selection and returns unwrapped key material in a zeroizing owner:

// This example requires the `aes-kw` feature.
use reallyme_crypto::operations::key_wrap;
use reallyme_crypto::KeyWrapAlgorithm;

let kek = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
];
let key_data = [
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
    0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
];
let wrapped = key_wrap::wrap_key(KeyWrapAlgorithm::Aes128Kw, &kek, &key_data)?;
let unwrapped = key_wrap::unwrap_key(
    KeyWrapAlgorithm::Aes128Kw,
    &kek,
    wrapped.as_bytes(),
)?;
assert_eq!(unwrapped.as_bytes(), key_data);

Swift:

import ReallyMeCrypto

let digest = try ReallyMeCrypto.hash(.sha2_256, Array("abc".utf8))

Kotlin:

import me.really.crypto.ReallyMeCrypto
import me.really.crypto.ReallyMeHashAlgorithm

val digest = ReallyMeCrypto.hash(ReallyMeHashAlgorithm.SHA2_256, "abc".toByteArray())

TypeScript:

import { ReallyMeCrypto } from "@reallyme/crypto";

const digest = ReallyMeCrypto.hash("SHA2-256", new TextEncoder().encode("abc"));

Signature verification fails closed: an invalid signature returns an error rather than a boolean that can be accidentally ignored.

§Protobuf

The canonical structured wire contract lives at crates/proto/proto/reallyme/crypto/v1/crypto.proto. Service, application, and storage protos can import it when they need the structured operation boundary, stable algorithm identifiers, or typed errors.

ReallyMe Crypto uses raw bytes for single primitive outputs, protobuf bytes for fixed multi-field boundary results, and strict proto-JSON for Connect JSON, CLI, browser-adapter, and conformance boundaries that require JSON. Proto-JSON is available for operation requests, but it is not a casual JSON crypto facade and is not the preferred representation for secret-bearing payloads. JSON convenience shapes remain limited to public metadata such as JWK/JWKS.

For example, a JSON-only client can express a SHA2-256 hash request as strict proto-JSON:

{
  "hash": {
    "algorithm": {
      "hash": "HASH_ALGORITHM_SHA2_256"
    },
    "input": "YWJj"
  }
}

See docs/proto-json.md for operation-family examples and the security notes for secret-bearing JSON payloads.

Rust adapters can enable the operation-response feature and call reallyme_crypto::operation_contract::process_operation_response(request_bytes) with one encoded CryptoOperationRequest: serialized request bytes in, binary CryptoOperationResponse bytes out, with either a generated CryptoOperationResult or generated CryptoError outcome. The ProtoJSON entrypoint accepts only generated non-secret hash, verification, key-generation, encapsulation, and sender-export requests and still returns binary protobuf. Secret-bearing operations must use the binary protobuf route. TypeScript exposes processOperationResponse and processOperationResponseJson; Swift and Kotlin expose the same method names on ReallyMeCrypto. Every structured adapter returns the generated operation response directly. Native SDK methods remain the primary ergonomic application API.

The generated proto adapters are available through:

LanguageProto surface
Rustreallyme-crypto-proto
SwiftReallyMeCryptoProto and ReallyMeCryptoProtoAdapters
Kotlinme.really.crypto.v1 and me.really.crypto.proto
TypeScript@reallyme/crypto/proto

See docs/protobuf.md for the boundary rules and adapter policy.

§Documentation

§Security Rules

This repository is security-sensitive code. The project policy is:

  • no panics, unwraps, or generic string errors in production paths;
  • typed errors only;
  • zeroizing owners for secret material;
  • checked arithmetic for buffer sizes and offsets;
  • negative tests and conformance vectors for every primitive;
  • no silent platform fallback in release platform lanes.

§Conformance

Shared vectors live in vectors. The generator and platform verifiers live in crates/conformance.

The everyday all-feature Rust check is:

cargo nextest run --workspace --all-features

The full release wall is documented in docs/conformance.md.

Re-exports§

pub use crypto_core as core;
pub use envelopes_jwk as jwk;
pub use envelopes_jwk_multikey as jwk_multikey;

Modules§

aes
AES-GCM authenticated encryption primitives and their typed key/nonce wrappers and length constants. AES-GCM facade routes backed by the semantic AEAD operation owner.
aes256_gcm
AES-256-GCM authenticated encryption with typed key and nonce boundaries. Focused AES-256-GCM facade with typed key and nonce boundaries.
aes_gcm_siv
AES-256-GCM-SIV nonce-misuse-resistant authenticated encryption primitive and its typed key/nonce wrappers and length constants. AES-256-GCM-SIV facade routes backed by the semantic AEAD operation owner.
aes_kw
AES-128, AES-192, and AES-256 Key Wrap (RFC 3394) for compact key material. AES-KW facade routes backed by the semantic key-wrap operation owner.
argon2id
Argon2id password-based key derivation, including platform-tuned cost profiles and typed salt/secret/derived-key wrappers. Argon2id facade routes backed by the semantic KDF operation owner.
chacha20_poly1305
ChaCha20-Poly1305 and XChaCha20-Poly1305 authenticated encryption primitives with typed key and nonce wrappers. ChaCha20-Poly1305 facade routes backed by the semantic AEAD operation owner.
concat_kdf
JWA ECDH-ES Concat KDF over SHA-256 for deriving content-encryption keys from an ECDH shared secret. JWA Concat KDF facade routes backed by the semantic KDF operation owner.
csprng
OS-backed cryptographically secure randomness and typed generators for AEAD nonces and Argon2 salts.
dispatch
Algorithm-selected dispatch: keygen, sign/verify, key agreement, KEM, AEAD, hashing, and multikey binding routed by an core::Algorithm selector. Root dispatch facade.
ed25519
Ed25519 signatures: keypair generation, sign/verify, and public-key encoding. Ed25519 root facade routed through the signature operation layer.
hkdf
HKDF (RFC 5869) extract-and-expand key derivation over the SHA-2/SHA-3 suites, with domain-separated key derivation helpers. HKDF facade routes backed by the semantic KDF operation owner.
hmac
HMAC authentication tags over SHA-256, SHA-384, and SHA-512. HMAC facade routes backed by the semantic MAC operation owner.
hpke
RFC 9180 HPKE Base-mode encryption over supported DHKEM/HKDF/AEAD suites. Typed HPKE identifiers, suites, key management, encryption, and exporters.
kmac
KMAC256 key derivation for protocols using NIST SP 800-108 and SP 800-185. KMAC facade routes backed by the semantic KDF operation owner.
ml_dsa_44
ML-DSA-44 (FIPS 204) post-quantum signatures: keygen, sign/verify, and public-key encoding. ML-DSA-44 root facade routed through the signature operation layer.
ml_dsa_65
ML-DSA-65 (FIPS 204) post-quantum signatures: keygen, sign/verify, and public-key encoding. ML-DSA-65 root facade routed through the signature operation layer.
ml_dsa_87
ML-DSA-87 (FIPS 204) post-quantum signatures: keygen, sign/verify, and public-key encoding. ML-DSA-87 root facade routed through the signature operation layer.
ml_kem_512
ML-KEM-512 (FIPS 203) post-quantum key encapsulation: keygen, encapsulate, and decapsulate. ML-KEM-512 root facade routed through the KEM operation layer.
ml_kem_768
ML-KEM-768 (FIPS 203) post-quantum key encapsulation: keygen, encapsulate, and decapsulate. ML-KEM-768 root facade routed through the KEM operation layer.
ml_kem_1024
ML-KEM-1024 (FIPS 203) post-quantum key encapsulation: keygen, encapsulate, and decapsulate. ML-KEM-1024 root facade routed through the KEM operation layer.
operations
Operation-layer domain conventions shared by Rust and adapter boundaries. Semantic operation-layer conventions.
p256
NIST P-256 (secp256r1) ECDSA over pre-hashed messages, with public-key compression and Secure Enclave handle encoding. P-256 root facade with signature and key agreement routed through operations.
p384
NIST P-384 (secp384r1) ECDSA and ECDH, with public-key compression/decompression helpers. P-384 root facade with signature and key agreement routed through operations.
p521
NIST P-521 (secp521r1) ECDSA and ECDH, with public-key compression/decompression helpers. P-521 root facade with signature and key agreement routed through operations.
pbkdf2
PBKDF2 password-based key derivation conforming to RFC 8018. PBKDF2 facade routes backed by the semantic KDF operation owner.
rsa
RSA signature verification for PKCS#1 v1.5 and PSS. RSA signature verification facade over the semantic operation owner.
secp256k1
secp256k1 ECDSA signs SHA-256(message) once, returns compact low-S r || s, and uses compressed SEC1 public keys as the canonical API representation. secp256k1 root facade with ECDSA routed through the operation layer.
secret_material
Typed ownership, retention, export, and destruction contracts for secrets. Typed secret-material ownership and cleanup contracts.
sha2
SHA-2-256 hashing and its fixed-length digest wrapper. SHA-2 facade routes backed by the semantic hash operation owner.
sha3
SHA-3-256 hashing and its fixed-length digest wrapper. SHA-3 facade routes backed by the semantic hash operation owner.
signer
Signer/verifier traits and dispatch-backed implementations for producing and checking detached signatures.
slh_dsa
SLH-DSA-SHA2-128s (FIPS 205) hash-based post-quantum signatures. SLH-DSA-SHA2-128s root facade routed through the signature operation layer.
x25519
X25519 Diffie–Hellman key agreement and public-key encoding. X25519 root facade with key agreement routed through the operation layer.
x_wing
X-Wing hybrid KEM over X25519 plus ML-KEM-768. X-Wing root facade routed through the KEM operation layer.

Enums§

AeadAlgorithm
Authenticated encryption (AEAD) algorithm identifiers.
Algorithm
Asymmetric algorithm identifiers used for signatures and key agreement.
CryptoError
Typed error taxonomy for all crypto operations in the workspace.
HashAlgorithm
Hash algorithm identifiers.
KeyWrapAlgorithm
Key-wrapping algorithm identifier.
MacAlgorithm
Message authentication code algorithm identifiers.