<p>Yes, you can convert a 33-byte compressed public key into a 65-byte uncompressed public key in Java.</p>

<p>Here is the code to perform the operation. It is correct, robust, and only requires Java SE classes (no other libraries) - but I apologize for the implementation length.</p>



<pre><code>import java.math.BigInteger;
import java.util.Arrays;

static final BigInteger MODULUS =
    new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
static final BigInteger CURVE_A = new BigInteger("0");
static final BigInteger CURVE_B = new BigInteger("7");


// Given a 33-byte compressed public key, this returns a 65-byte uncompressed key.
byte[] decompressPubkey(byte[] compKey) {
    // Check array length and type indicator byte
    if (compKey.length != 33 || compKey[0] != 2 &amp;&amp; compKey[0] != 3)
        throw new IllegalArgumentException();

    final byte[] xCoordBytes = Arrays.copyOfRange(compKey, 1, compKey.length);
    final BigInteger xCoord = new BigInteger(1, xCoordBytes);  // Range [0, 2^256)

    BigInteger temp = xCoord.pow(2).add(CURVE_A);
    temp = sqrtMod(temp.add(CURVE_B));
    boolean tempIsOdd = temp.testBit(0);
    boolean yShouldBeOdd = compKey[0] == 3;
    if (tempIsOdd != yShouldBeOdd)
        temp = temp.negate().mod(MODULUS);
    final BigInteger yCoord = temp;

    // Copy the x coordinate into the new
    // uncompressed key, and change the type byte
    byte[] result = Arrays.copyOf(compKey, 65);
    result[0] = 4;

    // Carefully copy the y coordinate into uncompressed key
    final byte[] yCoordBytes = yCoord.toByteArray();
    for (int i = 0; i &lt; 32 &amp;&amp; i &lt; yCoordBytes.length; i++)
        result[result.length - 1 - i] = yCoordBytes[yCoordBytes.length - 1 - i];

    return result;
}


// Given x, this returns a value y such that y^2 % MODULUS == x.
BigInteger sqrtMod(BigInteger value) {
    assert (MODULUS.intValue() &amp; 3) == 3;
    BigInteger pow = MODULUS.add(BigInteger.ONE).shiftRight(2);
    BigInteger result = value.modPow(pow, MODULUS);
    assert result.pow(2).mod(MODULUS).equals(value);
    return result;
}
</code></pre>

<p>My <a href="https://www.nayuki.io/page/bitcoin-cryptography-library" rel="nofollow">Bitcoin cryptography library</a> does implement the modulo-prime field arithmetic, but it should add the functionality to decompress public keys as well...</p>

CC BY-SA 3.0
2016-05-10T06:31:27.573Z
Thanks! Program looks clean. I'll check and let you know.
prof.Zoom
CC BY-SA 3.0
2016-05-10T07:18:07.223Z
I'm unable to upvote this answer due to low reputation.
prof.Zoom
CC BY-SA 3.0
2017-12-10T21:07:34.163Z
It fails for this compressed key. `022A779D25B43F04C3DD8A27B079FF4C6BECFBDE1419F1CF0B5CDA2AB001517884` could you please check? fails at `assert result.pow(2).mod(MODULUS).equals(value);`
light_keeper
CC BY-SA 3.0
2017-12-10T23:54:43.940Z
@light_keeper Are you sure that your x coordinate of 2A77...7884 actually has a point on the elliptic curve?
Nayuki
CC BY-SA 4.0
2019-04-24T22:44:30.027Z
You need to multiply your first `temp` (x^2+a) by x before adding b and calling `sqrtMod`. Also for the second assertion to work correctly you must either reduce the argument to `sqrtMod` modulo p, or have the assertion check congruence rather than equality.
dave_thompson_085
CC BY-SA 3.0
2016-05-10T05:41:53.173Z
2016-05-10T05:41:53.173Z
Nayuki
<p>You can use bouncycastle ECPoint to do this conversion:</p>

<pre><code>static ECParameterSpec SPEC = ECNamedCurveTable.getParameterSpec("secp256k1");

