lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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.