pub struct MutationProof { /* private fields */ }Expand description
Authorization for one write to one registration.
Carries only what the record cannot derive from the call itself: the sequence number claiming a position in the record’s history, and the signature over the whole request. Everything else the signature covers (which agent, which record instance, which operation, which arguments) the store already holds or was just handed, so a proof has nothing in it that could contradict the write it accompanies.
§Examples
use agent_uri::AgentUri;
use agent_uri_attestation::SigningKey;
use agent_uri_dht::{Endpoint, Mutation, MutationProof, Registration};
let key = SigningKey::generate();
let uri = AgentUri::parse(
"agent://anthropic.com/assistant/chat/llm_01h455vb4pex5vsknk084sn02q"
).unwrap();
// In practice this record comes back from a lookup.
let record = Registration::new(
uri,
key.verifying_key(),
vec![Endpoint::https("us-east-1.agent.anthropic.com")],
);
let endpoints = vec![Endpoint::https("eu-west-1.agent.anthropic.com")];
// Migrating does not change when the record lapses, so the expiry signed
// is the one the record already carries.
let mutation = Mutation::UpdateEndpoint {
endpoints: &endpoints,
expires_at: record.expires_at(),
};
let proof = MutationProof::sign_next(&key, &record, &mutation);
assert!(proof.authorizes(&record, &mutation).is_ok());Implementations§
Source§impl MutationProof
impl MutationProof
Sourcepub fn sign_registration(key: &SigningKey, record: &Registration) -> Self
pub fn sign_registration(key: &SigningKey, record: &Registration) -> Self
Signs the registration of record.
Covers the record as submitted: its key, endpoints, expiry, instance identity, and starting sequence. A relay can therefore forward a registration but not alter one.
Checks that this proof authorizes the registration of record.
Unlike a later write there is no history to advance past, so only the signature is at issue: the record’s own key must have signed the record exactly as submitted.
§Errors
Returns DhtError::Unauthorized if the signature does not answer for
this record.
Sourcepub fn sign_next(
key: &SigningKey,
record: &Registration,
mutation: &Mutation<'_>,
) -> Self
pub fn sign_next( key: &SigningKey, record: &Registration, mutation: &Mutation<'_>, ) -> Self
Signs the next write to record.
The usual way to build a proof: look the record up, then sign against what you read. Signing against a stale copy produces a proof the store will refuse rather than one it will misapply.
Sourcepub fn sign(
key: &SigningKey,
agent_uri: &AgentUri,
version: RecordVersion,
mutation: &Mutation<'_>,
) -> Self
pub fn sign( key: &SigningKey, agent_uri: &AgentUri, version: RecordVersion, mutation: &Mutation<'_>, ) -> Self
Signs a write against an explicitly named version.
For a caller that cached a record’s version rather than the record.
Sourcepub const fn from_parts(sequence: u64, signature: Signature) -> Self
pub const fn from_parts(sequence: u64, signature: Signature) -> Self
Reassembles a proof received over the wire.
Checks that this proof authorizes mutation against record.
The whole authorization rule, in one place: the signature must be the record’s own key over exactly this record instance, position, operation and arguments, and the position must advance. A store calls this and has nothing further to decide.
§Errors
Returns DhtError::Unauthorized if the signature does not answer for
this write, or DhtError::StaleSequence if it does but the write
does not advance the record’s history.