synta 0.1.6

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# Merkle Tree Certificates


`synta.mtc` implements the ASN.1 types from `draft-ietf-plants-merkle-tree-certs`.
All classes are immutable (frozen) and constructed via `from_der` static methods.

```python
import synta.mtc as mtc
```

Name fields such as `issuer_der` and `subject_der` are raw DER-encoded `Name` SEQUENCES;
pass them to `synta.parse_name_attrs()` to decode the DN attributes.

## ProofNode

A single node in a Merkle inclusion proof path.

```python
class ProofNode:
    @staticmethod
    def from_der(data: bytes) -> ProofNode: ...
    is_left: bool   # True if this is the left sibling in the path
    hash: bytes     # raw hash bytes at this proof node
```

## Subtree

A hash subtree covering leaf range `[start, end)`.

```python
class Subtree:
    @staticmethod
    def from_der(data: bytes) -> Subtree: ...
    start: int    # start leaf index (inclusive)
    end: int      # end leaf index (exclusive)
    value: bytes  # aggregated hash bytes for [start, end)
```

## SubtreeProof

Left and right subtree lists for log compaction.

```python
class SubtreeProof:
    @staticmethod
    def from_der(data: bytes) -> SubtreeProof: ...
    left_subtrees: list[Subtree] | None
    right_subtrees: list[Subtree] | None
```

## InclusionProof

Merkle inclusion proof for a log entry.

```python
class InclusionProof:
    @staticmethod
    def from_der(data: bytes) -> InclusionProof: ...
    log_entry_index: int              # leaf position of the certified entry
    tree_size: int                    # total leaves at proof time
    inclusion_path: list[ProofNode]   # ordered sibling hashes
```

## LogID

Identifies a transparency log by its hash algorithm and public key.

```python
class LogID:
    @staticmethod
    def from_der(data: bytes) -> LogID: ...
    hash_algorithm_oid: str   # hash algorithm OID (dot-notation)
    public_key_der: bytes     # DER-encoded SubjectPublicKeyInfo
```

## CosignerID

Identifies a cosigner (witness) by the issuer and serial number of their certificate.

```python
class CosignerID:
    @staticmethod
    def from_der(data: bytes) -> CosignerID: ...
    issuer_der: bytes    # DER-encoded issuer Name SEQUENCE
    serial_number: int   # certificate serial number
```

## Checkpoint

A signed Merkle tree head from a transparency log.

```python
class Checkpoint:
    @staticmethod
    def from_der(data: bytes) -> Checkpoint: ...
    log_id: LogID
    tree_size: int
    tree_minimum_index: int | None   # optional lower leaf bound
    root_value: bytes                # Merkle root hash bytes
    timestamp: str                   # GeneralizedTime string
```

## SubtreeSignature

A cosigner's signature over a subtree and checkpoint.

```python
class SubtreeSignature:
    @staticmethod
    def from_der(data: bytes) -> SubtreeSignature: ...
    cosigner: CosignerID              # cosigner identity
    subtree: Subtree                  # subtree being signed
    checkpoint: Checkpoint            # checkpoint signed alongside the subtree
    signature_algorithm_oid: str      # dotted-decimal OID
    signature: bytes                  # raw signature bytes
```

## TbsCertificateLogEntry

The to-be-signed body of a Merkle Tree Certificate log entry.

```python
class TbsCertificateLogEntry:
    @staticmethod
    def from_der(data: bytes) -> TbsCertificateLogEntry: ...

    issuer_der: bytes                            # raw Name DER
    validity_not_before: str                     # GeneralizedTime string
    validity_not_after: str                      # GeneralizedTime string
    subject_der: bytes                           # raw Name DER
    subject_public_key_algorithm_oid: str        # algorithm OID (dot-notation)
    subject_public_key_hash: bytes               # hash of the SubjectPublicKeyInfo
    issuer_unique_id: bytes | None
    subject_unique_id: bytes | None
    extensions_der: bytes | None                 # raw SEQUENCE OF Extension DER
```

## MerkleTreeCertEntry

Top-level CHOICE wrapper for a Merkle Tree Certificate log entry.

```python
class MerkleTreeCertEntry:
    @staticmethod
    def from_der(data: bytes) -> MerkleTreeCertEntry: ...
    variant: str                              # "NullEntry" or "TbsCertEntry"
    tbs_cert_entry: TbsCertificateLogEntry | None
    # tbs_cert_entry is set when variant == "TbsCertEntry", else None.
```

## LandmarkID

Identifies a landmark log: a `LogID` plus the tree size at issuance.

```python
class LandmarkID:
    @staticmethod
    def from_der(data: bytes) -> LandmarkID: ...
    log_id: LogID   # identifies the landmark log
    tree_size: int  # tree size at issuance
```

## StandaloneCertificate

A full standalone Merkle Tree Certificate.

```python
class StandaloneCertificate:
    @staticmethod
    def from_der(data: bytes) -> StandaloneCertificate: ...
    tbs_certificate_der: bytes              # DER-encoded TBSCertificate
    inclusion_proof: InclusionProof
    subtree_proof: SubtreeProof
    subtree_signatures: list[SubtreeSignature]
    signature_algorithm_oid: str            # dotted-decimal OID
    signature: bytes
```

## LandmarkCertificate

A Merkle Tree Landmark Certificate.

```python
class LandmarkCertificate:
    @staticmethod
    def from_der(data: bytes) -> LandmarkCertificate: ...
    tbs_certificate_der: bytes   # DER-encoded TBSCertificate
    inclusion_proof: InclusionProof
    landmark_id: LandmarkID
    signature_algorithm_oid: str
    signature: bytes
```

## Usage

```python
import synta
import synta.mtc as mtc

# Parse a Merkle Tree Certificate log entry
entry = mtc.MerkleTreeCertEntry.from_der(data)
if entry.variant == "TbsCertEntry":
    tbs = entry.tbs_cert_entry
    issuer = synta.parse_name_attrs(tbs.issuer_der)
    subject = synta.parse_name_attrs(tbs.subject_der)
    print(f"issuer: {issuer}")
    print(f"subject: {subject}")
    print(f"not before: {tbs.validity_not_before}")

# Parse a StandaloneCertificate
sc = mtc.StandaloneCertificate.from_der(data)
print(f"leaf index: {sc.inclusion_proof.log_entry_index}")
print(f"tree size: {sc.inclusion_proof.tree_size}")
print(f"cosignatures: {len(sc.subtree_signatures)}")
```