{"id":51061230,"url":"https://github.com/dereckscompany/ethsign","last_synced_at":"2026-06-23T02:03:10.783Z","repository":{"id":363178449,"uuid":"1262219089","full_name":"dereckscompany/ethsign","owner":"dereckscompany","description":"Local Ethereum and EVM wallet signing in pure R: keccak-256 hashing, secp256k1 ECDSA with Ethereum recovery id and low-s, EIP-712 typed-data signing, and address derivation. The cryptographic primitives needed to authenticate and sign orders on EVM venues such as Hyperliquid and Polymarket.","archived":false,"fork":false,"pushed_at":"2026-06-07T20:11:17.000Z","size":78,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-07T20:15:17.624Z","etag":null,"topics":["pkgdown","r","rcpp","testthat"],"latest_commit_sha":null,"homepage":null,"language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dereckscompany.png","metadata":{"files":{"readme":"README.Rmd","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T18:10:21.000Z","updated_at":"2026-06-07T20:11:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dereckscompany/ethsign","commit_stats":null,"previous_names":["dereckscompany/ethsign"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dereckscompany/ethsign","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dereckscompany%2Fethsign","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dereckscompany%2Fethsign/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dereckscompany%2Fethsign/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dereckscompany%2Fethsign/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dereckscompany","download_url":"https://codeload.github.com/dereckscompany/ethsign/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dereckscompany%2Fethsign/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34672250,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pkgdown","r","rcpp","testthat"],"created_at":"2026-06-23T02:03:09.802Z","updated_at":"2026-06-23T02:03:10.777Z","avatar_url":"https://github.com/dereckscompany.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n```{r setup, include = FALSE}\nknitr::opts_chunk$set(\n  warning = FALSE,\n  message = FALSE,\n  fig.path = \"./man/figures/README-\",\n  fig.align = \"center\",\n  collapse = TRUE,\n  comment = \"#\u003e\"\n)\n\n# Every example below runs at render time. Signing is OFFLINE and deterministic\n# (RFC 6979), so the document executes with no network, no funds, and no chain\n# connection -- the printed signatures are the real, reproducible output.\nbox::use(ethsign[eth_signer, eth_address, keccak256, eip712_digest, ecrecover, as_rsv, as_hex])\n```\n\n# ethsign \u003cimg src=\"man/figures/logo.png\" align=\"right\" height=\"139\" alt=\"ethsign hex sticker\" /\u003e\n\n**ethsign creates the cryptographic signature a crypto wallet makes -- the digital \"stamp\" that proves a request came from your wallet and authorizes it -- directly from R.**\n\nPure-R Ethereum and EVM wallet signing primitives: keccak-256 hashing,\nsecp256k1 ECDSA with the Ethereum recovery id and low-s normalisation, EIP-712\ntyped-data signing, EIP-191 `personal_sign`, and address derivation. These are\nthe cryptographic primitives needed to authenticate and sign orders on EVM\nvenues such as Hyperliquid and Polymarket, with no native dependencies beyond\n`gmp` and `openssl`.\n\n\u003e **A note on responsibility.** This package handles private keys and produces\n\u003e signatures that can authorize real transactions. You are responsible for how\n\u003e you use it and for keeping your keys safe.\n\n## What this is — and what it is NOT\n\n`ethsign` is the signing **maths** plus a small signer object that holds a key\nin memory. That is the whole scope.\n\nIt is **NOT** a wallet application. It does not:\n\n- hold or move funds,\n- read balances,\n- connect to any chain or RPC node,\n- broadcast, submit, or track transactions.\n\nIt **does**:\n\n- derive an Ethereum address from a private key,\n- hash data with keccak-256,\n- build the EIP-712 typed-data digest,\n- produce a canonical `(r, s, v)` ECDSA signature, deterministically, and\n- recover the signing address from a signature (`ecrecover`).\n\nWhat you do with the resulting signature -- post it to a venue, embed it in a\nraw transaction, present it as a login -- is up to you and your other tooling.\n\n## Installation\n\n```{r install, eval = FALSE}\nrenv::install(\"dereckscompany/ethsign\")\n\n# or, if you use remotes instead of renv:\n# install.packages(\"remotes\")\n# remotes::install_github(\"dereckscompany/ethsign\")\n```\n\n## Quick start\n\nEvery block below is executed at render time against no network. We use the\nwell-known `0x0123…0123` test key (the canonical eth_account / Hyperliquid\nexample key) so the output is reproducible; in real use, read your key from the\n`ETH_PRIVATE_KEY` environment variable (`eth_signer()` with no argument) or\ngenerate a throwaway one with `eth_signer_random()`.\n\n### Create a signer\n\n```{r signer}\nsigner \u003c- eth_signer(\n  \"0x0123456789012345678901234567890123456789012345678901234567890123\"\n)\n\n# The address is derived from the key; the private key is never printed.\nsigner$address\nsigner\n```\n\n### Sign EIP-712 typed data\n\nA single struct over atomic field types is all most venues need. Here is a\nHyperliquid `usdSend` user action (an exact reproduction of the official\nHyperliquid Python SDK testnet vector):\n\n```{r typed-data}\ndomain \u003c- list(\n  name = \"HyperliquidSignTransaction\",\n  version = \"1\",\n  chainId = 421614,\n  verifyingContract = \"0x0000000000000000000000000000000000000000\"\n)\n\ntypes \u003c- list(\n  list(name = \"hyperliquidChain\", type = \"string\"),\n  list(name = \"destination\", type = \"string\"),\n  list(name = \"amount\", type = \"string\"),\n  list(name = \"time\", type = \"uint64\")\n)\n\nmessage \u003c- list(\n  hyperliquidChain = \"Testnet\",\n  destination = \"0x5e9ee1089755c3435139848e47e6635505d5a13a\",\n  amount = \"1\",\n  time = 1687816341423\n)\n\nsig \u003c- signer$sign_typed_data(domain, \"HyperliquidTransaction:UsdSend\", types, message)\nsig\n```\n\n### Two wire formats\n\nThe same signature serializes to either venue convention:\n\n```{r serialize}\n# {r, s, v} object form, e.g. Hyperliquid\nas_rsv(sig)\n\n# 65-byte concatenated hex r || s || v, e.g. Polymarket\nas_hex(sig)\n```\n\n### Verify with `ecrecover`\n\nRecompute the digest, recover the address, and confirm it is the signer's --\nthe inverse check that any venue (or you) can run on a signature:\n\n```{r recover}\ndigest \u003c- eip712_digest(domain, \"HyperliquidTransaction:UsdSend\", types, message)\nrsv \u003c- as_rsv(sig)\n\necrecover(digest, rsv$r, rsv$s, rsv$v) == signer$address\n```\n\n### Hashing and addresses\n\n```{r hashing}\n# keccak-256 of a string (the empty-string Ethereum vector) or raw bytes\nkeccak256(\"\")\nkeccak256(as.raw(c(0x12, 0x34)))\n\n# derive an address from a key without constructing a signer\neth_address(\"0x0123456789012345678901234567890123456789012345678901234567890123\")\n```\n\n### Sign a login message (SIWE)\n\n`$sign_message()` applies the EIP-191 `personal_sign` prefix -- the digest used\nby Sign-In with Ethereum and most \"sign this message to log in\" flows:\n\n```{r login}\nlogin \u003c- \"example.com wants you to sign in with your Ethereum account\"\nmsig \u003c- signer$sign_message(login)\nas_hex(msig)\n```\n\n## Use cases\n\nThe same `sign_typed_data` / `sign_message` / `sign_digest` primitives cover the\nEIP-712 and EIP-191 signing required by, among others:\n\n- **Hyperliquid** user actions (`usdSend`, `withdraw`, approve-agent, and other\n  user-signed actions) -- verified against the official SDK vectors.\n- **Polymarket** order signing (CLOB orders, the 65-byte hex form via\n  `as_hex()`).\n- **0x**, **CoW Protocol**, **1inch**, and **Seaport** (OpenSea) order/intent\n  signing.\n- **ERC-2612** and **Permit2** token permits.\n- **Gnosis Safe** transaction hashes.\n- **Sign-In with Ethereum** (SIWE) and generic `personal_sign` login messages.\n- **Raw EVM transaction** signing (sign the transaction's keccak-256 digest with\n  `$sign_digest()`; RLP encoding is supplied by your tooling).\n\n### Out of scope\n\n- **Hyperliquid order placement** (the `l1` actions) is msgpack-wrapped and\n  needs an external msgpack encoder before hashing; the signing step itself is\n  in scope, the encoding is not.\n- **StarkEx / zk / Cosmos venues** -- dYdX, Paradex, ApeX, Lighter -- use\n  different cryptography (Stark-friendly curves, Cosmos ADR-036) and are not\n  EVM secp256k1 signing.\n\n## License\n\nMIT © Dereck Mezquita. Provided \"as is\", without warranty of any kind; see\n`LICENSE`. You are responsible for how you use this software and for the safe\ncustody of your private keys.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdereckscompany%2Fethsign","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdereckscompany%2Fethsign","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdereckscompany%2Fethsign/lists"}