README.md (6690B)
1 # radroots_identity 2 3 `radroots_identity` provides the portable public identity and account values 4 shared by Radroots packages: canonical public keys, identity and account IDs, 5 public profiles, normalized usernames, and transport-neutral account status. 6 7 The crate supports `no_std` environments with `alloc`. It performs no I/O, 8 starts no tasks or threads, reads no clocks or process state, and owns no key 9 generation, secrets, signing, persistence, networking, or account selection. 10 11 ## Example 12 13 Construct public identities from validated keys and derive account identifiers 14 without exposing or inventing secret material: 15 16 ```rust 17 use radroots_identity::{AccountId, Profile, PublicIdentity, PublicKey, Username}; 18 19 let public_key = PublicKey::from_hex( 20 "585591529da0bab31b3b1b1f986611cf5f435dca84f978c89ee8a40cca7103df", 21 )?; 22 let username = Username::parse(" Alice.Farm ")?; 23 let identity = PublicIdentity::new(public_key) 24 .with_profile(Profile::new().with_username(username)); 25 let account_id = AccountId::from_public_identity(&identity); 26 27 assert_eq!(identity.id().as_bytes(), public_key.as_bytes()); 28 assert_eq!(account_id.as_bytes(), public_key.as_bytes()); 29 assert_eq!( 30 identity.profile().and_then(Profile::username).map(Username::as_str), 31 Some("alice.farm"), 32 ); 33 # Ok::<(), radroots_identity::Error>(()) 34 ``` 35 36 The same program is available as the 37 [`public_identity`](examples/public_identity.rs) example. 38 39 ## Public API 40 41 The crate root intentionally exports `AccountId`, `IdentityId`, 42 `PublicIdentity`, `PublicKey`, `Profile`, `Username`, and the aggregate 43 [`Error`](https://docs.rs/radroots_identity/latest/radroots_identity/enum.Error.html). 44 Focused values remain in these modules: 45 46 - `account` — derived account IDs, public account records, and observable 47 readiness status; 48 - `key` — validated 32-byte x-only secp256k1 public keys and identity IDs; 49 - `profile` — public identity metadata and the invariant-matched public 50 identity aggregate; 51 - `username` — canonical username parsing, bounds, and normalization. 52 53 The normative responsibility and dependency boundary are defined by the 54 [`radroots_identity` package charter](../../contracts/crates/release_v1/radroots_crates_release_v1.toml). 55 The reviewed pre-release surface is recorded in the 56 [`radroots_identity` API baseline](../../contracts/api_baselines/radroots_identity.txt). 57 Signing, Nostr-key, secret-provider, and storage ownership remains outside 58 this public-only identity package as described by the package boundary above. 59 60 ## Features 61 62 | Feature | Default | Effect | 63 | --- | --- | --- | 64 | `std` | yes | Implements the standard error integration; value behavior remains portable. | 65 | `serde` | yes | Implements checked canonical serialization and deserialization for public values. | 66 67 Disabling default features leaves the `no_std` + `alloc` value model. Features 68 are additive; enabling one does not select a runtime, backend, global account, 69 secret source, or side effect. 70 71 ## Invariants and untrusted input 72 73 `PublicKey`, `IdentityId`, and `AccountId` store exactly 32 validated bytes. 74 Text parsing accepts exact-width hexadecimal input and emits canonical 75 lowercase hexadecimal output. `PublicKey` validation confirms that the x-only 76 bytes identify a secp256k1 curve point. The three Rust types remain distinct so 77 callers cannot accidentally substitute an account identifier for a public key. 78 79 `PublicIdentity` derives its `IdentityId` from its `PublicKey` and rejects 80 separately decoded parts that do not match. `account::Record` derives its 81 `AccountId` from its public identity and rejects mismatched IDs or an update 82 timestamp before creation. `Record::touch_updated` rejects time reversal and 83 leaves the timestamp unchanged on error. `Record::set_label` does not read a 84 clock or update the timestamp; the composing host owns clock policy and must 85 advance the timestamp explicitly when appropriate. 86 87 `Username` trims surrounding whitespace, folds ASCII uppercase to lowercase, 88 enforces its byte bounds, and rejects unsupported characters or leading, 89 trailing, and consecutive dots. Account labels are opaque host-facing strings: 90 callers must apply their own content and resource limits before accepting them 91 from untrusted sources. 92 93 ## Serialization 94 95 With `serde`, identifiers are canonical lowercase 64-character hexadecimal 96 strings and usernames are canonical strings. Profiles, public identities, and 97 account records use named fields and reject unknown fields. Deserializing a 98 public identity or account record re-applies identifier and timestamp 99 invariants; invalid native state is not admitted through the supported serde 100 surface. Account status variant names use `snake_case`. 101 102 Serialization contains public metadata only and does not add confidentiality, 103 authenticity, event signing, or transport framing. Versioned cross-process wire 104 DTOs belong in `radroots_protocol` rather than this native value crate. 105 106 ## Execution and commit semantics 107 108 Operations are synchronous and deterministic. Username parsing and account 109 record construction may allocate in proportion to caller-supplied username or 110 label text, so callers should cap untrusted input bytes before invoking them. 111 There are no asynchronous cancellation points, deadlines, retries, callbacks, 112 partial external effects, or durable commit points. A successful call returns 113 or updates the complete in-memory value; an error returns before any durable 114 commit because this crate owns no durable state. 115 116 ## Security boundary 117 118 The crate forbids unsafe Rust. Public keys and identifiers are public data and 119 must not be treated as proof of control; authentication requires a verified 120 signature in the appropriate event or signing layer. This crate deliberately 121 has no raw secret keys, key generation, nsec/NIP-49 helpers, keyrings, vaults, 122 files, SQLite, runtime paths, signer sessions, or upstream Nostr events. 123 124 ```compile_fail 125 use radroots_identity::{SecretKey, generate_keypair}; 126 ``` 127 128 Do not recreate those responsibilities through compatibility wrappers around 129 this crate. Compose the signing, Nostr, secrets, and storage packages named by 130 the migration boundary instead. 131 132 ## Intended consumers 133 134 `radroots_identity` is intended for lower-level Radroots event, signing, 135 transport, storage, and domain packages and for integrators that need the 136 portable public value model directly. Applications should normally begin with 137 the curated `radroots` crate or the advanced `radroots_sdk` composition 138 surface. 139 140 The package is pre-1.0. Its durable responsibility and package identity are 141 fixed, while API-breaking changes follow the workspace's pre-1.0 versioning 142 policy. 143 144 ## License 145 146 Licensed under either Apache-2.0 or MIT, at your option.