# Commits And Signatures `Potable.Commit` and `Potable.Signing` implement atproto commit v3 creation and verification with algorithm-aware signatures. Supported signature algorithms: - Ed25519 (`:ed25519`) - ES256K (`:es256k`, ECDSA secp256k1 + SHA-256) - ES256 (`:es256`, ECDSA P-256 + SHA-256) For ECDSA algorithms, Potable emits compact 64-byte `(r || s)` signatures with low-S normalization. Verification defaults to strict compact low-S mode. Set `allow_malleable_sig: true` on `Potable.Signing.verify/4` to accept DER/high-S compatibility inputs. ## Commit Shape A commit is a DAG-CBOR map with: - `"did"`: repository DID - `"version"`: integer `3` - `"data"`: MST root CID - `"rev"`: TID revision string - `"prev"`: previous commit CID (absent in genesis) - `"sig"`: signature bytes as CBOR byte string ## Signing Flow `Potable.Commit.create/4` and `create/5` follow this sequence: 1. Build unsigned commit map (`did`, `version`, `data`, `rev`, optional `prev`) 2. DAG-CBOR encode unsigned map deterministically 3. Sign unsigned bytes with configured algorithm/private key 4. Add `"sig"` field as `%CBOR.Tag{tag: :bytes, value: sig_bytes}` 5. DAG-CBOR encode full signed commit 6. CID-address the full commit bytes Return value: - `{:ok, commit_cid, commit_bytes}` ## Verification Flow `Potable.Commit.verify/2`: 1. decode commit bytes 2. validate required fields and commit version 3. extract signature bytes 4. remove `"sig"` from map 5. re-encode unsigned map deterministically 6. verify signature against one or more verifier candidates Result: - `:ok` - `:invalid` (signature mismatch) - `{:error, reason}` (decode/structure/verifier-spec failures) ## Interop Note Algorithm support and ECDSA wire-format normalization are implemented. Remaining interop work is primarily around deployment-level DID key resolution and trust policy. ## Key Operations (`Potable.Signing`) - `generate_keypair/0` -> Ed25519 `{public_key, private_key}` - `generate_keypair/1` -> algorithm-selected keypair - `sign(message, private_key)` -> Ed25519 signature (backward compatible) - `sign(message, private_key, alg: alg)` -> algorithm-selected signature - `verify(message, signature, public_key)` -> Ed25519 verify (backward compatible) - `verify(message, signature, public_key, alg: alg)` -> algorithm-selected verify ## Revision IDs (`Potable.TID`) By default, `create/4` generates `rev` with `Potable.TID.new/0`: - 13 characters - sortable lexical ordering - timestamp + clock ID encoding `create/5` allows passing explicit `rev`. ## Decode Helper `Potable.Commit.decode/1` returns decoded commit map and unwraps `"sig"` to raw binary for easier downstream handling. ## Important Encoding Detail - Potable emits genesis commits with `"prev"` omitted. - Potable verification accepts either omitted `"prev"` or `"prev": nil` in imported commits.