static byte[] compressedToUncompressed(byte[] compKey) {
    ECPoint point = SPEC.getCurve().decodePoint(compKey);
    byte[] x = point.getXCoord().getEncoded();
    byte[] y = point.getYCoord().getEncoded();
    // concat 0x04, x, and y, make sure x and y has 32-bytes:
    return concat(new byte[] {0x04}, x, y);
}
</code></pre>

CC BY-SA 3.0
2018-03-16T00:41:48.750Z
2018-03-16T00:41:48.750Z
michaelliao
<p>In openssl, you can use the EC_POINT_point2oct and EC_POINT_oct2point functions to convert between compressed and uncompressed.   </p>

<p>Check if the first octet contains POINT_CONVERSION_UNCOMPRESSED, if you want to know whether it's compressed.</p>

CC BY-SA 4.0
2018-08-13T13:54:11.497Z
2018-08-13T13:54:11.497Z
Erik Aronesty
<p>A similar question has an answer in Python which links to the bitcointalk forum:</p>

<ul>
<li><a href="https://bitcoin.stackexchange.com/questions/28398/how-can-i-get-the-uncompressed-public-key-from-the-compressed-public-key-in-open">How can I get the uncompressed public key from the compressed public key in openssl?</a></li>
<li><a href="https://bitcointalk.org/index.php?topic=644919.msg7205689#msg7205689" rel="nofollow noreferrer">https://bitcointalk.org/index.php?topic=644919.msg7205689#msg7205689</a></li>
</ul>

<p>But I'd like to know how a Java program can be written for the same conversion? I noticed that Java uses the byte data type and I'm unable to understand how to operate on values.</p>

CC BY-SA 3.0
2016-05-09T16:49:21.560Z
It looks like the algorithm you need is published on bitcointalk.  Are you asking whether Java has the same capabilities to convert public keys as Python?
Jestin
CC BY-SA 3.0
2016-05-09T17:17:24.807Z
Right! Actually I started doing the code I don't understand how to do the p//4 (floor division) part though since I'm working with biginteger. I also tried doing y=((x^3+7)^1/2)mod p where p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F but it didn't work either.
prof.Zoom
CC BY-SA 3.0
2016-05-09T18:08:30.327Z
If your question is about how to do a specific thing in Java, it might be worthwhile to post the question to StackOverflow.  I'm sure there's a few people here who have worked with BigIntegers in Java, but there's certainly more on SO.
Jestin
<public-key><cryptography><algorithms><java><math>
Get uncompressed public key from compressed form
prof.Zoom
# Get uncompressed public key from compressed form

(Asked by: username_0 on 2016-05-09)

A similar question has an answer in Python which links to the bitcointalk forum:

