secp256k1 point arithmetic
Add two curve points, double a point, or multiply the generator by a scalar — the raw group law that every Bitcoin public key is built from. Feed it k·G and watch the private key become a point; add a point to its own negation and watch it collapse into the point at infinity.
Enter a value above and press Convert. Not sure what to type? Press “Use example” to load the sample from the placeholder.
What this page computes
This is a bare-metal playground for the group law of secp256k1, the elliptic curve Bitcoin uses. It offers three operations and nothing else:
- mul — scalar × generator:
k · G, the operation that turns a private key into a public key. - add — point + point:
P + Q, the chord step of the group law. - double — point doubled:
2 · P, the tangent step.
Everything is computed live on this server in pure PHP with GMP-backed big integers. The output shows the operands as they were parsed, the curve constants actually used, the resulting point, its parity, both standard serializations, whether the result is the point at infinity, and an independent on-curve check of the answer.
1. The curve and why its points form a group
secp256k1 is the set of pairs (x, y) with coordinates taken modulo the prime p
that satisfy
plus one extra element, the point at infinity ∞. Because the equation is
modular, this is not a smooth arch drawn on paper but a scattered set of roughly n points in a
256-bit-wide finite grid. The useful miracle is that you can define an addition on those points which is
associative, commutative, has an identity (∞) and gives every point an inverse
(−P). Any set with those four properties is an abelian group, and a group is exactly
the structure you need in order to iterate an operation — which is what "multiply by an integer" means.
The inverse of a point is free: if (x, y) is on the curve then so is (x, −y),
because the curve equation only contains y². So −P = (x, p − y). Note that
p − y has the opposite parity from y, a fact the compressed encoding uses.
| Constant | Value | Meaning |
|---|---|---|
Field prime p | 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F | Coordinates live in [0, p−1]. Equal to 2²⁵⁶ − 2³² − 977, decimal 115792089237316195423570985008687907853269984665640564039457584007908834671663. |
Group order n | 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 | The number of points (including ∞). Private keys live in [1, n−1]. Decimal 115792089237316195423570985008687907852837564279074904382605163141518161494337. |
Generator Gx | 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 | The conventional base point. Every Bitcoin public key is a multiple of it. |
Generator Gy | 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 | Even, which is why the compressed form of G starts with 02. |
Cofactor h | 1 | The curve group has exactly n points, and n is prime. See §4. |
p mod 4 | 3 | This is what makes modular square roots cheap: √a = a^((p+1)/4). |
p and n are different numbers
Nearly every beginner bug on this curve comes from mixing them up. p bounds the
coordinates and all field arithmetic is done mod p. n bounds the
scalars and all scalar arithmetic is done mod n. They are numerically close to
2²⁵⁶ and therefore easy to confuse, but using the wrong one produces garbage that still looks
like a valid 32-byte number.
2. The group law, geometrically: chords and tangents
The classical construction works over the real numbers, where you can draw it. Take two points
P and Q on the curve and draw the straight line through them. A cubic curve meets a
line in exactly three points (counted with multiplicity), so there is a third intersection point
R. Define the sum as R reflected across the x-axis:
Why the reflection? Because the reflection of a curve point is still on the curve, and without it the
construction fails to be associative — the reflected version is the one that makes (P+Q)+R = P+(Q+R)
hold. Three special cases are worth naming, because they are exactly where the implementation has to branch:
- P = Q. There is no unique line through one point; the limiting case is the
tangent line at
P. That is the "tangent" in "chord and tangent" and it is what doubling computes. - Q = −P (same
x, oppositey). The line through them is vertical, it meets the curve only at those two points, and the third intersection is the point at infinity. SoP + (−P) = ∞, exactly as an additive inverse should. - P = ∞ or Q = ∞. Since
∞is the identity, the sum is simply the other operand.
Over a finite field "the line through P and Q" is still meaningful — it is the set of points satisfying a
linear equation mod p — and the same three-intersections argument holds. The drawing stops being
useful, but the algebra does not.
3. The group law, algebraically
Division by a non-zero element mod p is multiplication by its modular inverse, so every
"slope" below is a real, computable field element. With λ the slope of the chord (or tangent)
through the points being added, and (x₃, y₃) the result:
x₃ = λ² − x₁ − x₂ y₃ = λ(x₁ − x₃) − y₁ (all mod p)
That is the entire group law. Notice that x₃ depends only on λ and the two x
coordinates, and that y₃ is then fixed by reflecting through the line. Notice also that the
formula is symmetric in x₁ ↔ x₂ but the y terms are not, which is why
P + Q = Q + P holds while P + (−P) needs its own case.
A single addition costs one modular inversion (the expensive part: here it is done by Fermat
exponentiation, a^(p−2)) plus two or three modular multiplications/squarings. Real libraries use
projective or Jacobian coordinates to defer the inversion, trading it for extra multiplications, because
inversions are roughly a hundred times more expensive than multiplications.
| Case | Condition | Formula used | Result |
|---|---|---|---|
| Generic addition | x₁ ≠ x₂ | chord slope (y₂−y₁)/(x₂−x₁) | a normal curve point |
| Doubling | P = Q (so x₁ = x₂, y₁ = y₂) | tangent slope 3x₁²/(2y₁) | a normal curve point |
| Inverse pair | x₁ = x₂ and y₁ + y₂ ≡ 0 | division by zero is avoided | ∞, the identity |
| Identity | P = ∞ or Q = ∞ | short-circuit | the other operand |
Zero y | y₁ = 0 (doubling) | 2y₁ ≡ 0 | ∞; no such point exists on secp256k1 |
4. Why ∞ is the identity, and when it appears
The point at infinity is not a coordinate pair and cannot be serialized as a public key — the standard encodings simply have no room for it. It exists as the answer to "what is the third intersection when the line is vertical", and it behaves exactly like zero in ordinary arithmetic:
Three situations produce it, and this page shows whether the result is ∞ explicitly:
- Adding a point to its own negation.
P + (−P) = ∞. You can see this yourself: add the demo public key to its negation — the two inputs share an x coordinate and differ only in the02/03prefix. - Doubling a point with
y = 0. The tangent is vertical, so the result is∞. On secp256k1 no such point exists: a point withy = 0would satisfy2P = ∞, i.e. it would be an element of order 2, and a group of prime ordern(an odd prime) has no elements of order 2. The branch is in the code for safety, not because you can reach it here. - Multiplying the generator by a multiple of
n.n · G = ∞by definition of the order, and therefore(n+1) · G = G. This is exactly why private keys are restricted to[1, n−1]: a "private key" ofn+1would be a legal-looking 32-byte number that silently behaves like1.
5. Cofactor 1, cyclicity, and why every public key is a multiple of G
The number of points on the curve is h · n with h the cofactor. For secp256k1,
h = 1, so the group order is n, and n is prime. This has several
very convenient consequences:
- No small subgroups. A group of prime order has exactly two subgroups:
{∞}and the whole group. Curves with a cofactor above 1 (Curve25519, for instance, hash = 8) contain small-order points, and an attacker who can force a victim to operate on one of them can learn bits of a secret through invalid-curve attacks. Implementations must then multiply by the cofactor or blacklist those points. Here there is nothing to clear. - The group is cyclic of order
n. Every non-identity point has order exactlyn(its order dividesnand is not 1). So any point other than∞generates the entire group —Gis not special mathematically, it is merely the publicly agreed starting point. - Every public key is some
k · G, withk ∈ [1, n−1], and thatkis unique. Existence follows from cyclicity; uniqueness from the fact thatk₁·G = k₂·Gimplies(k₁−k₂)·G = ∞, which can only happen whenk₁ ≡ k₂ (mod n). - Scalars distribute.
(a + b)·G = a·G + b·Gand(a·b)·G = a·(b·G). This is why a BIP32 child key can be computed as a scalar sum, and why "double the point" equals "use twice the scalar" — both are shown in the worked example below.
6. Double-and-add: how k · G is actually computed
There is no closed-form shortcut for scalar multiplication, so implementations iterate the bits of the scalar. The version in this codebase walks the 256 bits from most significant to least:
R = ∞ # the identity
for bit in bits_of(k): # 256 iterations for a 256-bit scalar
R = double(R) # R = R + R
if bit == 1:
R = add(R, G) # R = R + G
return R # R = k · G
The cost is one doubling per bit plus one addition per set bit. For the demo private key
0824c314…171ca the bit census is 256 bits with 116 of them set, so the loop performs
256 doublings and 116 additions — 372 point operations, each of which internally is one
inversion plus a few multiplications. Production code uses windowed or fixed-window methods (precomputing
G, 2G, 3G, …, 15G and processing four bits at a time) to cut that count by roughly a third, and a
Montgomery ladder when the scalar must stay secret.
| Operation | Point ops (256-bit scalar / one call) | Dominant cost |
|---|---|---|
double — 2 · P | 1 doubling | 1 inversion + ~2 squarings + ~2 multiplications |
add — P + Q (P ≠ ±Q) | 1 addition | 1 inversion + ~3 multiplications/squarings |
add — P + (−P) | 0 (case detected) | one comparison of coordinates; returns ∞ |
mul — k · G | 256 doublings + (popcount of k) additions | the inversion in each step, so ~hundreds of inversions |
mul — k · G, windowed (real libraries) | ~64 doublings + ~64 additions + precomputation | same, but 2–3× fewer of them |
Going from k to k·G takes 256 iterations. Going from the point back to the
scalar is the elliptic curve discrete logarithm problem; the best known general algorithm
(Pollard's rho) needs on the order of √n ≈ 2¹²⁸ steps. That asymmetry — cheap forwards,
astronomically expensive backwards — is the entire reason public keys can be published.
7. Timing, side channels and what "constant time" means here
The pseudocode above is a security hazard if the scalar is a real private key, because its control flow depends on the secret: a scalar bit of 0 skips the addition, a bit of 1 performs it. Any observer who can measure how long a signature or a derivation takes, or watch the power drawn by the chip, can recover the scalar bit by bit. This is not theoretical: timing attacks on naive ECDSA implementations have recovered keys across a network.
Constant time means the sequence of executed operations and memory accesses does not depend
on secret values — only the data does. Concretely, implementations achieve it by always doing both the
doubling and the addition and then selecting the right result arithmetically; by using unified addition
formulas with no special cases; by scalar blinding (computing (k + r·n)·G for a random
r, which gives the same point but a different bit pattern); and by point blinding. libsecp256k1
combines several of these and is written specifically to avoid secret-dependent branches.
The PHP + GMP implementation behind this page is not constant time: GMP bignums have data-dependent timings, the double-and-add loop branches on scalar bits, and there is no blinding. It is perfectly safe for experimenting with public inputs like the ones on this page, and it must never be used to process a private key that protects money. Use a hardware wallet or a well-tested constant-time library for that.
8. Worked example: doubling G
The most-cited sanity check on any secp256k1 implementation is 2G. Using the tangent formula
with the real constants above, this page computes:
| Step | Value |
|---|---|
| Start | G = (79be667e…f81798, 483ada77…10d4b8) |
Slope λ = 3Gx² / (2Gy) mod p | reduced to a 256-bit field element |
x₃ = λ² − 2Gx | c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5 |
y₃ = λ(Gx − x₃) − Gy | 1ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a |
Parity of y₃ | even → compressed prefix 02 |
2G compressed | 02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5 |
2G uncompressed | 04c6047f…b95c709ee51ae168…50cfe52a (65 bytes) |
| Independent check | Set the operation to double with A = G: the page doubles the generator and then computes pointMul(2, G) as a cross-check, reporting that the two match — they are the public key of private key 2 |
| hash160(2G) / P2PKH | 06afd46bcdfd22ef94ac122aa11f241244a37ecc → 1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP |
| WIF of private key 2 | KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU74NMTptX4 (compressed) |
Two more checks you can reproduce with the form above, both of which exercise the identities from §5:
- Scalar multiplication and doubling agree: in
mulmode with the demo private key you getk·G=02ff812e…8c67ee80, which is exactly the demo public key. Doubling that point indoublemode produces a compressed result that starts028c65af…, and the(2k mod n) · Gcross-check row in the results panel returns precisely the same value — the identity2·(k·G) = (2k)·Gmade visible. (The panel prints both values in full, so you can compare them digit by digit.) - Inverses cancel:
addmode with02ff812e…8c67ee80and03ff812e…8c67ee80returns the point at infinity and no serialization at all, because∞has no coordinates.
9. Common mistakes
- Feeding a scalar to a point parser. A 64-hex-digit string is a legal scalar and a legal x-only public key. This page decides which one you meant from the mode, and the hint under each field says so. Getting it wrong gives a valid-looking but unrelated result.
- Skipping the on-curve check. Accepting an arbitrary
(x, y)as a point is how invalid-curve attacks start. Every parse here verifiesy² ≡ x³ + 7 (mod p)and throws a readable error otherwise — try a deliberately off-curve uncompressed key and watch the red box. - Assuming small scalars are safe.
1·G = Gpublicly. Scalars like 1, 2, 3, 0x1234 are trivially searchable; that is why real key generation uses 256 bits of entropy, not "a number I like". - Expecting to serialize
∞. There is no prefix for it. Code that does not check for it will either crash or emit a bogus04key. - Confusing this with ECDSA. Signing needs nonces and modular arithmetic over
n; this page only covers the group law, which is the arithmetic layer underneath.
10. Quick reference
| Item | Value |
|---|---|
| Curve | y² = x³ + 7 over GF(p), p = 2²⁵⁶ − 2³² − 977 |
| Group order | n (prime, 256 bits), cofactor h = 1 |
| Identity | ∞ — no coordinates, cannot be serialized |
| Inverse | −P = (Px, p − Py); flips the 02/03 prefix |
| Add slope | λ = (y₂ − y₁)(x₂ − x₁)⁻¹ mod p |
| Double slope | λ = 3x₁²(2y₁)⁻¹ mod p |
| Result | x₃ = λ² − x₁ − x₂, y₃ = λ(x₁ − x₃) − y₁ (all mod p) |
| Scalar cost | 256 doublings + one addition per set bit of k |
| Public key | k · G, serialized as 02/03 ‖ x (33 B) or 04 ‖ x ‖ y (65 B) |
| Valid scalars | 1 ≤ k ≤ n−1; validated with Btc::normalizePrivateKey |