Attestation Class

Overview

The Attestation class encapsulates a digital signature and additional metadata. Attestations are associated with verifiable data, credentials, and transactions and represent the main mechanism by which those data are verified.

The signature of an attestation authenticates the original data object’s serialized data, the serialization of all previous attestations in order, and the metadata of this attestation.

Package: keychain.core.attestation

from keychain.core.attestation import Attestation

Class Definition

class Attestation(SerializableObject):
    """An attestation is an encapsulation of a digital signature and additional metadata."""

Constructor

def __init__(
    self,
    serialized_string: Optional[bytes] = None,
    serialization_format: SerializationFormat = SerializationFormat.PROTOBUF,
    c_pointer: Optional[ctypes.c_void_p] = None,
) -> None

Initialize an Attestation object.

Parameters:

  • serialized_string (bytes, optional) - Serialized attestation bytes to deserialize

  • serialization_format (SerializationFormat, optional) - Format of the serialized data (defaults to PROTOBUF)

  • c_pointer (ctypes.c_void_p, optional) - Existing C pointer to wrap

Example:

from keychain.core.attestation import Attestation
from keychain.constants import SerializationFormat

# Create from serialized data
attestation_bytes = b"..."  # Previously serialized attestation
attestation = Attestation(
    serialized_string=attestation_bytes,
    serialization_format=SerializationFormat.PROTOBUF
)

# Create from existing C pointer (typically from library functions)
attestation = Attestation(c_pointer=existing_pointer)

Class Methods

from_copy()

@classmethod
def from_copy(cls, other: "Attestation") -> "Attestation"

Create a copy of an attestation.

Parameters:

  • other (Attestation) - The attestation to copy

Returns: A new Attestation instance that is a deep copy

Example:

original_attestation = get_attestation()
copied_attestation = Attestation.from_copy(original_attestation)

Instance Methods

copy()

def copy(self) -> "Attestation"

Create a deep copy of this attestation.

Returns: A new Attestation instance that is a deep copy

serialize()

def serialize(self) -> bytes

Serialize the attestation.

Returns: Bytes serialization of the attestation in protobuf format

Example:

attestation = get_attestation()
serialized_data = attestation.serialize()
# Can be stored or transmitted and later reconstructed
restored_attestation = Attestation(serialized_data)

data_type()

def data_type(self) -> DataType

Get the data type.

Returns: DataType.ATTESTATION

Properties

Core Signature Properties

index

@property
def index(self) -> int

Get the index (sequence number) of this attestation.

Returns: The index number of this attestation in the attestation chain

signature

@property
def signature(self) -> str

Get the digital signature.

Returns: The signature in hexadecimal format

prev_signature

@property
def prev_signature(self) -> str

Get the previous signature in the attestation chain.

Returns: The previous signature in hexadecimal format

public_key

@property
def public_key(self) -> str

Get the public key used for signature verification.

Returns: The public key in hexadecimal format

Cryptographic Properties

algorithm

@property
def algorithm(self) -> SignatureScheme

Get the cryptographic algorithm used to produce the signature.

Returns: The SignatureScheme used for signing

Example:

attestation = get_attestation()
algorithm = attestation.algorithm
print(f"Signature algorithm: {algorithm.name}")

Temporal Properties

timestamp

@property
def timestamp(self) -> int

Get the timestamp of when the attestation was created.

Returns: Timestamp as milliseconds since the epoch (Jan 1, 1970 00:00:00 UTC)

Example:

import datetime

attestation = get_attestation()
timestamp_ms = attestation.timestamp
timestamp_dt = datetime.datetime.fromtimestamp(timestamp_ms / 1000)
print(f"Attestation created at: {timestamp_dt}")

version

@property
def version(self) -> Version

Get the data format version.

Returns: The Version of the data format used

Approval and Status Properties

is_approval

@property
def is_approval(self) -> bool

Get whether the attestation signals approval or rejection.

Returns: True if approval, False if rejection

Example:

attestation = get_attestation()
if attestation.is_approval:
    print("Attestation indicates approval")
else:
    print("Attestation indicates rejection")

is_reattachable