* [How can I get the uncompressed public key from the compressed public key in openssl?](https://bitcoin.stackexchange.com/questions/28398/how-can-i-get-the-uncompressed-public-key-from-the-compressed-public-key-in-open)
* <https://bitcointalk.org/index.php?topic=644919.msg7205689#msg7205689>

But I'd like to know how a Java program can be written for the same conversion? I noticed that Java uses the byte data type and I'm unable to understand how to operate on values.

**Tags:** public-key, cryptography, algorithms, java, math

> **Comments:**
> **username_1**: It looks like the algorithm you need is published on bitcointalk.  Are you asking whether Java has the same capabilities to convert public keys as Python?  
> **username_0**: Right! Actually I started doing the code I don't understand how to do the p//4 (floor division) part though since I'm working with biginteger. I also tried doing y=((x^3+7)^1/2)mod p where p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F but it didn't work either.  
> **username_1**: If your question is about how to do a specific thing in Java, it might be worthwhile to post the question to StackOverflow.  I'm sure there's a few people here who have worked with BigIntegers in Java, but there's certainly more on SO.  

---

## 3 answers

### Answer by username_2 on 2016-05-10. Score: 2 | Accepted answer

Yes, you can convert a 33-byte compressed public key into a 65-byte uncompressed public key in Java.
Here is the code to perform the operation. It is correct, robust, and only requires Java SE classes (no other libraries) - but I apologize for the implementation length.
import java.math.BigInteger;
import java.util.Arrays;

static final BigInteger MODULUS =
    new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
static final BigInteger CURVE_A = new BigInteger("0");
static final BigInteger CURVE_B = new BigInteger("7");


// Given a 33-byte compressed public key, this returns a 65-byte uncompressed key.
byte[] decompressPubkey(byte[] compKey) {
    // Check array length and type indicator byte
    if (compKey.length != 33 || compKey[0] != 2 && compKey[0] != 3)
        throw new IllegalArgumentException();

    final byte[] xCoordBytes = Arrays.copyOfRange(compKey, 1, compKey.length);
    final BigInteger xCoord = new BigInteger(1, xCoordBytes);  // Range [0, 2^256)

    BigInteger temp = xCoord.pow(2).add(CURVE_A);
    temp = sqrtMod(temp.add(CURVE_B));
    boolean tempIsOdd = temp.testBit(0);
    boolean yShouldBeOdd = compKey[0] == 3;
    if (tempIsOdd != yShouldBeOdd)
        temp = temp.negate().mod(MODULUS);
    final BigInteger yCoord = temp;

    // Copy the x coordinate into the new
    // uncompressed key, and change the type byte
    byte[] result = Arrays.copyOf(compKey, 65);
    result[0] = 4;

    // Carefully copy the y coordinate into uncompressed key
    final byte[] yCoordBytes = yCoord.toByteArray();
    for (int i = 0; i < 32 && i < yCoordBytes.length; i++)
        result[result.length - 1 - i] = yCoordBytes[yCoordBytes.length - 1 - i];

    return result;
}


// Given x, this returns a value y such that y^2 % MODULUS == x.
BigInteger sqrtMod(BigInteger value) {
    assert (MODULUS.intValue() & 3) == 3;
    BigInteger pow = MODULUS.add(BigInteger.ONE).shiftRight(2);
    BigInteger result = value.modPow(pow, MODULUS);
    assert result.pow(2).mod(MODULUS).equals(value);
    return result;
}

My Bitcoin cryptography library does implement the modulo-prime field arithmetic, but it should add the functionality to decompress public keys as well...

> **Comments:**
> **username_0**: Thanks! Program looks clean. I'll check and let you know.  
> **username_0**: I'm unable to upvote this answer due to low reputation.  
> **username_3**: It fails for this compressed key. `022A779D25B43F04C3DD8A27B079FF4C6BECFBDE1419F1CF0B5CDA2AB001517884` could you please check? fails at `assert result.pow(2).mod(MODULUS).equals(value);`  
> **username_2**: @username_3 Are you sure that your x coordinate of 2A77...7884 actually has a point on the elliptic curve?  
> **username_4**: You need to multiply your first `temp` (x^2+a) by x before adding b and calling `sqrtMod`. Also for the second assertion to work correctly you must either reduce the argument to `sqrtMod` modulo p, or have the assertion check congruence rather than equality.  

---

### Answer by username_5 on 2018-03-16. Score: 2

You can use bouncycastle ECPoint to do this conversion:
static ECParameterSpec SPEC = ECNamedCurveTable.getParameterSpec("secp256k1");

static byte[] compressedToUncompressed(byte[] compKey) {
    ECPoint point = SPEC.getCurve().decodePoint(compKey);
    byte[] x = point.getXCoord().getEncoded();
    byte[] y = point.getYCoord().getEncoded();
    // concat 0x04, x, and y, make sure x and y has 32-bytes:
    return concat(new byte[] {0x04}, x, y);
}


---

### Answer by username_6 on 2018-08-13. Score: 0

In openssl, you can use the EC\_POINT\_point2oct and EC\_POINT\_oct2point functions to convert between compressed and uncompressed.

Check if the first octet contains POINT\_CONVERSION\_UNCOMPRESSED, if you want to know whether it's compressed.


---

