v0.2.5-pre.002

This commit is contained in:
2026-08-19 09:56:01 +02:00
parent c2ccef3849
commit c97a8739ab
19 changed files with 1037 additions and 27 deletions

View File

@@ -0,0 +1,15 @@
// file: crates/ksp-wallet-lib/src/capability.rs
// version: 1
/// Authorized capability represented by an unlocked Wallet handle.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum WalletCapability {
/// Metadata access plus rotation of the current VIEW password only.
View,
/// Full Wallet ownership including signing and administration.
Owner,
}
#[cfg(test)]
#[path = "../unit_tests/capability.rs"]
mod tests;

View File

@@ -0,0 +1,7 @@
// file: crates/ksp-wallet-lib/src/constants.rs
// version: 1
//! Wallet-owned constants.
/// Owning tracing target for events emitted by the Wallet crate.
pub(crate) const TRACING_TARGET: &str = "ksp-wallet-lib";

View File

@@ -0,0 +1,29 @@
// file: crates/ksp-wallet-lib/src/error.rs
// version: 1
/// Error code used when a native Wallet structure is invalid.
pub const ERROR_CODE_FORMAT_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "format_invalid");
/// Error code used when a native Wallet format version is unsupported.
pub const ERROR_CODE_FORMAT_VERSION_UNSUPPORTED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "format_version_unsupported");
/// Error code used when serialized cryptographic parameters are invalid or unsupported.
pub const ERROR_CODE_CRYPTO_PARAMETERS_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "crypto_parameters_invalid");
/// Error code used when an authenticated Wallet structure cannot be verified.
pub const ERROR_CODE_AUTHENTICATION_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "authentication_failed");
/// Error code used when a VIEW unlock attempt fails without exposing a finer cryptographic oracle.
pub const ERROR_CODE_VIEW_UNLOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "view_unlock_failed");
/// Error code used when an OWNER unlock attempt fails without exposing a finer cryptographic oracle.
pub const ERROR_CODE_OWNER_UNLOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "owner_unlock_failed");
/// Error code used when an operation requires a capability that the caller does not own.
pub const ERROR_CODE_CAPABILITY_INSUFFICIENT: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "capability_insufficient");
/// Error code used when Wallet filesystem I/O fails.
pub const ERROR_CODE_IO_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "io_failed");
/// Error code used when a no-clobber create or import destination already exists.
pub const ERROR_CODE_DESTINATION_EXISTS: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "destination_exists");
/// Error code used when an atomic Wallet persistence operation cannot publish a valid replacement.
pub const ERROR_CODE_ATOMIC_PERSISTENCE_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "atomic_persistence_failed");
/// Error code used when an import/export transfer format is unsupported.
pub const ERROR_CODE_TRANSFER_FORMAT_UNSUPPORTED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "transfer_format_unsupported");
/// Error code used when imported or decoded key material is invalid.
pub const ERROR_CODE_KEY_MATERIAL_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "key_material_invalid");
/// Error code used when a Wallet signing operation fails.
pub const ERROR_CODE_SIGNATURE_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("wallet", "signature_failed");

View File

