Client and backend. This class is shared: the same code is compiled into your app and into your server, so everything on this page works in both.

public final class Secp256k1

  1. Object
  2. Secp256k1

ECDSA over the secp256k1 curve, the signature scheme of Bitcoin and Ethereum, written in portable Java so a wallet can sign on the device and a server can verify or sign with the same class.

Keys are raw bytes: a private key is 32 big-endian bytes in [1, n-1], a public key is the SEC 1 encoding of the point, either compressed (33 bytes, 02/03 then x) or uncompressed (65 bytes, 04 then x then y). Every method accepts a public key in either form.

Signing an Ethereum transaction

byte[] priv = Hash.fromHex("4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318");

// the address is the last 20 bytes of keccak256(x || y)
byte[] pub = Secp256k1.publicKey(priv, false);          // 04 || x || y
byte[] xy = new byte[64];
System.arraycopy(pub, 1, xy, 0, 64);
byte[] digest = Hash.keccak256(xy);
byte[] address = new byte[20];
System.arraycopy(digest, 12, address, 0, 20);           // 2c7536e3605d9c16a7a3d7b1898e529396a65c23

// sign the keccak256 of the RLP-encoded transaction
byte[] rlp = Hash.fromHex("02c0");                       // your encoded transaction
Secp256k1.EcdsaSignature sig = Secp256k1.sign(Hash.keccak256(rlp), priv);
byte[] r = sig.r();
byte[] s = sig.s();
int v = 27 + sig.recoveryId();                           // or chainId * 2 + 35 + recoveryId

Signatures are deterministic (RFC 6979, HMAC-SHA256) and always low-S, as Bitcoin’s standardness rules and Ethereum’s EIP-2 require, and they carry the recovery id Ethereum derives the signer’s address from. verify rejects a high-S signature the way libsecp256k1 does; recoverPublicKey accepts either, the way the EVM’s ecrecover does. A signature from another library can be lowered with EcdsaSignature.normalize.

Constant time

Everything that touches a private key or a nonce – key derivation, signing, the tweak used by BIP32 derivation – runs in constant time: the field and scalar arithmetic uses fixed 16-bit limbs with no data-dependent branches, the curve arithmetic uses complete addition formulas that have no special case for doubling or the point at infinity, and the scalar multiplication is a fixed-window ladder whose table lookup reads every entry. Verification and recovery handle public data only and share the same code. The implementation is independent of libsecp256k1 and depends on nothing but this package and the core JDK subset, so it runs identically on every port and on the backend.

Nested types

class Secp256k1.EcdsaSignatureAn ECDSA signature: r and s as 32-byte big-endian integers, and the recovery id a signer knows and a verifier does not need.

Fields

public static final int PRIVATE_KEY_LENGTH = 32Length in bytes of a private key.
public static final int HASH_LENGTH = 32Length in bytes of the message hash a signature covers.
public static final int COMPRESSED_PUBLIC_KEY_LENGTH = 33Length in bytes of a compressed public key (02/03 then x).
public static final int UNCOMPRESSED_PUBLIC_KEY_LENGTH = 65Length in bytes of an uncompressed public key (04 then x then y).

Methods

public static boolean isValidPrivateKey(byte[] privateKey)Tells whether the bytes are a usable private key: exactly 32 bytes holding a big-endian integer in [1, n-1].
public static byte[] publicKey(byte[] privateKey, boolean compressed)Derives the public key of a private key.
public static boolean isValidPublicKey(byte[] publicKey)Tells whether the bytes encode a point on the curve, in either SEC 1 form.
public static byte[] convertPublicKey(byte[] publicKey, boolean compressed)Re-encodes a public key in the requested form.
public static byte[] privateKeyTweakAdd(byte[] privateKey, byte[] tweak)Adds a tweak to a private key modulo the curve order: the private half of a BIP32 child derivation.
public static byte[] publicKeyTweakAdd(byte[] publicKey, byte[] tweak, boolean compressed)Adds tweak * G to a public key: the public half of a BIP32 child derivation, matching privateKeyTweakAdd on the private key.
public static byte[] publicKeyAdd(byte[] a, byte[] b, boolean compressed)Adds two public keys as curve points.
public static Secp256k1.EcdsaSignature sign(byte[] hash, byte[] privateKey)Signs a 32-byte message hash.
public static boolean verify(byte[] hash, Secp256k1.EcdsaSignature signature, byte[] publicKey)Verifies a signature over a 32-byte hash.
public static byte[] recoverPublicKey(byte[] hash, Secp256k1.EcdsaSignature signature, boolean compressed)Recovers the public key that made a signature, from the signature’s recovery id: what Ethereum does instead of carrying the sender’s key in a transaction.

