# `MAVLink2.Signing`
[🔗](https://github.com/isaiahdw/mavlink2/blob/v0.1.0/lib/mavlink2/signing.ex#L1)

MAVLink v2 message signing: a 32-byte secret shared by both ends, a link
id, and a timestamp that only moves forward.

A signed frame has `incompat_flags` bit 0 set and 13 bytes after its
checksum: the link id, a 48-bit timestamp (little endian, 10 µs units
since 2015-01-01 00:00:00 UTC) and the first 6 bytes of

    SHA-256(secret ++ frame from STX through checksum ++ link id ++ timestamp)

Receiving, a frame is accepted only if its signature matches and its
timestamp is later than the last one accepted from the same stream
(link id, system, component). A stream not seen before is accepted if its
timestamp is no more than one minute behind this end's timestamp, which
is at least the clock. The signature is checked before any stream state
changes, so a forged frame moves nothing.

Sending, each frame takes a timestamp later than the previous one and no
earlier than the clock, so a clock that steps back cannot repeat one.
This end's timestamp also follows the latest accepted from a peer.

Each frame this end signs also records its own stream, so its frames
reflected back to it are refused as replays.

The replay window is only as good as the clock: a board that boots with
no real time accepts stale frames until its timestamp catches up. Such a
board can persist `timestamp` and pass it back to `new/2`.

# `t`

```elixir
@type t() :: %MAVLink2.Signing{
  accept_unsigned: [non_neg_integer()] | :all,
  key: &lt;&lt;_::256&gt;&gt;,
  link_id: 0..255,
  streams: %{required({0..255, 0..4_294_967_295, 0..255}) =&gt; non_neg_integer()},
  timestamp: non_neg_integer()
}
```

# `encode`

```elixir
@spec encode(t(), MAVLink2.Frame.t(), module(), non_neg_integer()) ::
  {:ok, binary(), t()} | {:error, term()}
```

Encodes `frame` signed: the signed bit set before the checksum, then the
signature with the next timestamp at or after `now`.

# `iflag_signed`

```elixir
@spec iflag_signed() :: 1
```

# `new`

```elixir
@spec new(&lt;&lt;_::256&gt;&gt;, keyword()) :: t()
```

Signing state for `key`. Options:

| | |
| --- | --- |
| `:link_id` | default 0 |
| `:accept_unsigned` | message ids delivered even when unsigned, or `:all` (for a link that is secure by itself, such as USB); default none |
| `:timestamp` | the earliest timestamp, for a board that persists it; default 0 |

# `sign`

```elixir
@spec sign(t(), binary(), non_neg_integer()) :: {binary(), t()}
```

Signs `wire`, an encoded frame whose `incompat_flags` already carry the
signed bit, with the next timestamp at or after `now` (a `timestamp/1`).

# `timestamp`

```elixir
@spec timestamp(integer()) :: non_neg_integer()
```

A timestamp for `unix_us`, Unix time in microseconds.

# `verify`

```elixir
@spec verify(t(), MAVLink2.Frame.t(), non_neg_integer()) ::
  {:ok, t()} | {:error, :unsigned | :bad_signature | :replay}
```

Checks a decoded frame at `now`, this end's clock as a `timestamp/1`.
`{:ok, state}` for a signed frame that verifies and is not a replay, or
an unsigned one of an `accept_unsigned` id; otherwise
`{:error, :unsigned | :bad_signature | :replay}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
