Class Secp256k1

java.lang.Object
com.codename1.security.Secp256k1

public final class Secp256k1 extends Object

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(byte[], Secp256k1.EcdsaSignature, byte[]) rejects a high-S signature the way libsecp256k1 does; recoverPublicKey(byte[], Secp256k1.EcdsaSignature, boolean) accepts either, the way the EVM's ecrecover does. A signature from another library can be lowered with Secp256k1.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 Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final class 
    An ECDSA signature: r and s as 32-byte big-endian integers, and the recovery id a signer knows and a verifier does not need.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    Length in bytes of a compressed public key (02/03 then x).
    static final int
    Length in bytes of the message hash a signature covers.
    static final int
    Length in bytes of a private key.
    static final int
    Length in bytes of an uncompressed public key (04 then x then y).
  • Method Summary

    Modifier and Type
    Method
    Description
    static byte[]
    convertPublicKey(byte[] publicKey, boolean compressed)
    Re-encodes a public key in the requested form.
    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].
    static boolean
    isValidPublicKey(byte[] publicKey)
    Tells whether the bytes encode a point on the curve, in either SEC 1 form.
    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.
    static byte[]
    publicKey(byte[] privateKey, boolean compressed)
    Derives the public key of a private key.
    static byte[]
    publicKeyAdd(byte[] a, byte[] b, boolean compressed)
    Adds two public keys as curve points.
    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(byte[], byte[]) on the private key.
    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.
    sign(byte[] hash, byte[] privateKey)
    Signs a 32-byte message hash.
    static boolean
    verify(byte[] hash, Secp256k1.EcdsaSignature signature, byte[] publicKey)
    Verifies a signature over a 32-byte hash.

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • PRIVATE_KEY_LENGTH

      public static final int PRIVATE_KEY_LENGTH
      Length in bytes of a private key.
      See Also:
    • HASH_LENGTH

      public static final int HASH_LENGTH
      Length in bytes of the message hash a signature covers.
      See Also:
    • COMPRESSED_PUBLIC_KEY_LENGTH

      public static final int COMPRESSED_PUBLIC_KEY_LENGTH
      Length in bytes of a compressed public key (02/03 then x).
      See Also:
    • UNCOMPRESSED_PUBLIC_KEY_LENGTH

      public static final int UNCOMPRESSED_PUBLIC_KEY_LENGTH
      Length in bytes of an uncompressed public key (04 then x then y).
      See Also:
  • 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: 32 bytes in [1, n-1]

      • compressed: 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: 32 bytes in [1, n-1]

      • tweak: 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(byte[], byte[]) 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: 32 bytes, the digest of the message (Keccak-256 of the RLP-encoded transaction on Ethereum, double SHA-256 on Bitcoin)

      • privateKey: 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 Secp256k1.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(byte[], Secp256k1.EcdsaSignature, byte[]) this accepts a high-S signature, as the EVM's ecrecover does.

      Parameters
      • hash: the 32 bytes that were signed

      • signature: a signature whose recovery id is known (0 to 3)

      • compressed: 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