import { type Sphere } from "./did.js"; export { base64url, base64urlDecode, sha256Hex } from "./encoding.js"; export interface KeyPair { seed: Uint8Array; publicKey: Uint8Array; } export declare function generateKeyPair(): KeyPair; /** * Ed25519 seed → X25519 key pair, per libsodium's ed25519_sk_to_curve25519. * The public key is the Montgomery form; the private key is the SHA-512 first * half with the standard curve25519 clamp. */ export declare function edSeedToX25519Secret(seed: Uint8Array): Uint8Array; /** * Ed25519 PUBLIC key → X25519 public key (Edwards → Montgomery). * * Needed when we only have the delegate's Ed25519 pubkey (the thing stored in * `mandate.grantee.pubkey`) and must derive the X25519 key used to wrap zone / * gamma DEKs for them. Symmetric invariant with the seed-based path: * * x25519PublicFromSecret(edSeedToX25519Secret(seed)) * === ed25519PubToX25519Pub(ed.getPublicKey(seed)) * * The formula is RFC 7748 §4.1 applied to the decoded Edwards y-coordinate: * * u = (1 + y) / (1 - y) (mod p) * * where p = 2^255 - 19 and y is the field element encoded in the lower 255 * bits of the 32-byte Ed25519 public key (the top bit is the sign of x and is * discarded for this conversion). */ export declare function ed25519PubToX25519Pub(edPub: Uint8Array): Uint8Array; /** X25519 public key from a clamped scalar, using @noble/ed25519 internals. */ export declare function x25519PublicFromSecret(sk: Uint8Array): Uint8Array; /** Roles a sealed seed file can carry: the root, the three Ethos spheres, or * the optional dedicated `#data` sub-protocol sphere. */ export type SeedRole = "root" | Sphere | "data"; export interface StoredSeed { aithos: "0.1.0"; role: SeedRole; seed_hex: string; created_at: string; } export interface Identity { handle: string; displayName: string; root: KeyPair; public: KeyPair; circle: KeyPair; self: KeyPair; /** * Dedicated data sub-protocol sphere (spec/data/02-key-hierarchy.md §2.2). * Owner data/asset PDS envelopes sign under this `#data` key so the root key * stays cold and the data key can rotate independently. OPTIONAL for backward * compatibility: identities created before the #data sphere landed (and * imported recovery files lacking it) have no `data` key and sign data ops * under `#root` as before. */ data?: KeyPair; } export declare function createIdentity(handle: string, displayName: string): Identity; export declare function writeIdentityToDisk(id: Identity): { dir: string; did: string; }; /** * A tracked identity is one we hold the public data for — `did.json` plus * whatever is in `ethos/` — but for which we do NOT possess the private * sphere seeds. This is the normal state when you've imported someone else's * ethos bundle to follow or verify it. * * Tracked identities can: * - have their metadata listed (handle, DID, public sphere keys) * - have their `public` zone read (plaintext, signature-verifiable) * - have their ethos partially verified (public zone + manifest signature) * * Tracked identities CANNOT: * - decrypt circle/self zones (no sphere secret) * - issue mandates / revocations / rotations (no sphere secret) * - append new revisions under either the sphere key or a delegate (the * write-mandate flow still requires the subject's sphere key to have * previously issued the mandate, which implies owned state) * * The distinction is purely an on-disk one: sealed seed files present ⇒ owned. * Missing one or more ⇒ tracked. */ export declare class TrackedIdentityError extends Error { constructor(handle: string, missing: string[]); } /** True if any of the four sealed seed files is missing on disk. */ export declare function isTrackedIdentity(handle: string): boolean; /** * Public, read-only view of an identity, derived entirely from `did.json`. * Anyone who has downloaded the identity's DID document can reconstruct this. */ export interface IdentityMetadata { handle: string; displayName: string; did: string; tracked: boolean; sphereDids: Record; /** Ed25519 public key per sphere, multibase-encoded. */ sphereKeys: Record; didDocument: DidDocument; } /** * Load an identity's public metadata (did.json only). Works for both owned and * tracked identities. Throws only if `did.json` is missing. */ export declare function loadIdentityMetadata(handle: string): IdentityMetadata; export declare function loadIdentity(handle: string): Identity; export interface DidDocument { "@context": string[]; id: string; verificationMethod: VerificationMethod[]; keyAgreement: VerificationMethod[]; service?: Service[]; aithos: { version: "0.1.0"; display_name?: string; created_at: string; rotated: RotatedEntry[]; /** * Mandate-revocation EPOCH. When present (ISO-8601 UTC), every mandate * whose `issued_at` is strictly before this instant is VOID — verifiers * MUST reject it, regardless of individual revocation objects. One * root-signed did.json write thus revokes ALL pre-epoch mandates at once, * and makes garbage-collecting per-mandate revocation objects safe (the * epoch subsumes them). Absent ⇒ no epoch (legacy: nothing rejected). */ mandates_void_before?: string; }; proof?: Proof; } interface VerificationMethod { id: string; type: "Ed25519VerificationKey2020" | "X25519KeyAgreementKey2020"; controller: string; publicKeyMultibase: string; } interface Service { id: string; type: string; serviceEndpoint: string; } interface Proof { type: "Ed25519Signature2020"; created: string; verificationMethod: string; proofPurpose: "assertionMethod"; proofValue: string; } interface RotatedEntry { sphere: Sphere; previous_key: string; rotated_at: string; reason: string; } export declare function verifyDidDocument(doc: DidDocument): boolean;