9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
151 lines
8.9 KiB
Markdown
151 lines
8.9 KiB
Markdown
NIP-OA
|
|
======
|
|
|
|
Owner Attestation
|
|
-----------------
|
|
|
|
`draft` `optional`
|
|
|
|
This NIP defines an optional `auth` tag by which an owner key authorizes an agent key to publish events under the agent's own authorship.
|
|
|
|
## Motivation
|
|
|
|
NIP-26 defines a sound Schnorr-signature mechanism for proving that one key authorized another key subject to explicit conditions.
|
|
NIP-26 assigns the event to the delegator semantically, and that semantic MUST NOT be reused for agent provenance.
|
|
This NIP reuses NIP-26 as prior art for the credential format and signing flow and defines the credential as authorization evidence only.
|
|
A valid `auth` tag is a reusable capability: the same tag MAY appear on multiple events by the same agent key provided each event satisfies the conditions.
|
|
An event that includes a valid `auth` tag remains authored by `event.pubkey`.
|
|
|
|
## Non-Goals
|
|
|
|
This NIP does not define impersonation.
|
|
This NIP does not define key derivation.
|
|
This NIP does not define relay-side author rewriting.
|
|
|
|
## The Tag
|
|
|
|
Events MAY include zero or one `auth` tag.
|
|
If an event contains more than one `auth` tag, verifiers and clients MUST treat the event as having no valid `auth` tag.
|
|
Agents MAY publish events without an `auth` tag.
|
|
Agents that require provenance to be respected by verifiers SHOULD include a valid `auth` tag.
|
|
The `auth` tag MUST contain exactly four elements:
|
|
|
|
```json
|
|
["auth", "<owner-pubkey-hex>", "<conditions>", "<sig-hex>"]
|
|
```
|
|
|
|
- `<owner-pubkey-hex>`: 64-character lowercase hex encoding of the owner's 32-byte x-only public key as defined in BIP-340.
|
|
- `<conditions>`: UTF-8 string containing zero or more clauses separated by `&`.
|
|
- `<sig-hex>`: 128-character lowercase hex encoding of the 64-byte Schnorr signature.
|
|
|
|
An `auth` tag with fewer or more than four elements is malformed and MUST be rejected.
|
|
|
|
The signing preimage is the UTF-8 byte sequence of `nostr:agent-auth:` || `event.pubkey` || `:` || `<conditions>`.
|
|
The domain separator string is exactly `nostr:agent-auth:`.
|
|
The signed message is `SHA256(preimage)`.
|
|
The owner MUST produce `<sig-hex>` as a BIP-340 Schnorr signature over the signed message with the owner's secret key.
|
|
|
|
Each clause in `<conditions>` MUST be one of:
|
|
|
|
- `kind=<decimal>`
|
|
- `created_at<unix-timestamp>`
|
|
- `created_at>unix-timestamp`
|
|
|
|
The `<conditions>` string MUST be either the empty string or a non-empty ASCII string of the form `clause` or `clause&clause&...`.
|
|
Whitespace is not permitted anywhere in `<conditions>`.
|
|
Empty clauses are invalid.
|
|
Clause names and operators are case-sensitive and MUST appear exactly as specified above.
|
|
A trailing `&`, a leading `&`, or `&&` is malformed and MUST be rejected.
|
|
|
|
The decimal encoding in a clause MUST be canonical base-10 with no leading zeroes except `0`.
|
|
Values in `kind=` clauses MUST be in the range `0` to `65535`.
|
|
Values in `created_at<` and `created_at>` clauses MUST be in the range `0` to `4294967295`.
|
|
An empty `<conditions>` string imposes no additional event constraints.
|
|
Verifiers MUST evaluate every clause.
|
|
Verifiers MUST reject an `auth` tag that contains an unsupported clause, malformed decimal encoding, invalid public key, or invalid signature.
|
|
If `<owner-pubkey-hex>` equals `event.pubkey`, the `auth` tag is invalid and MUST be rejected.
|
|
An event satisfies `kind=<n>` if and only if `event.kind = n`.
|
|
An event satisfies `created_at<t>` if and only if `event.created_at < t`.
|
|
An event satisfies `created_at>t` if and only if `event.created_at > t`.
|
|
Clause order is part of the signed preimage and verifiers MUST use the exact `<conditions>` string from the tag when verifying the signature.
|
|
Implementers MUST NOT reorder, deduplicate, normalize, or canonicalize the `<conditions>` string before computing the preimage.
|
|
Verifiers MUST NOT reinterpret a valid `auth` tag as an identity override.
|
|
|
|
## Relay Behavior
|
|
|
|
Relays require no changes to support this NIP.
|
|
Relays MAY store, index, and forward the `auth` tag as any other event tag.
|
|
Relays MUST NOT rewrite event authorship on the basis of an `auth` tag.
|
|
Relays MUST NOT be required to verify an `auth` tag.
|
|
|
|
## Client Behavior
|
|
|
|
Clients MUST validate the event according to the core Nostr event rules, including that `id` and `sig` are valid for `event.pubkey`, before treating an `auth` tag as verified provenance.
|
|
A valid `auth` tag on an otherwise invalid event does not establish provenance.
|
|
Clients that process an `auth` tag SHOULD verify the owner signature and the conditions against the event.
|
|
Clients MUST treat the agent key in `event.pubkey` as the only author key for the event.
|
|
Clients MUST NOT display the owner key as the author of the event solely because of a valid `auth` tag.
|
|
Clients MUST NOT merge the event into owner-authored timelines, author indexes, or pubkey-filtered results for the owner solely because of a valid `auth` tag.
|
|
Clients SHOULD display provenance only when the `auth` tag verifies successfully, and any such display MUST be clearly distinguished from authorship (for example, "authorized by \<owner\>").
|
|
Clients SHOULD ignore an invalid `auth` tag for protocol purposes.
|
|
Clients MUST NOT display owner provenance when the `auth` tag is invalid.
|
|
|
|
## Security Properties
|
|
|
|
The owner key and the agent key are independent keys.
|
|
Compromise of the agent secret key MUST NOT imply compromise of the owner secret key.
|
|
Compromise of the agent secret key permits only signatures by the compromised agent key.
|
|
Owners SHOULD bound authorization lifetime with a `created_at<...` clause when revocation latency matters.
|
|
Owners MAY revoke future authorization by refusing to issue new `auth` tags.
|
|
A `created_at<...` or `created_at>...` clause constrains the event's self-declared `created_at` field, which the agent controls.
|
|
These clauses do not enforce wall-clock expiry; a misbehaving agent can backdate `event.created_at` to satisfy an expired window.
|
|
Relays or clients that require wall-clock freshness MUST enforce it independently of this NIP.
|
|
Verification MUST NOT depend on the verifier's local clock, receipt time, or relay storage time.
|
|
|
|
## Privacy Considerations
|
|
|
|
Including an `auth` tag intentionally links the owner key and the agent key.
|
|
Verifiers MAY correlate all events that reuse the same owner key and agent key pair.
|
|
Agents that omit the `auth` tag avoid this disclosure but also omit the provenance claim defined by this NIP.
|
|
|
|
## Test Vectors
|
|
|
|
The following vector uses `owner_secret = 0000000000000000000000000000000000000000000000000000000000000001`.
|
|
The corresponding `owner_pubkey` is `79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798`.
|
|
The following vector uses `agent_secret = 0000000000000000000000000000000000000000000000000000000000000002`.
|
|
The corresponding `agent_pubkey` is `c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5`.
|
|
|
|
```text
|
|
conditions=kind=1&created_at<1713957000
|
|
preimage=nostr:agent-auth:c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5:kind=1&created_at<1713957000
|
|
sha256(preimage)=08cdecd55af4c28d3801fd69615dcf5cc04fab3bc134b38a840bf157197069a6
|
|
auth_sig=8b7df2575caf0a108374f8471722b233c53f9ff827a8b0f91861966c3b9dd5cb2e189eae9f49d72187674c2f5bd244145e10ff86c9f257ffe65a1ee5f108b369
|
|
tag=["auth","79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","kind=1&created_at<1713957000","8b7df2575caf0a108374f8471722b233c53f9ff827a8b0f91861966c3b9dd5cb2e189eae9f49d72187674c2f5bd244145e10ff86c9f257ffe65a1ee5f108b369"]
|
|
tag-bytes-hex=5b2261757468222c2237396265363637656639646362626163353561303632393563653837306230373032396266636462326463653238643935396632383135623136663831373938222c226b696e643d3126637265617465645f61743c31373133393537303030222c223862376466323537356361663061313038333734663834373137323262323333633533663966663832376138623066393138363139363663336239646435636232653138396561653966343964373231383736373463326635626432343431343565313066663836633966323537666665363561316565356631303862333639225d
|
|
```
|
|
|
|
## Signed Event Example
|
|
|
|
```json
|
|
{
|
|
"id": "d892a65e7677e0554ebb70ee16deeb6a0727dba46450fb4bc001291d7bff971b",
|
|
"pubkey": "c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
|
|
"created_at": 1713956400,
|
|
"kind": 1,
|
|
"tags": [["auth", "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "kind=1&created_at<1713957000", "8b7df2575caf0a108374f8471722b233c53f9ff827a8b0f91861966c3b9dd5cb2e189eae9f49d72187674c2f5bd244145e10ff86c9f257ffe65a1ee5f108b369"]],
|
|
"content": "owner-attested agent event",
|
|
"sig": "7fd38992b70b5e9e113644e51b4c8ee2227f3bdd402b1855f8786c0600394ab3ec2621742a7bad0b0000b93d4d1ae6e39525f286a3c1029f43f46c3359a6c76f"
|
|
}
|
|
```
|
|
|
|
## Invalid Test Vectors
|
|
|
|
Verifiers MUST reject each of the following:
|
|
|
|
- An event containing two `auth` tags.
|
|
- An `auth` tag with fewer or more than four elements.
|
|
- An `auth` tag whose `<conditions>` string is `kind=1&` (trailing delimiter).
|
|
- An `auth` tag whose `<conditions>` string is `kind=01` (leading zero).
|
|
- An `auth` tag whose `<owner-pubkey-hex>` equals `event.pubkey` (self-attestation).
|
|
- An otherwise well-formed `auth` tag attached to an event whose Nostr `id` or `sig` is invalid.
|