@@ -0,0 +1,66 @@
// file: crates/ksp-wallet-lib/src/lib.rs
// version: 1
#![warn(missing_docs)]
#![deny(unreachable_pub)]
#![forbid(unsafe_code)]
//! Autonomous KSP Wallet foundation.
//!
//! `ksp-wallet-lib` owns the native `.kspwallet` domain, VIEW/OWNER capability model, protected metadata projection, password-secret wrappers and Wallet
//! error contract. The `0.2.5-pre.002` foundation deliberately contains no file codec, KDF/AEAD implementation, Solana secret material, persistence,
//! network access, Config integration or execution policy. Public keys are consumed exclusively through the [`ksp_core_lib::Pubkey`] re-export owned by
//! KSP Core, and behavioral observability uses only `ksp-logging-lib` with the explicit crate target defined in `src/constants.rs`.
mod capability;
mod constants;
mod error;
mod metadata;
mod owner;
mod password;
mod view;
/// Authorized capability represented by an unlocked Wallet handle.
pub use self::capability::WalletCapability;
/// Error code used when an atomic Wallet persistence operation cannot publish a valid replacement.
pub use self::error::ERROR_CODE_ATOMIC_PERSISTENCE_FAILED;
/// Error code used when an authenticated Wallet structure cannot be verified.
pub use self::error::ERROR_CODE_AUTHENTICATION_FAILED;
/// Error code used when an operation requires a capability that the caller does not own.
pub use self::error::ERROR_CODE_CAPABILITY_INSUFFICIENT;
/// Error code used when serialized cryptographic parameters are invalid or unsupported.
pub use self::error::ERROR_CODE_CRYPTO_PARAMETERS_INVALID;
/// Error code used when a no-clobber create or import destination already exists.
pub use self::error::ERROR_CODE_DESTINATION_EXISTS;
/// Error code used when a native Wallet structure is invalid.
pub use self::error::ERROR_CODE_FORMAT_INVALID;
/// Error code used when a native Wallet format version is unsupported.
pub use self::error::ERROR_CODE_FORMAT_VERSION_UNSUPPORTED;
/// Error code used when Wallet filesystem I/O fails.
pub use self::error::ERROR_CODE_IO_FAILED;
/// Error code used when imported or decoded key material is invalid.
pub use self::error::ERROR_CODE_KEY_MATERIAL_INVALID;
/// Error code used when an OWNER unlock attempt fails without exposing a finer cryptographic oracle.
pub use self::error::ERROR_CODE_OWNER_UNLOCK_FAILED;
/// Error code used when a Wallet signing operation fails.
pub use self::error::ERROR_CODE_SIGNATURE_FAILED;
/// Error code used when an import/export transfer format is unsupported.
pub use self::error::ERROR_CODE_TRANSFER_FORMAT_UNSUPPORTED;
/// Error code used when a VIEW unlock attempt fails without exposing a finer cryptographic oracle.
pub use self::error::ERROR_CODE_VIEW_UNLOCK_FAILED;
/// Minimal non-secret information available while a native Wallet remains locked.
pub use self::metadata::LockedWalletInfo;
/// Safe metadata projection produced after VIEW or OWNER authorization.
pub use self::metadata::WalletInfo;
/// One protected Wallet note exposed only after authorization.
pub use self::metadata::WalletNote;
/// Authorized OWNER capability handle.
pub use self::owner::WalletOwner;
/// Owned OWNER password material with redacted diagnostics and drop-time zeroization.
pub use self::password::OwnerPassword;
/// Owned VIEW password material with redacted diagnostics and drop-time zeroization.
pub use self::password::ViewPassword;
/// Authorized VIEW capability handle.
pub use self::view::WalletView;
/// Wallet-owned tracing target used by the KSP logging facade.
pub(crate) use self::constants::TRACING_TARGET;

View File

@@ -0,0 +1,109 @@
// file: crates/ksp-wallet-lib/src/metadata.rs
// version: 1
/// One protected Wallet note exposed only after VIEW or OWNER authorization.
#[derive(Clone, Eq, PartialEq)]
pub struct WalletNote {
id: std::string::String,
text: std::string::String,
}
impl WalletNote {
/// Returns the stable note identifier used by Wallet administration operations.
#[must_use]
pub fn id(&self) -> &str {
return self.id.as_str();
}
/// Returns the protected note text after authorization.
#[must_use]
pub fn text(&self) -> &str {
return self.text.as_str();
}
}
impl std::fmt::Debug for WalletNote {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.debug_struct("WalletNote").field("id", &"<redacted>").field("text", &"<redacted>").finish();
}
}
/// Safe metadata projection produced after VIEW or OWNER authorization.
#[derive(Clone, Eq, PartialEq)]
pub struct WalletInfo {
format_version: u32,
capability: crate::WalletCapability,
pubkey: ksp_core_lib::Pubkey,
alias: std::option::Option<std::string::String>,
notes: std::vec::Vec<crate::WalletNote>,
}
impl WalletInfo {
/// Returns the native Wallet format version parsed for this projection.
#[must_use]
pub const fn format_version(&self) -> u32 {
return self.format_version;
}
/// Returns the authorization capability that produced this projection.
#[must_use]
pub const fn capability(&self) -> crate::WalletCapability {
return self.capability;
}
/// Returns the authorized Solana public key using the KSP Core re-export.
#[must_use]
pub const fn pubkey(&self) -> &ksp_core_lib::Pubkey {
return &self.pubkey;
}
/// Returns the protected internal alias after authorization, when present.
#[must_use]
pub fn alias(&self) -> std::option::Option<&str> {
return self.alias.as_deref();
}
/// Returns the protected Wallet notes after authorization.
#[must_use]
pub fn notes(&self) -> &[crate::WalletNote] {
return self.notes.as_slice();
}
}
impl std::fmt::Debug for WalletInfo {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter
.debug_struct("WalletInfo")
.field("format_version", &self.format_version)
.field("capability", &self.capability)
.field("pubkey", &self.pubkey)
.field("alias", &self.alias.as_ref().map(|_| "<redacted>"))
.field("note_count", &self.notes.len())
.finish();
}
}
/// Minimal non-secret information available while a native Wallet remains locked.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LockedWalletInfo {
format_version: u32,
view_enabled: bool,
}
impl LockedWalletInfo {
/// Returns the native Wallet format version.
#[must_use]
pub const fn format_version(&self) -> u32 {
return self.format_version;
}
/// Reports whether a VIEW capability slot exists without exposing its protected contents.
#[must_use]
pub const fn view_enabled(&self) -> bool {
return self.view_enabled;
}
}
#[cfg(test)]
#[path = "../unit_tests/metadata.rs"]
mod tests;

View File

