@me2em/core
    Preparing search index...

    Class Attestation

    A parent-signed statement binding a derived child key to a name and a grant. Chains of attestations (Identity → Handle → SubHandle) allow any third party to verify sessions offline using only the root public key, with grant constraints enforced at verification time.

    Tokens have the form base64url(payload).base64url(signature) and are deterministic: the same inputs (including jti and now) always produce byte-identical tokens.

    • * import { ed25519 } from '@noble/curves/ed25519.js';
      *
      * // Issuer (a Signer — Identity/Handle qualify) and subject public key:
      * const identity = await Identity.fromSeed(seed);
      * const childPub = ed25519.getPublicKey(ed25519.utils.randomPrivateKey());
      *
      * const A = await Attestation.issue(identity, childPub, 'station-001', {
      * audiences: ['ev-app.com'],
      * scopes: ['charge:start', 'charge:stop'],
      * maxSessionTtl: 7200,
      * subNamePatterns: ['connector-*'],
      * });
      *
      * const ok = await Attestation.verifySignature(A.token, identity.getPublicKey()); // true
      * const payload = Attestation.decode(A.token); // structure only — no sig, no time
      *
    Index
    • Verifies the token signature against a public key.

      A signature whose length differs from the 64-byte Ed25519 size is rejected with false before any crypto runs (PR-7 pre-check) — the method therefore never throws for short/long signatures.

      Parameters

      • token: string
      • signerPublicKey: Uint8Array

      Returns Promise<boolean>

      false for a bad signature or a wrong key. Returns false for any invalid signature, including malformed lengths. It still throws AttestationError MALFORMED/FORMAT for structurally invalid tokens (see decode).

    • Wildcard name matching used for subNamePatterns. A pattern matches if it equals name, or ends with * and name starts with the pattern's prefix. A lone * matches everything.

      Parameters

      • name: string
      • patterns: string[]

      Returns boolean

      Attestation.matchNamePattern('connector-1', ['connector-*']); // true
      Attestation.matchNamePattern('meter-1', ['connector-*']); // false
      Attestation.matchNamePattern('anything', ['*']); // true
    • Creates and signs a new attestation.

      The subject name is canonicalized (NFKC → lowercase → trim) before signing; the subject public key must be exactly 32 bytes. Serialization is deterministic: fields are emitted in a fixed order and undefined grant fields are omitted from the JSON entirely (distinguishable from []).

      The signer is a Signer — typically the issuing Identity (root attestations) or Handle (SubHandle attestations). Raw private keys never cross a trust boundary as function arguments (D2): the key material stays encapsulated in the signer object.

      Parameters

      • signer: Signer

        Object producing the Ed25519 signature via sign(data). Identity and Handle implement Signer; custom implementations (remote/HSM-backed signing) are accepted structurally.

      • subjectPublicKey: Uint8Array

        32-byte Ed25519 public key being attested.

      • subjectName: string

        Child name; canonicalized before signing.

      • grant: AttestationGrant

        Constraints enforced by verifiers (Mode 2).

      • Optionalopts: {
            ttlSeconds?: number;
            expiresAt?: number;
            jti?: string;
            now?: number;
            subjectWallet?: string;
            subjectWalletChain?: string;
            subjectWalletPath?: string;
        }

        Lifetime control: ttlSeconds (default one year), expiresAt (overrides ttlSeconds), jti (default random UUID), now (fixed clock for deterministic tests). Optional wallet extensions (specs/v1.0.md §5.1): subjectWallet, subjectWalletChain (exact CAIP-2) and subjectWalletPath — emitted in that canonical order after jti; absent fields are omitted (byte-identity for tokens without them). Pairing and structural rules are enforced at issue time; when an adapter is registered for the chain, the address must pass adapter.isValidAddress() (fail-closed).

      Returns Promise<Attestation>

      The attestation with payload, token and jti accessors.

      MALFORMED/FORMAT if the grant is structurally invalid (bad scopes/TTL/audiences or a wildcard not at the end of a subNamePatterns entry).

      If signer has no callable sign method — e.g. when a raw private key is passed (the pre-v1.0 form is no longer accepted).

      If subjectPublicKey is not 32 bytes.

      const att = await Attestation.issue(rootIdentity, childPub, 'Station-1',
      { scopes: ['read'], maxSessionTtl: 3600 }, { ttlSeconds: 600 });