Skip to main content

Authority

Struct Authority 

Source
pub struct Authority { /* private fields */ }
Expand description

A tailnet-lock authority as a client tracks it: the current trusted-key State and the chain head. Built by replaying the AUM chain (or from a control-provided checkpoint); the client then uses Authority::node_key_authorized to decide whether a peer is trusted.

Implementations§

Source§

impl Authority

Source

pub fn head(&self) -> AumHash

The current chain head hash (Go Authority.Head).

Source

pub fn state(&self) -> &State

The trusted-key state.

Source

pub fn head_matches(&self, head: &AumHash) -> bool

Whether head (e.g. decoded from TkaInfo.head) matches this authority’s head. A client that finds a mismatch must resync before trusting verifications.

Source

pub fn key_trusted(&self, key_id: &[u8]) -> bool

Whether a key with the given key_id is currently trusted by this authority (Go Authority.KeyTrusted / a State.GetKey(keyID) != nil check).

key_id is the 32-byte ed25519 public key (Go Key25519/NLKey id is the pubkey). This is the gate a mutation caller uses before attempting to sign: a node whose network-lock key is not trusted cannot produce a signature the authority would accept (see NodeKeySignature::sign_direct / Aum::sign), so the builder checks this first rather than submitting a doomed signature. Verify-and-log posture is unchanged — this only reads the trusted-key set.

Source

pub fn node_key_authorized( &self, node_key: &[u8], signature_cbor: &[u8], ) -> Result<(), TkaError>

Verify that node_key is authorized under the current authority state by the given node-key-signature CBOR blob (Go Authority.NodeKeyAuthorized).

Fail-closed: a credential-only signature, an untrusted authorizing key, a malformed blob, or a bad signature all return Err.

§Errors

Returns TkaError::Decode if signature_cbor is malformed, TkaError::CredentialCannotAuthorize for a credential-only signature, TkaError::UntrustedKey if the authorizing key is not in the current state, TkaError::NodeKeyMismatch if the signature does not cover node_key, or TkaError::BadSignature if cryptographic verification fails.

Source

pub fn node_key_authorized_with_details( &self, node_key: &[u8], signature_cbor: &[u8], ) -> Result<Option<RotationDetails>, TkaError>

As node_key_authorized, but on success also returns the RotationDetails of the signature — Some iff it is a SigKind::Rotation chain, None otherwise. Mirrors Go Authority.NodeKeyAuthorizedWithDetails.

The verification performed is byte-identical to node_key_authorized (same decode → credential-reject → trusted-key lookup → signature check); the details are a pure post-success walk of the already-decoded nested chain, never an extra cryptographic operation. A netmap-wide rotation filter feeds these details to drop peers presenting a rotated-away node key.

§Errors

Same as node_key_authorized: TkaError::Decode, TkaError::CredentialCannotAuthorize, TkaError::UntrustedKey, TkaError::NodeKeyMismatch, or TkaError::BadSignature.

Source§

impl Authority

Source

pub fn from_verified_chain(chain: VerifiedAumChain) -> Authority

Build an Authority from a VerifiedAumChain — the trust-boundary constructor.