@@ -0,0 +1,54 @@
// file: crates/ksp-wallet-lib/src/owner.rs
// version: 1
/// Authorized OWNER capability handle.
///
/// OWNER exposes all authorized metadata and will receive signing plus Wallet administration operations in later `0.2.5` tranches without exposing a
/// general-purpose secret-key getter.
pub struct WalletOwner {
info: crate::WalletInfo,
}
impl WalletOwner {
/// Returns the authorization capability represented by this handle.
#[must_use]
pub const fn capability(&self) -> crate::WalletCapability {
return crate::WalletCapability::Owner;
}
/// Returns the authorized Solana public key.
#[must_use]
pub const fn pubkey(&self) -> &ksp_core_lib::Pubkey {
return self.info.pubkey();
}
/// Returns the protected internal alias, when present.
#[must_use]
pub fn alias(&self) -> std::option::Option<&str> {
return self.info.alias();
}
/// Returns the protected notes.
#[must_use]
pub fn notes(&self) -> &[crate::WalletNote] {
return self.info.notes();
}
/// Returns the complete safe metadata projection for this OWNER capability.
#[must_use]
pub fn info(&self) -> &crate::WalletInfo {
ksp_logging_lib::trace!(
target: crate::TRACING_TARGET,
operation = "wallet_info_projection",
capability = "owner",
"wallet metadata projection requested"
);
return &self.info;
}
}
impl std::fmt::Debug for WalletOwner {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.debug_struct("WalletOwner").field("info", &self.info).finish();
}
}

View File

@@ -0,0 +1,74 @@
// file: crates/ksp-wallet-lib/src/password.rs
// version: 1
/// Owned VIEW password material.
///
/// The value is never exposed through `Debug` or `Display`, is intentionally non-`Clone`, and is zeroized on drop. Consumers should move an existing
/// `String` into this type instead of keeping unnecessary clear-text copies.
///
/// ```compile_fail
/// let password = ksp_wallet_lib::ViewPassword::new(std::string::String::from("test-only"));
/// let duplicated = password.clone();
/// let _ = duplicated;
/// ```
pub struct ViewPassword {
value: std::string::String,
}
impl ViewPassword {
/// Takes ownership of VIEW password material.
#[must_use]
pub fn new(value: std::string::String) -> Self {
return Self { value };
}
}
impl std::fmt::Debug for ViewPassword {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.write_str("ViewPassword(<redacted>)");
}
}
impl std::ops::Drop for ViewPassword {
fn drop(&mut self) {
zeroize::Zeroize::zeroize(&mut self.value);
}
}
/// Owned OWNER password material.
///
/// The value is never exposed through `Debug` or `Display`, is intentionally non-`Clone`, and is zeroized on drop. Consumers should move an existing
/// `String` into this type instead of keeping unnecessary clear-text copies.
///
/// ```compile_fail
/// let password = ksp_wallet_lib::OwnerPassword::new(std::string::String::from("test-only"));
/// let duplicated = password.clone();
/// let _ = duplicated;
/// ```
pub struct OwnerPassword {
value: std::string::String,
}
impl OwnerPassword {
/// Takes ownership of OWNER password material.
#[must_use]
pub fn new(value: std::string::String) -> Self {
return Self { value };
}
}
impl std::fmt::Debug for OwnerPassword {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.write_str("OwnerPassword(<redacted>)");
}
}
impl std::ops::Drop for OwnerPassword {
fn drop(&mut self) {
zeroize::Zeroize::zeroize(&mut self.value);
}
}
#[cfg(test)]
#[path = "../unit_tests/password.rs"]
mod tests;

View File

@@ -0,0 +1,54 @@
// file: crates/ksp-wallet-lib/src/view.rs
// version: 1
/// Authorized VIEW capability handle.
///
/// VIEW exposes protected metadata and, in later `0.2.5` tranches, will expose only self-rotation of its VIEW password. It never owns the Solana secret or
/// OWNER administration material.
pub struct WalletView {
info: crate::WalletInfo,
}
impl WalletView {
/// Returns the authorization capability represented by this handle.
#[must_use]
pub const fn capability(&self) -> crate::WalletCapability {
return crate::WalletCapability::View;
}
/// Returns the authorized Solana public key.
#[must_use]
pub const fn pubkey(&self) -> &ksp_core_lib::Pubkey {
return self.info.pubkey();
}
/// Returns the protected internal alias, when present.
#[must_use]
pub fn alias(&self) -> std::option::Option<&str> {
return self.info.alias();
}
/// Returns the protected notes.
#[must_use]
pub fn notes(&self) -> &[crate::WalletNote] {
return self.info.notes();
}
/// Returns the complete safe metadata projection for this VIEW capability.
#[must_use]
pub fn info(&self) -> &crate::WalletInfo {
ksp_logging_lib::trace!(
target: crate::TRACING_TARGET,
operation = "wallet_info_projection",
capability = "view",
"wallet metadata projection requested"
);
return &self.info;
}
}
impl std::fmt::Debug for WalletView {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.debug_struct("WalletView").field("info", &self.info).finish();
}
}