Private Key Tools

Compressed public key → point, hash160, addresses

Decompress a 33-byte public key back into a full curve point: recover Y from X, verify it really lies on secp256k1, then hash and encode it into P2PKH, P2SH-P2WPKH, P2WPKH and P2TR addresses. The uncompressed form of the same point is shown alongside, because it produces a different address — and no private key is used anywhere.

66 hex characters: 02 (even Y) or 03 (odd Y) followed by the 32-byte X coordinate. An optional 0x prefix and spaces are accepted. About half of all such strings are not valid curve points and are rejected after the on-curve check.
No input yet

Enter a value above and press Convert. Not sure what to type? Press “Use example” to load the sample from the placeholder.

How it works

What this page computes

You give it a compressed public key — 66 hex characters, starting with 02 or 03 — and it does two things a wallet does every time it loads an address: it decompresses the key back into a full curve point, verifies that the point really lies on secp256k1, and then hashes and encodes it into every address type it can produce. No private key is involved anywhere in this page, and none is needed.

given X and a parity bit:  Y = (X³ + 7)(p+1)/4 mod p  then flip to the required parity
02/03 ‖ X→ solve Y² = X³+7→ point (X, Y)→ on-curve check→ hash160→ Base58Check / Bech32 / Bech32m

It also shows the uncompressed serialization of the very same point and the different address that comes out of it, because the compressed/uncompressed distinction is the most common source of "my wallet shows the wrong balance" confusion in Bitcoin.

1. The 02/03 prefix is a parity bit

A public key is a point (X, Y) on the curve y² = x³ + 7 over the prime field p. Storing it naively costs 64 bytes. In 2012 the ecosystem switched to storing only X plus one bit, since Y can be recomputed exactly. That bit rides in the first byte:

Prefix byteTotal lengthMeaning
0x0233 bytes (66 hex)compressed encoding; the true Y is even
0x0333 bytes (66 hex)compressed encoding; the true Y is odd
0x0465 bytes (130 hex)uncompressed: 04 ‖ X ‖ Y, both coordinates stored explicitly
0x06/0x0765 byteshybrid, legacy: X ‖ Y plus a redundant parity bit that must agree with Y

The bit is not a checksum and not a version number. It is the answer to exactly one question: "which of the two possible points with this X do I mean?"

2. How decompression actually works

For a given X, the curve equation becomes an equation in one unknown:

Y² = X³ + 7  (mod p)   →   two roots: Y and p − Y

A quadratic over a field has at most two solutions, and if one is Y the other is always p − Y, since (p − Y)² = Y² mod p. The two roots always have opposite parity: p is odd, so p − Y ≡ −Y (mod 2) flips the lowest bit. One even root, one odd root — precisely why a single bit suffices.

Note that a random X has no square root about half the time: only about half of all field elements are quadratic residues, so roughly half of all 33-byte strings starting with 02 or 03 are not valid public keys at all.

Finding the root is usually done by trial (Tonelli–Shanks), but secp256k1's prime has a special shape that gives a closed form. Because

p ≡ 3 (mod 4)   ⇒   √a = a(p+1)/4 mod p

for any quadratic residue a. The reason is short: if y = a(p+1)/4 then y² = a(p+1)/2 = a · a(p−1)/2, and Euler's criterion says a(p−1)/2 ≡ 1 whenever a is a residue. So we can go straight to a modular exponentiation with the fixed exponent

(p + 1) / 4 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFF0C

and then replace it with p − Y if the parity is wrong. On secp256k1 p mod 4 = 3 exactly, so the shortcut is always available; curves with p ≡ 1 (mod 4) need the slower general algorithm.

Decompression produces no new information

It is tempting to think the 33-byte form "loses" something. It does not: the encoding maps bijectively onto the valid keys with that X. Nothing is recovered from the private key — the information was never removed, only recomputed from the curve equation. Both 02 ‖ X and 04 ‖ X ‖ Y describe the same point.

3. Why an off-curve point must be rejected

A curve equation is a test, not a hint: a pair (X, Y) either satisfies Y² = X³ + 7 (mod p) or it does not, and nothing is "almost" on the curve. If the check fails, the number you hold is not a public key — it is not an element of the group, so scalar multiplication with it is undefined and every protocol above it is fed garbage.

That matters because of a family of attacks known collectively as invalid curve attacks. Suppose a protocol takes a point supplied by the other party and multiplies it by a secret scalar (this is what ECDH does). If the point is not validated, an attacker can send points that lie on a different curve, or in a subgroup of small order. The result of the multiplication then depends on only a few bits of the secret. By trying many such points and combining the partial answers with the Chinese Remainder Theorem, the attacker reconstructs the whole private key. Several TLS and smart-card implementations have been broken this way; the defence is one line of code — validate every externally supplied point before use.