Because a VerifiedAumChain can only be produced by VerifiedAumChain::verify (which runs Go’s aumVerify on every link), this is the constructor a live client must use when the chain originates from an untrusted source (the control plane / /machine/tka/* sync RPC). The type system makes the signature check un-skippable: there is no way to reach this function with an unverified chain. Mirrors Go tka.Open, which folds only AUMs already verified by Inform.

Source

pub fn from_chain(aums: &[Aum]) -> Result<Authority, TkaError>

Build an Authority by replaying a linear chain of AUMs from genesis to head (Go tka.Authority.Head after computeActiveChain on a single confirmed branch), checking only the chain’s structure (genesis kind, parent links, key-state transitions, checkpoint StateID) — NOT AUM signatures.

§This is NOT a trust boundary

from_chain does not verify that each AUM is signed by keys trusted at its parent. It is safe only for chains whose authenticity is already established by other means — the existing unit tests, and a chain the caller has itself fed through VerifiedAumChain::verify. For any chain that comes from an untrusted source (the control plane), use VerifiedAumChain::verify + Authority::from_verified_chain, which the type system makes impossible to bypass. (A malicious control plane could otherwise forge an AddKey/RemoveKey here and silently defeat tailnet lock — the exact threat TKA exists to stop.)

aums must be ordered parent→child: the first is the genesis — a NoOp, AddKey, or Checkpoint with no parent (Go computeStateAt rejects any other kind as an invalid genesis) — and each subsequent AUM’s prev_aum_hash must equal the prior AUM’s Aum::hash. A slice that is actually a suffix of a chain (its first AUM names a parent not in the slice) is rejected rather than mis-rooted.

For the forked case (competing children of one parent), use Authority::from_forked_chain.

§Errors

TkaError::BadChain if aums is empty or its genesis is an invalid kind; TkaError::BadParent if a link doesn’t chain (incl. a genesis that carries a parent); TkaError::BadKeyState for an invalid add/remove/update or a mismatched checkpoint StateID; TkaError::Decode for a malformed checkpoint/add.

Source

pub fn from_forked_chain( prefix: &[Aum], branches: &[&[Aum]], ) -> Result<Authority, TkaError>

Resolve a single fork point: a shared linear prefix (genesis→fork point, parent-ordered) followed by branches, the competing children of the fork point. The active child is chosen by pick_next_aum’s deterministic rules (weight → RemoveKey preference → lowest hash), evaluated against the state at the fork point, and applied. This is the consensus-critical selection every node must make identically; the linear Authority::from_chain is the common (no-fork) case.

Each branch must be exactly one AUM. In this single-AUM-per-branch shape the choice is provably identical to Go’s pickNextAUM over the fork point’s children. A multi-step branch is rejected (TkaError::BadChain) rather than mis-resolved: Go re-runs pickNextAUM at every link (advanceByPrimary), re-evaluating weight against the evolving state, so judging a whole multi-AUM branch by its first AUM alone could pick a different active head than Go and silently fork the trusted-key set. Implementing the per-step loop (and a general multi-fork DAG walk) is deferred to when the sync layer can actually surface such a chain; until then this guard keeps the model honest. (The common re-bootstrap case — competing single-AUM heads — is fully covered.)

§Errors

As Authority::from_chain, plus TkaError::BadChain if branches is empty, or any branch is not exactly one AUM.

Source§

impl Authority

Source

pub fn sync_offer( &self, storage: &dyn AumStore, oldest: AumHash, ) -> Result<SyncOffer, TkaError>

Build the SyncOffer this authority would send a peer (Go Authority.SyncOffer): its head plus every checkpoint on the chain back to oldest, ending with oldest. oldest is the oldest AUM the caller holds (Go a.oldestAncestor.Hash()); our verify-only Authority does not track it, so it is passed in — typically the genesis hash of the chain the caller staged in storage.

Checkpoints, not a sample: a node compacts its chain (keep the last 24 AUMs, keep two weeks, then back to the last checkpoint) and can end up holding only a few dozen AUMs. A sparse sample of positions taken from a long chain can then be entirely disjoint from the window a peer kept, leaving the peer unable to find a common ancestor and stuck re-polling with a permanently stale view. Compaction is guaranteed to leave at least one checkpoint behind, so offering the checkpoints is what makes an intersection findable.

storage must contain the chain from head back to oldest; a gap simply truncates the ancestor list early (the walk breaks on the first missing parent, exactly like Go).

Source

pub fn missing_aums( &self, storage: &dyn AumStore, remote_offer: &SyncOffer, oldest: AumHash, ) -> Result<Vec<Aum>, TkaError>

Given a peer’s SyncOffer, compute the AUMs they are missing — the ones to send them so their chain catches up to ours (Go Authority.MissingAUMs). storage must hold our chain. Returns an empty Vec when the peer is already up to date.

Mirrors Go: compute our own offer, find the intersection of the two chains, then gather every AUM from the intersection forward to our head (excluding the intersection AUM itself).

Trait Implementations§

Source§

impl Clone for Authority

Source§

fn clone(&self) -> Authority

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Authority

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Send + Sync>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<A, T> DynMessage<A> for T
where A: Actor + Message<T>, T: Send + 'static,

Source§

fn handle_dyn<'a>( self: Box<T>, state: &'a mut A, actor_ref: ActorRef<A>, tx: Option<Sender<Result<Box<dyn Any + Send>, SendError<Box<dyn Any + Send>, Box<dyn Any + Send>>>>>, stop: &'a mut bool, ) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn ReplyError>>> + Send + 'a>>

Handles the dyn message with the provided actor state, ref, and reply sender.
Source§

fn as_any(self: Box<T>) -> Box<dyn Any>

Casts the type to a Box<dyn Any>.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ReplyError for T
where T: Debug + Send + 'static,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more