@property
def is_reattachable(self) -> bool

Get whether the attestation can be reattached to other verifiable objects.

Returns: True if the attestation may be reattached to a verifiable object

Metadata Properties

tags

@property
def tags(self) -> TagSet

Get the tags of the attestation.

Returns: The TagSet used to store additional application-level data

Example:

attestation = get_attestation()
tags = attestation.tags

# Read application-specific metadata
app_id = tags.get_tag_value("app", "identifier")
priority = tags.get_tag_value("processing", "priority")

variables

@property
def variables(self) -> TagSet

Get the variables of the attestation.

Returns: The TagSet to store mutable application-level stack variables

Example:

attestation = get_attestation()
variables = attestation.variables

# Read consensus state variables
consensus_stage = variables.get_tag_value("consensus", "stage")
participant_count = variables.get_tag_value("consensus", "participants")

Comparison Methods

eq()

def __eq__(self, other: object) -> bool

Compare attestations for equality.

Parameters:

  • other (Attestation) - The other attestation to compare

Returns: True if attestations are equal, False otherwise

Example:

attestation1 = get_attestation()
attestation2 = attestation1.copy()

if attestation1 == attestation2:
    print("Attestations are identical")

String Representation

str()

def __str__(self) -> str

Return string representation of the attestation.

Returns: Hex string of serialized data

repr()

def __repr__(self) -> str

Return detailed string representation.

Returns: Detailed representation showing class and serialized form

Example: Working with Attestations

from keychain.core.attestation import Attestation
from keychain.constants import SignatureScheme
import datetime

def analyze_attestation(attestation: Attestation):
    """Analyze an attestation and display its properties."""

    print("=== Attestation Analysis ===")

    # Basic properties
    print(f"Index: {attestation.index}")
    print(f"Approval: {'Yes' if attestation.is_approval else 'No'}")
    print(f"Reattachable: {'Yes' if attestation.is_reattachable else 'No'}")

    # Cryptographic information
    print(f"Algorithm: {attestation.algorithm.name}")
    print(f"Public Key: {attestation.public_key[:32]}...")  # First 32 chars
    print(f"Signature: {attestation.signature[:32]}...")    # First 32 chars

    # Temporal information
    timestamp_dt = datetime.datetime.fromtimestamp(attestation.timestamp / 1000)
    print(f"Timestamp: {timestamp_dt}")
    print(f"Version: {attestation.version.name}")

    # Metadata
    tags = attestation.tags
    variables = attestation.variables
    print(f"Tags available: {len(tags) > 0}")
    print(f"Variables available: {len(variables) > 0}")

def verify_attestation_chain(attestations: list[Attestation]):
    """Verify that attestations form a valid chain."""

    if not attestations:
        return True

    print("Verifying attestation chain...")

    # Sort by index
    sorted_attestations = sorted(attestations, key=lambda a: a.index)

    for i, attestation in enumerate(sorted_attestations):
        print(f"\\nAttestation {i}:")
        print(f"  Index: {attestation.index}")
        print(f"  Approval: {attestation.is_approval}")

        if i > 0:
            # Check that previous signature matches
            prev_attestation = sorted_attestations[i-1]
            if attestation.prev_signature == prev_attestation.signature:
                print("  ✓ Chain link valid")
            else:
                print("  ✗ Chain link broken")
                return False
        else:
            print("  ✓ First attestation in chain")

    print("\\n✓ Attestation chain is valid")
    return True

def create_attestation_summary(attestations: list[Attestation]) -> dict:
    """Create a summary of attestation properties."""

    summary = {
        "total_attestations": len(attestations),
        "approval_count": 0,
        "rejection_count": 0,
        "algorithms_used": set(),
        "reattachable_count": 0,
        "timestamp_range": None
    }

    if not attestations:
        return summary

    timestamps = []

    for attestation in attestations:
        # Count approvals/rejections
        if attestation.is_approval:
            summary["approval_count"] += 1
        else:
            summary["rejection_count"] += 1

        # Track algorithms
        summary["algorithms_used"].add(attestation.algorithm.name)

        # Count reattachable
        if attestation.is_reattachable:
            summary["reattachable_count"] += 1

        # Collect timestamps
        timestamps.append(attestation.timestamp)

    # Calculate timestamp range
    if timestamps:
        min_ts = min(timestamps)
        max_ts = max(timestamps)
        min_dt = datetime.datetime.fromtimestamp(min_ts / 1000)
        max_dt = datetime.datetime.fromtimestamp(max_ts / 1000)
        summary["timestamp_range"] = (min_dt, max_dt)

    # Convert set to list for JSON serialization
    summary["algorithms_used"] = list(summary["algorithms_used"])

    return summary

