synta 0.2.6

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

This walkthrough covers encoding ASN.1 structures to DER with the `synta` library.

## Creating an encoder

```rust
use synta::{Encoder, Encoding};

// DER encoding (default for cryptographic data)
let mut encoder = Encoder::new(Encoding::Der);
```

## Quick encode with `ToDer`

For the common case of encoding a single value, `ToDer` removes the need to
construct an `Encoder` manually.  Import the trait and call `to_der()` or
`to_ber()` directly on any value that implements `Encode`:

```rust,ignore
use synta::{Integer, ToDer};

let n = Integer::from(42i32);

// Encode to DER
let der_bytes: Vec<u8> = n.to_der()?;
// der_bytes == [0x02, 0x01, 0x2A]

// Encode to BER (same bytes for simple types; useful for constructed types
// that may use indefinite-length encoding)
let ber_bytes: Vec<u8> = n.to_ber()?;
```

`ToDer` is a blanket impl — it is automatically available on every type that
implements `Encode`, including structs generated by `synta-codegen`.

When you need to write multiple values into a shared buffer, or want fine-grained
control over the encoding, use the `Encoder` API directly (see
[Creating an encoder](#creating-an-encoder) above).

## Encoding primitive types

### Integer

```rust
use synta::{Encoder, Encoding, Integer};

let value = Integer::from(42i32);

let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&value)?;
let encoded = encoder.finish()?;
// encoded = [0x02, 0x01, 0x2A]
```

Create from different numeric types:

```rust
use synta::Integer;

let i1 = Integer::from(42i32);
let i2 = Integer::from(12345i64);
let i3 = Integer::from(i128::MAX);
```

### Boolean

```rust
use synta::types::primitive::Boolean;

let b = Boolean::new(true);
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&b)?;
```

### OctetString

```rust
use synta::types::string::OctetString;

let data = vec![0xDE, 0xAD, 0xBE, 0xEF];
let octets = OctetString::new(data);
encoder.encode(&octets)?;
```

### ObjectIdentifier

```rust
use synta::types::oid::ObjectIdentifier;

let components = &[1, 2, 840, 113549, 1, 1, 1]; // RSA Encryption
let oid = ObjectIdentifier::new(components)?;
encoder.encode(&oid)?;
```

## Encoding string types

```rust
use synta::types::string::{Utf8String, PrintableString, IA5String};

let utf8 = Utf8String::new("Hello, World!".to_string());
encoder.encode(&utf8)?;

let printable = PrintableString::new("Hello World".to_string())?;
encoder.encode(&printable)?;

let ia5 = IA5String::new("ASCII only".to_string())?;
encoder.encode(&ia5)?;
```

## Encoding time types

```rust
use synta::types::time::{UtcTime, GeneralizedTime};

let utc = UtcTime::new(2023, 2, 23, 12, 0, 0)?;
encoder.encode(&utc)?;

let gen = GeneralizedTime::new(2023, 2, 23, 12, 0, 0, None)?;
encoder.encode(&gen)?;
```

## Encoding constructed types

### SEQUENCE

```rust
use synta::types::constructed::{Element, Sequence};
use synta::types::primitive::{Boolean, Integer};
use synta::{Encoder, Encoding};

let mut seq = Sequence::new();
seq.push(Element::Integer(Integer::from(42)));
seq.push(Element::Boolean(Boolean::new(true)));

let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&seq)?;
let encoded = encoder.finish()?;
```

### SET

```rust
use synta::types::constructed::{Element, Set};

let mut set = Set::new();
set.push(Element::Integer(Integer::from(10)));
set.push(Element::Integer(Integer::from(5)));
// In DER, elements are sorted lexicographically on encode
```

### SequenceOf

```rust
use synta::types::constructed::SequenceOf;
use synta::types::primitive::Integer;

let mut seq_of = SequenceOf::<Integer>::new();
seq_of.push(Integer::from(1));
seq_of.push(Integer::from(2));
seq_of.push(Integer::from(3));

encoder.encode(&seq_of)?;
```

## Encoding tagged types

### EXPLICIT tag

```rust
use synta::types::tagged::ExplicitTag;
use synta::types::primitive::Integer;

// [0] EXPLICIT Integer
let tagged = ExplicitTag::context_specific(0, Integer::from(42));
encoder.encode(&tagged)?;
```

### IMPLICIT tag

```rust
use synta::types::tagged::ImplicitTag;
use synta::types::primitive::Integer;

// [0] IMPLICIT Integer
let tagged = ImplicitTag::context_specific(0, Integer::from(42));
encoder.encode(&tagged)?;
```

## Building complex structures

```rust
use synta::*;
use synta::types::string::Utf8StringRef;
use synta::types::constructed::Sequence;

fn build_info() -> Sequence<'static> {
    let mut seq = Sequence::new();

    // Version
    seq.push(Element::Integer(Integer::from(3)));

    // Serial number
    seq.push(Element::Integer(Integer::from(123456)));

    // Subject (Utf8StringRef borrows from a &'static str literal)
    let mut subject = Sequence::new();
    subject.push(Element::Utf8String(Utf8StringRef::new("Example")));
    seq.push(Element::Sequence(subject));

    seq
}
```

## Serde integration

Enable the `serde` feature to add JSON serialization support:

```toml
[dependencies]
synta = { version = "0.1", features = ["serde"] }
serde_json = "1"
```

JSON representations:

| Type | JSON format |
|------|-------------|
| `Boolean` | `true` / `false` |
| `Integer` | lowercase hex string, e.g. `"2a"` |
| `Null` | `null` |
| `Real` | float |
| `OctetString` | lowercase hex string, e.g. `"deadbeef"` |
| `BitString` | `{"bytes":"<hex>","unused_bits":<n>}` |
| Text strings | plain string |
| `ObjectIdentifier` | dotted-decimal, e.g. `"1.2.840.113549"` |
| `UtcTime` | `"YYMMDDHHMMSSZ"` |
| `GeneralizedTime` | `"YYYYMMDDHHMMSSZ"` |
| `SequenceOf<T>` | JSON array |
| `Element` | `{"type":"<Name>","value":<value>}` |

Example — DER to JSON to DER round-trip:

```rust
use synta::{Decoder, Encoder, Encoding, Integer};

let der = vec![0x02, 0x02, 0x30, 0x39]; // INTEGER 12345
let mut decoder = Decoder::new(&der, Encoding::Der);
let value: Integer = decoder.decode().unwrap();

let json = serde_json::to_string(&value).unwrap(); // "\"3039\""

let restored: Integer = serde_json::from_str(&json).unwrap();

let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&restored).unwrap();
assert_eq!(encoder.finish().unwrap(), der);
```

Serialize an `Element` tree:

```rust
use synta::{Decoder, Element, Encoding};

let der = [
    0x30, 0x09,       // SEQUENCE
    0x02, 0x01, 0x01, // INTEGER 1
    0x01, 0x01, 0xff, // BOOLEAN TRUE
    0x05, 0x00,       // NULL
];

let mut decoder = Decoder::new(&der, Encoding::Der);
let element: Element = decoder.decode().unwrap();

let json = serde_json::to_string_pretty(&element).unwrap();
```

Note: `Element`, `Sequence`, and `Set` implement `Serialize` only (borrowed
lifetimes prevent `Deserialize`).  `SequenceOf<T>`, `SetOf<T>`,
`ExplicitTag<T>`, and `ImplicitTag<T>` implement both.

## Performance tips

**Reuse the decoder buffer** — decode multiple values from the same decoder:

```rust
let mut decoder = Decoder::new(&data, Encoding::Der);
let int1: Integer = decoder.decode()?;
let int2: Integer = decoder.decode()?;
```

**Reuse the encode buffer** — clear and reuse for batches:

```rust
let mut buffer = Vec::with_capacity(1024);
for item in &items {
    buffer.clear();
    let mut encoder = Encoder::new(Encoding::Der);
    encoder.encode(item)?;
    buffer.extend_from_slice(&encoder.finish()?);
    send(&buffer);
}
```

**SmallVec optimization** — integers up to 16 bytes avoid heap allocation:

```rust
// These do not allocate:
let i1 = Integer::from(42i32);    // 1–4 bytes inline
let i2 = Integer::from(i64::MAX); // 8 bytes inline
let i3 = Integer::from(i128::MAX);// 16 bytes inline

// This allocates:
let huge = Integer::from_bytes(&[0xFF; 32]); // > 16 bytes
```

## Next steps

- [PKI Workflow]pki-workflow.md — certificate, CRL, and OCSP end to end
- [ASN.1 Constructed Types]../asn1/constructed.md — SEQUENCE, SET, CHOICE details
- [Code Generation]../codegen/overview.md — generate typed structs from ASN.1 schemas