The honest caveat: secp256k1 has cofactor 1 and prime order n. There are no small subgroups, and no weak twist of smooth order, so the textbook small-subgroup version of the attack has nothing to grab hold of on this curve. Bitcoins are not lost simply because someone once parsed a bad point. But the discipline is not optional, for three practical reasons:

This page parses the point, checks the equation, and refuses to continue if it fails. An input of 02 followed by 64 zeroes is a good test: it is rejected with a readable message rather than silently deriving addresses from a meaningless number.

One accepted subtlety: X is reduced modulo p

The canonical SEC1 encoding requires 0 < X < p. Strict decoders — including libsecp256k1, which Bitcoin consensus relies on — reject an X that is greater than or equal to p as non-canonical. This teaching implementation instead reduces X modulo p and continues, so a handful of numerically odd inputs are accepted here that a consensus parser would reject. That is a deliberate simplification, and it is the kind of difference that matters when you compare two implementations byte for byte.

4. Addresses need no private key — and that has consequences

Everything below this point is public arithmetic: hash the serialized public key, encode the hash. Nothing in that pipeline needs the scalar k, and nothing in it can be inverted to find k.

5. Compressed versus uncompressed

Both forms are valid encodings of the same point and both are accepted by consensus, yet they produce different addresses — the address is a hash of the serialized bytes, and those differ.

CompressedUncompressed
Serialization02/03 ‖ X04 ‖ X ‖ Y
Length33 bytes65 bytes
hash160 of the demo key21f57b6debcfc5b67182dfb4af1641f0a81890123f0e966dc089c611a9c1d03bd4f69ea53b0223f9
P2PKH address of the demo key146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G
scriptSig when spending≈107 bytes (push + ~72-byte signature + 33-byte key)≈139 bytes (same, with a 65-byte key)
Usable in P2WPKH / P2SH-P2WPKH / P2TRYes — the only form allowedNo; witness programs are defined over compressed keys
Status todayThe default everywhere (since 2012)Legacy, but still valid and spendable

Because the uncompressed key is 32 bytes longer and embeds directly in the input script, spending from such an address costs more in fees — the whole reason the compressed form won.

6. Worked example — the real demo key

Every value below is what this page computes for the sample in the input box (02ff812e…67ee80):

StepValue
Input, 66 hex characters02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80
Prefix byte02 → Y is even
X (the 64 characters after the prefix)ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80
X³ + 7 mod p (the value to take a square root of)174ca53008928cd3c9c380e12c4b1dee0c5a0b6d851b1c472a58d744ca28c6dc
Recovered Y — the even root8f49cde13c7ffd64f1d730bf87a743a578eda4971ddac4a08118160732b424ae
Last hex digit of Ye → even, which matches the 02 prefix
The other root, p − Y70b6321ec380029b0e28cf407858bc5a87125b68e2253b5f7ee7e9f7cd4bd781
Last hex digit of p − Y1 → odd, as expected for the twin root
On-curve checkPASS — Y² equals X³ + 7 mod p
hash160 (compressed)21f57b6debcfc5b67182dfb4af1641f0a8189012
P2PKH (compressed)146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT
P2SH-P2WPKH3DZT76KyKyc5zkzvLugP8umgt4RPY4XPQw
P2WPKHbc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6
P2TRbc1pmsrhxnvmj8tjxxu9wj69ntvwvhvr28qufyc26tshz3rjj777tx3sh54u63

The uncompressed counterpart of the same point is the 130-character string 04ff812e…b424ae, which produces a completely different address: 16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G.

Finally, flip the prefix bit: same X, declared 03. The page recovers the odd root 70b6321e…cd4bd781, the negation of the original point. Its hash160 is bf2aa927b06822b645d48e54ac82676c2e586675 and its P2PKH address is 1JRoAmA3S9nPbucndLyARsmY2Awuzgdazb. If P = k·G, this twin is (n − k)·G — one bit in the encoding, a different key entirely.

7. What happens next in the chain

compressed public key→ SHA-256→ RIPEMD-160→ hash160 (20 B)→ Base58Check / Bech32 / Bech32m→ address

8. Security notes

9. Common mistakes

10. Quick reference

ItemValue
Input66 hex characters: 02 or 03 followed by a 32-byte X
Prefix meaning02 = even Y, 03 = odd Y
Field prime p0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
p mod 43 — so the closed-form square root applies
Root exponent (p+1)/40x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFF0C
Two rootsY and p − Y, always of opposite parity
On-curve testY² ≡ X³ + 7 (mod p)
OutputsX, Y, parity, hash160, P2PKH (compressed and uncompressed), P2SH-P2WPKH, P2WPKH, P2TR
Private key needed?No — none of this is reversible to k