# Usage examples
def attestation_examples():
    """Demonstrate attestation usage."""

    # Get attestations from some source (e.g., verifiable data)
    attestations = get_attestations_from_credential()

    if attestations:
        # Analyze first attestation
        analyze_attestation(attestations[0])

        # Verify the chain
        verify_attestation_chain(attestations)

        # Create summary
        summary = create_attestation_summary(attestations)
        print(f"\\n=== Summary ===")
        print(f"Total attestations: {summary['total_attestations']}")
        print(f"Approvals: {summary['approval_count']}")
        print(f"Rejections: {summary['rejection_count']}")
        print(f"Algorithms: {', '.join(summary['algorithms_used'])}")

        if summary['timestamp_range']:
            start, end = summary['timestamp_range']
            print(f"Time range: {start} to {end}")

if __name__ == "__main__":
    attestation_examples()

Example: Attestation Metadata Usage

from keychain.core.attestation import Attestation
from keychain.core.tag_set import TagSet

def examine_attestation_metadata(attestation: Attestation):
    """Examine and work with attestation metadata."""

    print("=== Attestation Metadata ===")

    # Access tags (immutable application data)
    tags = attestation.tags
    print("Tags (application metadata):")

    # Common tag namespaces
    try:
        # Application identification
        app_name = tags.get_tag_value("app", "name")
        app_version = tags.get_tag_value("app", "version")
        print(f"  Application: {app_name} v{app_version}")
    except:
        print("  No application metadata")

    try:
        # User/entity information
        user_id = tags.get_tag_value("user", "id")
        user_role = tags.get_tag_value("user", "role")
        print(f"  User: {user_id} (role: {user_role})")
    except:
        print("  No user metadata")

    try:
        # Context information
        operation = tags.get_tag_value("context", "operation")
        resource = tags.get_tag_value("context", "resource")
        print(f"  Context: {operation} on {resource}")
    except:
        print("  No context metadata")

    # Access variables (mutable consensus state)
    variables = attestation.variables
    print("\\nVariables (consensus state):")

    try:
        # Consensus protocol state
        stage = variables.get_tag_value("consensus", "stage")
        participants = variables.get_tag_value("consensus", "participants")
        print(f"  Consensus: stage={stage}, participants={participants}")
    except:
        print("  No consensus state")

    try:
        # Transaction state
        tx_status = variables.get_tag_value("transaction", "status")
        tx_amount = variables.get_tag_value("transaction", "amount")
        print(f"  Transaction: status={tx_status}, amount={tx_amount}")
    except:
        print("  No transaction state")

def filter_attestations_by_criteria(attestations: list[Attestation]) -> dict:
    """Filter attestations by various criteria."""

    filtered = {
        "approvals": [],
        "rejections": [],
        "recent": [],  # Last 24 hours
        "high_security": [],  # Strong algorithms
        "reattachable": []
    }

    # Current time for recency check
    current_time = datetime.datetime.now().timestamp() * 1000
    day_ago = current_time - (24 * 60 * 60 * 1000)

    # Strong signature algorithms
    strong_algorithms = {
        SignatureScheme.ECDSA_ECP_SECP384R1,
        SignatureScheme.ECDSA_ECP_SECP521R1,
        SignatureScheme.RSASS_PSS_4096
    }

    for attestation in attestations:
        # Filter by approval status
        if attestation.is_approval:
            filtered["approvals"].append(attestation)
        else:
            filtered["rejections"].append(attestation)

        # Filter by recency
        if attestation.timestamp >= day_ago:
            filtered["recent"].append(attestation)

        # Filter by security level
        if attestation.algorithm in strong_algorithms:
            filtered["high_security"].append(attestation)

        # Filter by reattachability
        if attestation.is_reattachable:
            filtered["reattachable"].append(attestation)

    return filtered

