# `Cartouche.Signer`
[🔗](https://github.com/ZenHive/onchain-stack/blob/cartouche-v0.9.1/packages/cartouche/lib/cartouche/signer.ex#L1)

Cartouche.Signer is a GenServer which can sign messages. The runtime carrier
is a `{backend_module, config}` pair implementing `Cartouche.Signer.Backend`
(for instance `Cartouche.Signer.Curvy` with a local key, or
`Cartouche.Signer.CloudKMS` with GCP Cloud KMS coordinates). A legacy
`{module, function, args}` MFA is also accepted so existing call sites
(`Cartouche.Signer.sign_direct/4`, and `start_link/1` handed a 3-tuple)
keep working. In either case, start the GenServer and call
`Cartouche.Signer.sign(MySigner, "message")` to get a packed
`r || s || v` Ethereum signature (`Cartouche.signature()`).

The packed form is 65 bytes when EIP-155 `v` fits in one byte and longer
otherwise. At chain id 110, `v` is 255 or 256 depending on recovery parity,
producing 65 or 66 bytes respectively. Chain binding for legacy transactions
lives in that trailing `v` because `Transaction.V1.add_signature/2` copies
it into the RLP `v` field; emitting a parity-only byte here would silently
drop EIP-155 replay protection. Typed transactions already take y-parity
from whatever width they receive.

This library never emits a packed Ethereum signature with `s > n/2`
(EIP-2). Low-s canonicalization is applied at the emission funnel, not by
the configured backend: both the `{backend, config}` path and the legacy
MFA path pass through `Cartouche.Recover.normalize_low_s/1` before the
recovery-bit search and EIP-155 packing. The MFA carrier is kept because
`sign_direct/4` is the production signing route in the downstream `onchain`
repo; migrating that call site is a separate task. It cannot bypass the
invariant.

Note: we also enforce that a given signer process knows its public key,
such that we can verify signatures recovery bits. That is, since CloudKMS
and other signing tools don't return a recovery bit, necessary for Ethereum,
we test all 4 possible bits to make sure a signature recovers to the correct
signer address, but we need to know what that address should be to accomplish
this task.

Additionally, chain_id is used to return EIP-155 compliant signatures.

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `sign_direct` | 4 | Sign a message directly with a signing MFA and known signer address. | `message: value`, `address: value`, `signer_mfa: value`, `chain_id_or_name: value` |
| `chain_id` | 1 | Get the chain id configured for a signer process. | `name: value` |
| `address` | 1 | Get the Ethereum address controlled by a signer process. | `name: value` |
| `sign_typed_data` | 3 | Sign EIP-712 typed data the way eth_signTypedData_v4 / ethers signTypedData does. | `typed: value`, `name: value`, `opts: value` |
| `sign_message` | 3 | Sign a message the way a wallet's personal_sign / ethers signMessage does. | `message: value`, `name: value`, `opts: value` |
| `sign` | 3 | Sign a message with a running signer process. | `message: value`, `name: value`, `opts: value` |
| `start_link` | 1 | Start a signer process backed by the provided signer backend carrier. | `signer_options: value` |
| `child_spec` | 1 | Build the supervisor child specification for a signer process. | `init_arg: value` |

# `address`

```elixir
@spec address(GenServer.server()) :: Cartouche.address()
```

Gets the address for this signer.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> Cartouche.Signer.address(signer_proc) |> Cartouche.Hex.to_address()
    "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

# `chain_id`

```elixir
@spec chain_id(GenServer.server()) :: integer()
```

Gets the chain id for this signer.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> Cartouche.Signer.chain_id(signer_proc)
    5

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `sign`

```elixir
@spec sign(String.t(), GenServer.server(), Keyword.t()) ::
  {:ok, Cartouche.signature()} | {:error, term()}
```

Signs a message using this signing key.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> {:ok, sig} = Cartouche.Signer.sign("test", signer_proc)
    iex> Cartouche.Recover.recover_eth("test", sig)
    ...> |> Cartouche.Hex.to_address()
    "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> {:ok, <<_r::256, _s::256, v::binary>>} = Cartouche.Signer.sign("test", signer_proc, chain_id: 0x05f5e0ff)
    iex> :binary.decode_unsigned(v)
    0x05f5e0ff * 2 + 35 + 1

# `sign_direct`

```elixir
@spec sign_direct(
  String.t(),
  binary(),
  {module(), atom(), [any()]},
  integer() | atom() | nil
) ::
  {:ok, Cartouche.signature()} | {:error, String.t()}
```

Directly sign a message, not using a signer process.

This is mostly used internally, but can be used safely externally as well.
The returned packed `r || s || v` signature is always low-s (EIP-2), regardless of
whether the MFA backend normalized. Width follows `Cartouche.signature()`:
65 bytes when EIP-155 `v` fits in one byte, longer when it does not.

# `sign_message`

```elixir
@spec sign_message(binary(), GenServer.server(), Keyword.t()) ::
  {:ok, Cartouche.signature()} | {:error, term()}
```

Signs a message as `personal_sign` / ethers `signMessage` / viem `signMessage` do.

Two differences from `sign/3`, both of which trip callers coming from
JavaScript libraries: the EIP-191 `"\x19Ethereum Signed Message:\n"` prefix is
applied before hashing, and `v` is 27/28 rather than the EIP-155 form.
`sign/3` remains the primitive for transaction and EIP-712 digests, which
must **not** carry the prefix.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> {:ok, sig} = Cartouche.Signer.sign_message("hello", signer_proc)
    iex> Cartouche.Recover.recover_personal_sign("hello", sig) |> Cartouche.Hex.to_address()
    "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> {:ok, <<_r::256, _s::256, v>>} = Cartouche.Signer.sign_message("hello", signer_proc)
    iex> v in [27, 28]
    true

# `sign_typed_data`

```elixir
@spec sign_typed_data(Cartouche.Typed.t(), GenServer.server(), Keyword.t()) ::
  {:ok, Cartouche.signature()} | {:error, term()}
```

Signs EIP-712 typed data as `eth_signTypedData_v4` / ethers `signTypedData` /
viem `signTypedData` do.

Encodes the `0x1901 || domainSeparator || hashStruct` payload with
`Cartouche.Typed.encode/1` and signs it with `v` in 27/28. No EIP-191
prefix is involved — that is `sign_message/3`. `sign/3` with the encoded
payload gives the same digest with an EIP-155 `v` instead.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> typed = %Cartouche.Typed{
    ...>   domain: %Cartouche.Typed.Domain{name: "Complex Array", version: "1"},
    ...>   types: %{"Array" => %Cartouche.Typed.Type{fields: [{"a", {:uint, 256}}, {"b", {:uint, 256}}, {"c", :string}, {"d", :bool}]}},
    ...>   value: %{"a" => 55, "b" => 66, "c" => "Hello", "d" => true}
    ...> }
    iex> {:ok, sig} = Cartouche.Signer.sign_typed_data(typed, signer_proc)
    iex> Cartouche.Recover.recover_eth(Cartouche.Typed.encode(typed), sig) |> Cartouche.Hex.to_address()
    "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"
    iex> <<_r::256, _s::256, v>> = sig
    iex> v in [27, 28]
    true

# `start_link`

```elixir
@spec start_link(
  mfa: Cartouche.Signer.Backend.t() | {module(), atom(), [any()]},
  name: GenServer.name() | nil
) :: GenServer.on_start()
```

Starts a new Cartouche.Signer process.

---

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