Skip to main content

TransparencyLog

Struct TransparencyLog 

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

The transparency log: the push-attestation log, plus the evidence that it has not been rewritten.

§What it adds, and what it deliberately does not

It adds nothing to the attestation format. The Merkle tree is a pure function of the lines already on disk — leaf i is SHA-256(0x00 ‖ line_i) over the exact bytes of line i, no canonicalisation, no re-serialisation — so there is no second encoding to keep in step and no chance of hashing something other than what is stored.

A signed tree head at size N pins every line up to N. Rewriting line 3 changes the root, so every head issued since stops verifying against the file: the tampering is detected by any holder of any later head, including one who never saw the original line. That is the property, and TransparencyLog::audit is the check.

What it does not add is a consistency proof between two heads (RFC 6962’s second proof type). A verifier with two heads can today detect that the file changed under them; it cannot yet be shown that head M is a prefix-extension of head N without recomputing from the records. That is a real gap and it is named rather than papered over.

Implementations§

Source§

impl TransparencyLog

Source

pub fn under(root: impl AsRef<Path>) -> Self

The push-attestation log under a data root.

Source

pub fn over(records: impl Into<PathBuf>, heads: impl Into<PathBuf>) -> Self

Any append-only JSONL file, with its own heads beside it.

The Merkle machinery cares about lines, not about what is in them, so the same log covers push attestations and build provenance without a second implementation (one implementation). What is record-specific is exactly two methods — Self::records and Self::prove_pack — and they say so.

Source

pub fn records(&self) -> AttestationLog

This log’s records, read as push attestations.

Only meaningful for the push log; a build log’s lines are a different shape and this would refuse them. Everything else on this type is record-agnostic.

Source

pub fn records_path(&self) -> &Path

Where the records are.

Source

pub fn heads_path(&self) -> &Path

Where the signed heads are.

Source

pub fn lines_of(&self) -> Result<Vec<String>>

The record lines, for a caller that decodes them itself.

pub because the build log’s records are not PushAttestations and have to be parsed by whoever knows their shape.

Source

pub fn len(&self) -> Result<usize>

How many records the log holds.

Source

pub fn is_empty(&self) -> Result<bool>

Source

pub fn root(&self) -> Result<String>

The current Merkle root, hex.

Source

pub fn issue_head( &self, key: &PrivateKey, at_unix_ms: i64, ) -> Result<SignedTreeHead>

Issue a signed tree head over everything the log currently holds, and append it.

Returns the head. Issuing one over an empty log is allowed and meaningful: it is how a verifier learns the log exists and held nothing at that moment, which is the only way “this server has never accepted a push” can be evidence rather than an absence.

Source

pub fn heads(&self) -> Result<Vec<SignedTreeHead>>

Every signed head that has been issued, oldest first.

Source

pub fn prove(&self, index: usize) -> Result<Option<Inclusion>>

The inclusion proof for the record at index.

None when the log does not hold that many records — a proof for a record that is not there is not an empty proof.

Source

pub fn prove_pack(&self, pack_hash: &str) -> Result<Option<Inclusion>>

Find the record for a pack hash, and prove it.

The lookup a verifier actually makes: it holds an artifact, the artifact names a pack, and it wants to know the push that landed it. Scans, which is honest about the cost — an index over the log is a later problem and pretending one exists would be worse than the scan.

Source

pub fn audit(&self, key: &PublicKey) -> Result<AuditVerdict>

Check every signed head against the records on disk.

This is what the log is for. It answers three different questions, and keeping them apart is the point:

  • a head that does not verify means somebody wrote a head they could not sign — or the key rotated and the verifier was not told;
  • a head that does verify over a root the records no longer produce means the records were changed after they were signed for, which is tampering and nothing else;
  • a head covering more records than exist means lines were removed.

The first verdict wins and is returned; an operator fixes one thing at a time.

Trait Implementations§

Source§

impl Clone for TransparencyLog

Source§

fn clone(&self) -> Self

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 TransparencyLog

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,

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<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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> 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<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> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

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

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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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