Cartouche.Signer.Curvy (Cartouche v0.5.0)

Copy Markdown View Source

Signer backend that signs with a local secp256k1 private key.

Implements Cartouche.Signer.Backend — its config is the raw private-key binary. The behaviour's Cartouche.Signer.Backend.sign_payload/2 signs the 32-byte digest it is handed directly; sign/2 is a convenience wrapper that keccaks a raw message first.

Note: this should not be used in production systems. Please see Cartouche.Signer.CloudKMS.

Summary

Functions

Get the Ethereum address associated with the given private key.

Get the uncompressed secp256k1 public key for the given private key.

Signs a raw message, keccak-digesting it first.

Deprecated alias for sign_payload/2; signs an already-digested message.

Signs the 32-byte digest it is handed directly — the pure-payload contract.

Functions

get_address(private_key)

@spec get_address(binary()) :: {:ok, binary()} | {:error, String.t()}

Get the Ethereum address associated with the given private key.

Examples

iex> priv_key = "800509fa3e80882ad0be77c27505bdc91380f800d51ed80897d22f9fcc75f4bf" |> Base.decode16!(case: :mixed)
iex> {:ok, address} = Cartouche.Signer.Curvy.get_address(priv_key)
iex> Cartouche.Hex.to_address(address)
"0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

public_key(private_key)

@spec public_key(binary()) :: {:ok, binary()} | {:error, String.t()}

Get the uncompressed secp256k1 public key for the given private key.

Examples

iex> priv_key = "800509fa3e80882ad0be77c27505bdc91380f800d51ed80897d22f9fcc75f4bf" |> Base.decode16!(case: :mixed)
iex> {:ok, pub} = Cartouche.Signer.Curvy.public_key(priv_key)
iex> Cartouche.Hex.to_address(Cartouche.Address.from_public_key(pub))
"0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

sign(message, private_key)

@spec sign(String.t(), binary()) :: {:ok, Curvy.Signature.t()} | {:error, String.t()}

Signs a raw message, keccak-digesting it first.

Back-compat convenience over sign_payload/2 for EIP-191-style raw-message signing; for typed data (EIP-712, Hyperliquid) the caller should compute the digest and call sign_payload/2 directly.

Examples

iex> use Cartouche.Hex
iex> priv_key = ~h[0x800509fa3e80882ad0be77c27505bdc91380f800d51ed80897d22f9fcc75f4bf]
iex> {:ok, sig} = Cartouche.Signer.Curvy.sign("test", priv_key)
iex> {:ok, recid} = Cartouche.Recover.find_recid("test", sig, ~h[0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7])
iex> Cartouche.Recover.recover_eth("test", %{sig|recid: recid}) |> Cartouche.Hex.to_address()
"0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

sign_digest(message_hash, private_key)

@spec sign_digest(String.t(), binary()) ::
  {:ok, Curvy.Signature.t()} | {:error, String.t()}

Deprecated alias for sign_payload/2; signs an already-digested message.

sign_payload(digest, private_key)

@spec sign_payload(binary(), binary()) ::
  {:ok, Curvy.Signature.t()} | {:error, String.t()}

Signs the 32-byte digest it is handed directly — the pure-payload contract.

This performs no hashing: the caller (Cartouche.Signer) owns digest computation, so the same backend serves plain Eth tx, EIP-712, and Hyperliquid.

Examples

iex> use Cartouche.Hex
iex> priv_key = ~h[0x800509fa3e80882ad0be77c27505bdc91380f800d51ed80897d22f9fcc75f4bf]
iex> message_hash = ~h[0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658]
iex> {:ok, sig} = Cartouche.Signer.Curvy.sign_payload(message_hash, priv_key)
iex> {:ok, recid} = Cartouche.Recover.find_recid("test", sig, ~h[0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7])
iex> Cartouche.Recover.recover_eth("test", %{sig|recid: recid}) |> Cartouche.Hex.to_address()
"0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"