def create_attestation_report(attestations: list[Attestation]) -> str:
    """Create a comprehensive report of attestations."""

    report_lines = ["ATTESTATION ANALYSIS REPORT", "=" * 30, ""]

    if not attestations:
        report_lines.append("No attestations found.")
        return "\\n".join(report_lines)

    # Basic statistics
    total = len(attestations)
    approvals = sum(1 for a in attestations if a.is_approval)
    rejections = total - approvals
    reattachable = sum(1 for a in attestations if a.is_reattachable)

    report_lines.extend([
        f"Total Attestations: {total}",
        f"Approvals: {approvals} ({approvals/total*100:.1f}%)",
        f"Rejections: {rejections} ({rejections/total*100:.1f}%)",
        f"Reattachable: {reattachable} ({reattachable/total*100:.1f}%)",
        ""
    ])

    # Algorithm distribution
    algorithm_counts = {}
    for attestation in attestations:
        alg_name = attestation.algorithm.name
        algorithm_counts[alg_name] = algorithm_counts.get(alg_name, 0) + 1

    report_lines.append("Algorithm Distribution:")
    for algorithm, count in sorted(algorithm_counts.items()):
        percentage = count / total * 100
        report_lines.append(f"  {algorithm}: {count} ({percentage:.1f}%)")

    report_lines.append("")

    # Timeline analysis
    timestamps = [a.timestamp for a in attestations]
    if timestamps:
        min_ts = min(timestamps)
        max_ts = max(timestamps)
        min_dt = datetime.datetime.fromtimestamp(min_ts / 1000)
        max_dt = datetime.datetime.fromtimestamp(max_ts / 1000)
        duration = max_dt - min_dt

        report_lines.extend([
            "Timeline:",
            f"  First: {min_dt}",
            f"  Last: {max_dt}",
            f"  Duration: {duration}",
            ""
        ])

    # Chain validation
    sorted_attestations = sorted(attestations, key=lambda a: a.index)
    chain_valid = True
    broken_links = []

    for i in range(1, len(sorted_attestations)):
        current = sorted_attestations[i]
        previous = sorted_attestations[i-1]

        if current.prev_signature != previous.signature:
            chain_valid = False
            broken_links.append(i)

    report_lines.extend([
        f"Chain Validation: {'✓ Valid' if chain_valid else '✗ Invalid'}",
        f"Broken Links: {len(broken_links)}"
    ])

    if broken_links:
        report_lines.append(f"  Broken at indices: {broken_links}")

    return "\\n".join(report_lines)

# Usage examples
def metadata_examples():
    """Demonstrate attestation metadata usage."""

    attestations = get_attestations_from_transaction()

    if attestations:
        # Examine metadata of first attestation
        examine_attestation_metadata(attestations[0])

        # Filter attestations
        filtered = filter_attestations_by_criteria(attestations)
        print(f"\\nFiltered Results:")
        print(f"  Approvals: {len(filtered['approvals'])}")
        print(f"  Recent: {len(filtered['recent'])}")
        print(f"  High Security: {len(filtered['high_security'])}")

        # Generate report
        report = create_attestation_report(attestations)
        print(f"\\n{report}")

if __name__ == "__main__":
    metadata_examples()

Error Handling

Attestation operations can raise various exceptions:

Example:

from keychain.exceptions import KeychainValidationError, KeychainSecurityError

try:
    # Create attestation from serialized data
    attestation = Attestation(serialized_data)

    # Access properties
    signature = attestation.signature
    public_key = attestation.public_key
    timestamp = attestation.timestamp

    # Check approval status
    if attestation.is_approval:
        print("Attestation indicates approval")

    # Access metadata
    tags = attestation.tags
    variables = attestation.variables

except KeychainValidationError as e:
    print(f"Validation error: {e}")
except KeychainSecurityError as e:
    print(f"Security error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

See Also