Skip to main content

KeystoreError

Enum KeystoreError 

Source
#[non_exhaustive]
pub enum KeystoreError {
Show 24 variants Backend(Arc<Error>), UnknownMagic { saw: [u8; 6], }, UnsupportedFormat { found: u16, }, SchemeMismatch { expected: u16, expected_name: &'static str, found: u16, }, CrcMismatch { stored: u32, computed: u32, }, DecryptFailed, InvalidKdfParams(&'static str), UnsupportedKdf(u8), UnsupportedCipher(u8), AlreadyExists(String), InvalidPlaintext { expected: usize, got: usize, }, InvalidSeed(String), Truncated { claimed: usize, available: usize, }, HardwareRequired { reason: DegradeReason, }, HardwareProbeIndeterminate { detail: String, }, HardwareWrapFailed { detail: String, }, HardwareUnwrapFailed { detail: String, }, MalformedEnvelope { detail: String, }, UnknownHardwareClass { wire_id: u8, }, NotHardwareBound { tier: String, }, HardwareStillBound { key: String, }, HardwareKindMismatch { expected: &'static str, found: &'static str, }, InsecurePermissions { path: String, mode: u32, }, UnsafeRoot { path: String, reason: &'static str, },
}
Expand description

Errors produced by keystore operations.

The enum is Clone so errors can be fanned out through broadcast channels or bubbled through async traits. The only non-Clone primitive (std::io::Error) is wrapped in Arc to preserve clonability.

#[non_exhaustive]: this catalog grows as the crate gains capability (six variants arrived with hardware binding alone), so downstream matches must carry a wildcard arm rather than break on every addition.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Backend(Arc<Error>)

An underlying backend I/O operation failed.

This is the catch-all for filesystem errors from crate::FileBackend as well as any future backend (OS keyring / HSM). The wrapped std::io::Error preserves the original ErrorKind for callers who want to distinguish e.g. NotFound from PermissionDenied.

§

UnknownMagic

The file’s magic prefix did not match any known scheme.

First 6 bytes of a keystore file carry DIGVK1, DIGLW1, etc. If the caller pointed at a non-keystore file (or a future-version file this build doesn’t understand), decode fails here before any cryptography.

Fields

§saw: [u8; 6]

The magic bytes that were actually read.

§

UnsupportedFormat

The file’s format version is newer or older than this library understands.

Format version is stored as a big-endian u16 right after the magic. This library recognizes crate::FORMAT_VERSION_V1 only.

Fields

§found: u16

The format version byte read from the file.

§

SchemeMismatch

The file’s key-scheme id does not match the type parameter used to open it.

If the caller opens Keystore::<BlsSigning>::load(...) but the file on disk is L1WalletBls (scheme id 0x0003), we refuse. This guards against accidentally interpreting wallet master seeds as validator signing seeds, which would produce perfectly-valid-looking BLS signatures that bind to the wrong domain.

Fields

§expected: u16

The scheme expected by the caller (K::SCHEME_ID).

§expected_name: &'static str

Human-readable expected name (e.g., "BlsSigning").

§found: u16

The scheme id actually stored in the file.

§

CrcMismatch

The CRC32 checksum at the end of the file did not match.

CRC is computed over every byte of the file except the trailing 4. A mismatch indicates disk corruption, partial write, or deliberate tampering. It is NOT a cryptographic integrity check (AES-GCM’s tag is) — CRC is only a fast-fail so we don’t burn ~0.5 s on Argon2 for a file that’s clearly garbage.

Fields

§stored: u32

The CRC32 read from the file.

§computed: u32

The CRC32 computed over the preceding bytes.

§

DecryptFailed

AES-GCM authentication tag failed.

This is the single error produced for any cryptographic decryption failure: wrong password, tampered ciphertext, tampered header (AAD mismatch), or truncated payload. We intentionally do NOT distinguish these variants at the error level to avoid side-channel leaks.

§

InvalidKdfParams(&'static str)

Argon2 or AES-GCM rejected the provided parameters.

Thrown when crate::KdfParams has out-of-bounds values (e.g., memory_kib < 8192) or when the underlying argon2 crate returns an error (rare — usually only on invalid output size).

§

UnsupportedKdf(u8)

The file advertised an unsupported KDF algorithm.

Currently only 0x01 = Argon2id is recognized. Non-0x01 values are reserved for future algorithms (scrypt, bcrypt, balloon).

§

UnsupportedCipher(u8)

The file advertised an unsupported symmetric cipher.

Currently only 0x01 = AES-256-GCM is recognized. Non-0x01 values are reserved for e.g. ChaCha20-Poly1305.

§

AlreadyExists(String)

Keystore::create was called for a path that already exists.

Deliberate: overwriting a keystore file is almost always an operator error. Callers that really want to replace a keystore should Keystore::delete first, or simply Keystore::change_password

  • Keystore::rotate_kdf which rotate in place.
§

InvalidPlaintext

The decrypted plaintext has the wrong length for the key scheme.

Each KeyScheme declares a fixed SECRET_LEN. If unlock decrypts successfully but the plaintext length disagrees with the scheme (e.g., file was encrypted under v1 with a 32-byte seed and this build expects 48), we reject. Normally impossible once the scheme id check has passed; included for defence in depth.

Fields

§expected: usize

Expected byte length.

§got: usize

Actual byte length read.

§

InvalidSeed(String)

The provided seed bytes were malformed (e.g., not a valid BLS seed).

Rarely thrown — chia-bls::SecretKey::from_seed accepts any byte length — but reserved for schemes where the raw bytes must pass a scheme-specific validity check (e.g., secp256k1 scalar bounds).

§

Truncated

The file’s length header claims a payload larger than the file bytes.

Indicates a truncated file (disk full mid-write, network transfer cut, etc). Should be rare since we write files atomically via rename, but guard anyway.

Fields

§claimed: usize

Bytes claimed by the header.

§available: usize

Bytes actually available.

§

HardwareRequired

The caller required hardware binding, and this host cannot provide it.

Raised by HardwarePolicy::Required rather than degrading. The DegradeReason says which negative outcome occurred — “no TPM on this machine” and “the TPM is present but unusable” lead a caller to different remedies.

Fields

§reason: DegradeReason

Why hardware binding could not be established.

§

HardwareProbeIndeterminate

The host could not be inspected, so hardware availability is unknown.

Deliberately distinct from a confident “no hardware present”: collapsing the two would turn an inspection failure into a confident negative, and a transient probe failure would then silently strip hardware protection from a machine that has it. Under the default Preferred policy this fails closed instead of degrading.

Fields

§detail: String

Non-secret detail of the probe failure.

§

HardwareWrapFailed

The hardware component refused to wrap a content key.

Fields

§detail: String

Non-secret detail of the failing operation.

§

HardwareUnwrapFailed

The hardware component could not unwrap a stored content key.

This variant means exactly one thing: the hardware refused. It is the expected error when a sealed blob is copied to a different machine — the wrapping key is non-exportable, so the copy cannot be opened — and that refusal is the guarantee, not a malfunction. Structural problems with the blob (MalformedEnvelope) and unnameable hardware (UnknownHardwareClass) are deliberately not reported here, so this variant keeps its meaning.

Fields

§detail: String

Non-secret detail of the failing operation.

§

MalformedEnvelope

A hardware envelope is structurally invalid.

A malformed blob, not a hardware refusal. Notably covers an envelope declaring a zero-length wrapped key — which asserts that no hardware key protects it, and so must never decode as a hardware envelope.

Fields

§detail: String

Non-secret detail of the structural violation.

§

UnknownHardwareClass

A hardware envelope records a hardware class this build cannot name.

A forward-compatibility case, not corruption: a newer writer may have sealed with hardware this build has no name for. Reported rather than guessed, so an unknown class can never be silently treated as a known one — or as unprotected.

Fields

§wire_id: u8

The hardware-kind wire id read from the blob.

§

NotHardwareBound

A hardware-wrapped blob was found on a host with no hardware tier.

Reported instead of returning the envelope bytes, so a copied blob fails loudly rather than being mistaken for a corrupt keystore.

Fields

§tier: String

The tier this host actually has.

§

HardwareStillBound

An unbind reported by storage as taken, but the stored blob is still a hardware envelope.

Its own variant rather than a generic write error because of what the caller does next: a user unbinds in order to safely retire the trusted component, so “unbound” over a blob that is still bound is the one message here that provokes a destructive action. The wording says STILL BOUND for that reason.

Fields

§key: String

The backend key whose blob is still wrapped.

§

HardwareKindMismatch

A hardware-wrapped blob was sealed by a different class of hardware.

Distinct from HardwareUnwrapFailed, which is another device of the same class: this is another kind of component (a blob from a Mac read on Windows), which is a migration case rather than a copied-blob case.

Fields

§expected: &'static str

The hardware class this host binds to.

§found: &'static str

The hardware class recorded in the blob.

§

InsecurePermissions

A path holding sealed key material is readable or writable by someone other than its owner, and the backend could not restrict it.

FileBackend requests owner-only permissions on its root directory and on every blob it writes, then verifies the result rather than trusting the request (SPEC.md §10.3, conformance C-14). This error is what that verification returns when the bits are still permissive — for example on a filesystem that does not implement POSIX modes, where chmod reports success and changes nothing.

It is deliberately fatal rather than a warning. The alternative is a write that reports success while leaving a keystore blob group- or world-readable, which makes the backend’s own documented guarantee a falsehood. Callers that genuinely accept that exposure should choose a different root, not a quieter backend.

Fields

§path: String

The offending path.

§mode: u32

The permission bits actually observed after the request.

§

UnsafeRoot

The keystore root is not a directory the backend is willing to own.

FileBackend refuses a root that is a symbolic link, or that exists as a non-directory, rather than following it. This is the one case that is deliberately not repaired: a permissive mode is a drift the backend can correct in one syscall and then verify, but a symlink is a statement about where the keystore lives, and the backend has no basis for deciding that some other directory is the intended one. Both fs::set_permissions and fs::metadata follow links, so following one would mean chmodding a directory chosen by whoever planted the link and then sealing an account master seed inside it.

Callers that genuinely want the link’s target as their root should pass the resolved path, making that choice explicit at the call site.

Fields

§path: String

The offending path, exactly as configured.

§reason: &'static str

Why the path cannot hold a keystore.

Trait Implementations§

Source§

impl Clone for KeystoreError

Source§

fn clone(&self) -> KeystoreError

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for KeystoreError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for KeystoreError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for KeystoreError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Error> for KeystoreError

Source§

fn from(err: Error) -> Self

Wrap an I/O error as a backend error.

Used liberally through the ? operator in crate::FileBackend and other std::io-backed code paths.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.