ID@agntn/curvesv0.0.0

Find k. Don't guess it.

A CTF hands you a curve, a point and another point. What's k? A model will do the modular inverse in its head and get it wrong by step three. This does the arithmetic. Points, orders, counts and discrete logs on a curve you define, plus secp256k1 with SEC1 points. Written from the specs, no noble underneath. Same call in TypeScript, the terminal and your agent.

Operations
15
in 2 agent tools
Orders up to
2^48
logs for a base up to 2^36
Network calls
0
every point computed in place
Install$ pnpm add @agntn/curves
CallmultiplyPoint(curve, G, 13n)F17 · 01 / 5
Curve / F17

y² = x³ + 2x + 2

The textbook curve from Paar and Pelzl. Nineteen points, and every one but infinity generates the rest.

Field

  1. 1G(5, 1)
  2. 2G(6, 3)
  3. 3G(10, 6)
  4. 4G(3, 1)
  5. 5G(9, 16)
  6. …6 more
  7. 12G(0, 11)
  8. 13G(16, 4)

pointG (5, 1)13G (16, 4)

Points
19 with infinity
G
(5, 1)
Order of G
19
13G
(16, 4)
Log back
k = 13
walked 13 / 19

Ask for k, get k

CTFs love a toy curve. Small prime, a base point, a target, find k. A model will try it in its head and drift by step three. curves_compute does the walk in code and hands back the order it searched in, so you know the answer is the smallest k. Every sample above goes through it right in your tab.

  • Counting and listing points for p up to 2^20, one x at a time
  • Orders by baby step giant step over the Hasse interval
  • Logs for a base of order up to 2^36. No k? You get null, not a guess
Read Orders and discrete logs
Callcurves_compute("log", p 17)
Tool / log

Which k gives (16, 4)?

Baby step giant step, in the executor. The model asks, the library answers, nobody does long division in a chat window.

base
(5, 1)
target
(16, 4)
order
19
scalar
13
MCP · Pi · OMPcurves mcp · stdio

secp256k1, no noble

Two public keys and you need their sum? Or the x-only key of a Taproot output as a full point? @agntn/curves/secp256k1 takes SEC1 hex and gives SEC1 hex back. It's written here from the SEC specs, not wrapped around another library. And it agrees with @noble/curves on every vector we threw at it.

  • Add, subtract, negate and multiply points, lift an x, check a point
  • Scalars mod n: add, subtract, multiply, invert
  • Domain parameters from SEC 2, encodings from SEC 1, Jacobian coordinates inside
Read secp256k1 with SEC1 points
Callcurves_secp256k1_compute("multiply")
secp256k1 / multiply

Three times G

The usual first check. 02f930… if your arithmetic is right.

point
0279be667e…f81798
scalar
3
point
02f9308a01…e036f9
SEC1 hex in, SEC1 hex out@agntn/curves/secp256k1

Two tools, one executor

curves mcp, the Pi and OMP extensions and @agntn/curves/ai all call the same executors. This page runs them too. Open a full response on any instrument above and you're reading exactly what a model reads. Integers travel as decimal strings, since JSON has never heard of a bigint.

  • curves_compute: add, double, negate, multiply, check, order, count, points, log
  • curves_secp256k1_compute: add, subtract, negate, multiply, lift, check
  • An argument the operation does not take is an error, never silently dropped
Read MCP, Pi, OMP and AI SDK
Filemcp.jsonstdio

Hosts

$ pi install npm:@agntn/curves$ omp install @agntn/curves{  "mcpServers": {    "curves": { "command": "npx", "args": ["-y", "@agntn/curves", "mcp"] }  }}
curves_compute · curves_secp256k1_compute
Startpnpm add @agntn/curvesNode.js 26 or newer

Start with one command

One install gets you the library, the curves CLI and the MCP server. Give it a, b and p, and it does the rest. Need secp256k1 instead? That's one import away, in @agntn/curves/secp256k1.

  • PinPre-1.0, so pin exact versions.
  • Not auditedPuzzles, CTFs and agents. Never real keys or real funds.
  • OfflineNothing to fetch, pure TypeScript, runs in the browser too.

First call

$ pnpm add @agntn/curvesimport { countPoints, defineCurve, discreteLog } from "@agntn/curves";import { liftX } from "@agntn/curves/secp256k1";const curve = defineCurve({ a: 2n, b: 2n, p: 17n });countPoints(curve);  // 19ndiscreteLog(curve, { x: 5n, y: 1n }, { x: 16n, y: 4n });  // 13nliftX("79be667e…1798").odd;  // "0379be667e…"