Inherited methods

Field details

PRIVATE_KEY_LENGTH

public static final int PRIVATE_KEY_LENGTH = 32
Length in bytes of a private key.

HASH_LENGTH

public static final int HASH_LENGTH = 32
Length in bytes of the message hash a signature covers.

COMPRESSED_PUBLIC_KEY_LENGTH

public static final int COMPRESSED_PUBLIC_KEY_LENGTH = 33
Length in bytes of a compressed public key (02/03 then x).

UNCOMPRESSED_PUBLIC_KEY_LENGTH

public static final int UNCOMPRESSED_PUBLIC_KEY_LENGTH = 65
Length in bytes of an uncompressed public key (04 then x then y).

Method details

isValidPrivateKey

public static boolean isValidPrivateKey(byte[] privateKey)
Tells whether the bytes are a usable private key: exactly 32 bytes holding a big-endian integer in [1, n-1].

publicKey

public static byte[] publicKey(byte[] privateKey, boolean compressed)
Derives the public key of a private key.

Parameters

privateKey byte[]
32 bytes in [1, n-1]
compressed boolean
true for the 33-byte SEC 1 form, false for the 65-byte form Ethereum derives an address from

Throws

CryptoException
if the private key is not valid

isValidPublicKey

public static boolean isValidPublicKey(byte[] publicKey)
Tells whether the bytes encode a point on the curve, in either SEC 1 form.

convertPublicKey

public static byte[] convertPublicKey(byte[] publicKey, boolean compressed)
Re-encodes a public key in the requested form.

Throws

CryptoException
if the key is not a point on the curve

privateKeyTweakAdd

public static byte[] privateKeyTweakAdd(byte[] privateKey, byte[] tweak)
Adds a tweak to a private key modulo the curve order: the private half of a BIP32 child derivation. Constant time.

Parameters

privateKey byte[]
32 bytes in [1, n-1]
tweak byte[]
32 bytes, less than n

Returns

(privateKey + tweak) mod n, 32 bytes

Throws

CryptoException
if either input is out of range or the sum is zero

publicKeyTweakAdd

public static byte[] publicKeyTweakAdd(byte[] publicKey, byte[] tweak, boolean compressed)
Adds tweak * G to a public key: the public half of a BIP32 child derivation, matching privateKeyTweakAdd on the private key.

Throws

CryptoException
if the key is not on the curve, the tweak is not less than n, or the result is the point at infinity

publicKeyAdd

public static byte[] publicKeyAdd(byte[] a, byte[] b, boolean compressed)
Adds two public keys as curve points.

Throws

CryptoException
if either key is not on the curve or the sum is the point at infinity

sign

public static Secp256k1.EcdsaSignature sign(byte[] hash, byte[] privateKey)
Signs a 32-byte message hash. The nonce is derived from the key and the hash as RFC 6979 specifies with HMAC-SHA256, so signing the same hash twice gives the same signature and no random number generator is involved. The result is always low-S and carries its recovery id.

Parameters

hash byte[]
32 bytes, the digest of the message (Keccak-256 of the RLP-encoded transaction on Ethereum, double SHA-256 on Bitcoin)
privateKey byte[]
32 bytes in [1, n-1]

Throws

CryptoException
if the hash is not 32 bytes or the key is not valid

verify

public static boolean verify(byte[] hash, Secp256k1.EcdsaSignature signature, byte[] publicKey)
Verifies a signature over a 32-byte hash. A signature whose s is in the upper half of the range is rejected, as libsecp256k1 and the Bitcoin and Ethereum networks reject it; see EcdsaSignature.normalize.

Returns

true if the signature was made over hash by the holder of the private key behind publicKey

Throws

CryptoException
if the hash is not 32 bytes or the public key is not a point on the curve

recoverPublicKey

public static byte[] recoverPublicKey(byte[] hash, Secp256k1.EcdsaSignature signature, boolean compressed)
Recovers the public key that made a signature, from the signature’s recovery id: what Ethereum does instead of carrying the sender’s key in a transaction. Unlike verify this accepts a high-S signature, as the EVM’s ecrecover does.

Parameters

hash byte[]
the 32 bytes that were signed
signature Secp256k1.EcdsaSignature
a signature whose recovery id is known (0 to 3)
compressed boolean
the form to return the key in

Returns

the public key, or null if no key could have produced the signature

Throws

CryptoException
if the hash is not 32 bytes or the signature has no recovery id