Class ECKey

  • All Implemented Interfaces:
    EncryptableItem
    Direct Known Subclasses:
    DeterministicKey

    public class ECKey
    extends java.lang.Object
    implements EncryptableItem

    Represents an elliptic curve public and (optionally) private key, usable for digital signatures but not encryption. Creating a new ECKey with the empty constructor will generate a new random keypair. Other static methods can be used when you already have the public or private parts. If you create a key with only the public part, you can check signatures but not create them.

    ECKey also provides access to Bitcoin Core compatible text message signing, as accessible via the UI or JSON-RPC. This is slightly different to signing raw bytes - if you want to sign your own data and it won't be exposed as text to people, you don't want to use this. If in doubt, ask on the mailing list.

    The ECDSA algorithm supports key recovery in which a signature plus a couple of discriminator bits can be reversed to find the public key used to calculate it. This can be convenient when you have a message and a signature and want to find out who signed it, rather than requiring the user to provide the expected identity.

    This class supports a variety of serialization forms. The methods that accept/return byte arrays serialize private keys as raw byte arrays and public keys using the SEC standard byte encoding for public keys. Signatures are encoded using ASN.1/DER inside the Bitcoin protocol.

    A key can be compressed or uncompressed. This refers to whether the public key is represented when encoded into bytes as an (x, y) coordinate on the elliptic curve, or whether it's represented as just an X co-ordinate and an extra byte that carries a sign bit. With the latter form the Y coordinate can be calculated dynamically, however, because the binary serialization is different the address of a key changes if its compression status is changed. If you deviate from the defaults it's important to understand this: money sent to a compressed version of the key will have a different address to the same key in uncompressed form. Whether a public key is compressed or not is recorded in the SEC binary serialisation format, and preserved in a flag in this class so round-tripping preserves state. Unless you're working with old software or doing unusual things, you can usually ignore the compressed/uncompressed distinction.

    • Field Detail

      • AGE_COMPARATOR

        public static final java.util.Comparator<ECKey> AGE_COMPARATOR
        Sorts oldest keys first, newest last.
      • PUBKEY_COMPARATOR

        public static final java.util.Comparator<ECKey> PUBKEY_COMPARATOR
        Compares by extracting pub key as a byte[] and using a lexicographic comparator
      • CURVE

        public static final org.bouncycastle.crypto.params.ECDomainParameters CURVE
        The parameters of the secp256k1 curve that Bitcoin uses.
      • HALF_CURVE_ORDER

        public static final java.math.BigInteger HALF_CURVE_ORDER
        Equal to CURVE.getN().shiftRight(1), used for canonicalising the S value of a signature. If you aren't sure what this is about, you can ignore it.
      • priv

        @Nullable
        protected final java.math.BigInteger priv
      • creationTime

        @Nullable
        protected java.time.Instant creationTime
      • encryptedPrivateKey

        protected EncryptedData encryptedPrivateKey
    • Constructor Detail

      • ECKey

        public ECKey()
        Generates an entirely new keypair. Point compression is used so the resulting public key will be 33 bytes (32 for the co-ordinate and 1 byte to represent the y bit).
      • ECKey

        public ECKey​(java.security.SecureRandom secureRandom)
        Generates an entirely new keypair with the given SecureRandom object. Point compression is used so the resulting public key will be 33 bytes (32 for the co-ordinate and 1 byte to represent the y bit).
      • ECKey

        protected ECKey​(@Nullable
                        java.math.BigInteger priv,
                        org.bouncycastle.math.ec.ECPoint pub,
                        boolean compressed)
      • ECKey

        protected ECKey​(@Nullable
                        java.math.BigInteger priv,
                        LazyECPoint pub)
    • Method Detail

      • fromASN1

        public static ECKey fromASN1​(byte[] asn1privkey)
        Construct an ECKey from an ASN.1 encoded private key. These are produced by OpenSSL and stored by Bitcoin Core in its wallet. Note that this is slow because it requires an EC point multiply.
      • fromPrivate

        public static ECKey fromPrivate​(java.math.BigInteger privKey)
        Creates an ECKey given the private key only. The public key is calculated from it (this is slow). The resulting public key is compressed.
      • fromPrivate

        public static ECKey fromPrivate​(java.math.BigInteger privKey,
                                        boolean compressed)
        Creates an ECKey given the private key only. The public key is calculated from it (this is slow).
        Parameters:
        compressed - Determines whether the resulting ECKey will use a compressed encoding for the public key.
      • fromPrivate

        public static ECKey fromPrivate​(byte[] privKeyBytes)
        Creates an ECKey given the private key only. The public key is calculated from it (this is slow). The resulting public key is compressed.
      • fromPrivate

        public static ECKey fromPrivate​(byte[] privKeyBytes,
                                        boolean compressed)
        Creates an ECKey given the private key only. The public key is calculated from it (this is slow).
        Parameters:
        compressed - Determines whether the resulting ECKey will use a compressed encoding for the public key.
      • fromPrivateAndPrecalculatedPublic

        public static ECKey fromPrivateAndPrecalculatedPublic​(java.math.BigInteger priv,
                                                              org.bouncycastle.math.ec.ECPoint pub,
                                                              boolean compressed)
        Creates an ECKey that simply trusts the caller to ensure that point is really the result of multiplying the generator point by the private key. This is used to speed things up when you know you have the right values already.
        Parameters:
        compressed - Determines whether the resulting ECKey will use a compressed encoding for the public key.
      • fromPrivateAndPrecalculatedPublic

        public static ECKey fromPrivateAndPrecalculatedPublic​(byte[] priv,
                                                              byte[] pub)
        Creates an ECKey that simply trusts the caller to ensure that point is really the result of multiplying the generator point by the private key. This is used to speed things up when you know you have the right values already. The compression state of the point will be preserved.
      • fromPublicOnly

        public static ECKey fromPublicOnly​(org.bouncycastle.math.ec.ECPoint pub,
                                           boolean compressed)
        Creates an ECKey that cannot be used for signing, only verifying signatures, from the given point.
        Parameters:
        compressed - Determines whether the resulting ECKey will use a compressed encoding for the public key.
      • fromPublicOnly

        public static ECKey fromPublicOnly​(byte[] pub)
        Creates an ECKey that cannot be used for signing, only verifying signatures, from the given encoded point. The compression state of pub will be preserved.
      • fromPublicOnly

        public static ECKey fromPublicOnly​(ECKey key)
      • decompress

        public ECKey decompress()
        Returns a copy of this key, but with the public point represented in uncompressed form. Normally you would never need this: it's for specialised scenarios or when backwards compatibility in encoded form is necessary.
      • fromEncrypted

        public static ECKey fromEncrypted​(EncryptedData encryptedPrivateKey,
                                          KeyCrypter crypter,
                                          byte[] pubKey)
        Constructs a key that has an encrypted private component. The given object wraps encrypted bytes and an initialization vector. Note that the key will not be decrypted during this call: the returned ECKey is unusable for signing unless a decryption key is supplied.
      • isPubKeyOnly

        public boolean isPubKeyOnly()
        Returns true if this key doesn't have unencrypted access to private key bytes. This may be because it was never given any private key bytes to begin with (a watching key), or because the key is encrypted. You can use isEncrypted() to tell the cases apart.
      • hasPrivKey

        public boolean hasPrivKey()
        Returns true if this key has unencrypted access to private key bytes. Does the opposite of isPubKeyOnly().
      • isWatching

        public boolean isWatching()
        Returns true if this key is watch only, meaning it has a public key but no private key.
      • toASN1

        public byte[] toASN1()
        Output this ECKey as an ASN.1 encoded private key, as understood by OpenSSL or used by Bitcoin Core in its wallet storage format.
        Throws:
        ECKey.MissingPrivateKeyException - if the private key is missing or encrypted.
      • publicKeyFromPrivate

        public static byte[] publicKeyFromPrivate​(java.math.BigInteger privKey,
                                                  boolean compressed)
        Returns public key bytes from the given private key. To convert a byte array into a BigInteger, use ByteUtils.bytesToBigInteger(byte[])
      • publicPointFromPrivate

        public static org.bouncycastle.math.ec.ECPoint publicPointFromPrivate​(java.math.BigInteger privKey)
        Returns public key point from the given private key. To convert a byte array into a BigInteger, use ByteUtils.bytesToBigInteger(byte[])
      • getPubKeyHash

        public byte[] getPubKeyHash()
        Gets the hash160 form of the public key (as seen in addresses).
      • getPubKey

        public byte[] getPubKey()
        Gets the raw public key value. This appears in transaction scriptSigs. Note that this is not the same as the pubKeyHash/address.
      • getPubKeyPoint

        public org.bouncycastle.math.ec.ECPoint getPubKeyPoint()
        Gets the public key in the form of an elliptic curve point object from Bouncy Castle.
      • getPrivKey

        public java.math.BigInteger getPrivKey()
        Gets the private key in the form of an integer field element. The public key is derived by performing EC point addition this number of times (i.e. point multiplying).
        Throws:
        java.lang.IllegalStateException - if the private key bytes are not available.
      • isCompressed

        public boolean isCompressed()
        Returns whether this key is using the compressed form or not. Compressed pubkeys are only 33 bytes, not 64.
      • sign

        public ECKey.ECDSASignature sign​(Sha256Hash input)
                                  throws KeyCrypterException
        Signs the given hash and returns the R and S components as BigIntegers. In the Bitcoin protocol, they are usually encoded using ASN.1 format, so you want toASN1() instead. However sometimes the independent components can be useful, for instance, if you're going to do further EC maths on them.
        Throws:
        KeyCrypterException - if this ECKey doesn't have a private part.
      • sign

        public ECKey.ECDSASignature sign​(Sha256Hash input,
                                         @Nullable
                                         AesKey aesKey)
                                  throws KeyCrypterException
        Signs the given hash and returns the R and S components as BigIntegers. In the Bitcoin protocol, they are usually encoded using DER format, so you want ECKey.ECDSASignature.encodeToDER() instead. However sometimes the independent components can be useful, for instance, if you're doing to do further EC maths on them.
        Parameters:
        aesKey - The AES key to use for decryption of the private key. If null then no decryption is required.
        Throws:
        KeyCrypterException - if there's something wrong with aesKey.
        ECKey.MissingPrivateKeyException - if this key cannot sign because it's pubkey only.
      • verify

        public static boolean verify​(byte[] data,
                                     ECKey.ECDSASignature signature,
                                     byte[] pub)

        Verifies the given ECDSA signature against the message bytes using the public key bytes.

        When using native ECDSA verification, data must be 32 bytes, and no element may be larger than 520 bytes.

        Parameters:
        data - Hash of the data to verify.
        signature - ASN.1 encoded signature.
        pub - The public key bytes to use.
      • verify

        public static boolean verify​(byte[] data,
                                     byte[] signature,
                                     byte[] pub)
                              throws SignatureDecodeException
        Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key.
        Parameters:
        data - Hash of the data to verify.
        signature - ASN.1 encoded signature.
        pub - The public key bytes to use.
        Throws:
        SignatureDecodeException - if the signature is unparseable in some way.
      • verify

        public boolean verify​(byte[] hash,
                              byte[] signature)
                       throws SignatureDecodeException
        Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key.
        Parameters:
        hash - Hash of the data to verify.
        signature - ASN.1 encoded signature.
        Throws:
        SignatureDecodeException - if the signature is unparseable in some way.
      • verify

        public boolean verify​(Sha256Hash sigHash,
                              ECKey.ECDSASignature signature)
        Verifies the given R/S pair (signature) against a hash using the public key.
      • verifyOrThrow

        public void verifyOrThrow​(byte[] hash,
                                  byte[] signature)
                           throws SignatureDecodeException,
                                  java.security.SignatureException
        Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key, and throws an exception if the signature doesn't match
        Throws:
        SignatureDecodeException - if the signature is unparseable in some way.
        java.security.SignatureException - if the signature does not match.
      • verifyOrThrow

        public void verifyOrThrow​(Sha256Hash sigHash,
                                  ECKey.ECDSASignature signature)
                           throws java.security.SignatureException
        Verifies the given R/S pair (signature) against a hash using the public key, and throws an exception if the signature doesn't match
        Throws:
        java.security.SignatureException - if the signature does not match.
      • isPubKeyCanonical

        public static boolean isPubKeyCanonical​(byte[] pubkey)
        Returns true if the given pubkey is canonical, i.e. the correct length taking into account compression.
      • isPubKeyCompressed

        public static boolean isPubKeyCompressed​(byte[] encoded)
        Returns true if the given pubkey is in its compressed form.
      • signMessage

        @Deprecated
        public java.lang.String signMessage​(java.lang.String message)
                                     throws KeyCrypterException
        Deprecated.
        use signMessage(String, ScriptType) instead and specify the correct script type
        Signs a text message using the standard Bitcoin messaging signing format and returns the signature as a base64 encoded string.
        Throws:
        java.lang.IllegalStateException - if this ECKey does not have the private part.
        KeyCrypterException - if this ECKey is encrypted and no AESKey is provided or it does not decrypt the ECKey.
      • signMessage

        public java.lang.String signMessage​(java.lang.String message,
                                            ScriptType scriptType)
                                     throws KeyCrypterException
        Signs a text message using the standard Bitcoin messaging signing format and returns the signature as a base64 encoded string.
        Throws:
        java.lang.IllegalStateException - if this ECKey does not have the private part.
        KeyCrypterException - if this ECKey is encrypted and no AESKey is provided or it does not decrypt the ECKey.
      • signMessage

        @Deprecated
        public java.lang.String signMessage​(java.lang.String message,
                                            @Nullable
                                            AesKey aesKey)
                                     throws KeyCrypterException
        Deprecated.
        use signMessage(String, AesKey, ScriptType) instead and specify the correct script type
        Signs a text message using the standard Bitcoin messaging signing format and returns the signature as a base64 encoded string.
        Throws:
        java.lang.IllegalStateException - if this ECKey does not have the private part.
        KeyCrypterException - if this ECKey is encrypted and no AESKey is provided or it does not decrypt the ECKey.
      • signMessage

        public java.lang.String signMessage​(java.lang.String message,
                                            @Nullable
                                            AesKey aesKey,
                                            ScriptType scriptType)
                                     throws KeyCrypterException
        Signs a text message using the standard Bitcoin messaging signing format and returns the signature as a base64 encoded string.
        Throws:
        java.lang.IllegalArgumentException - if uncompressed key is used for Segwit scriptType, or unsupported script type is specified
        java.lang.IllegalStateException - if this ECKey does not have the private part.
        KeyCrypterException - if this ECKey is encrypted and no AESKey is provided or it does not decrypt the ECKey.
      • signedMessageToKey

        public static ECKey signedMessageToKey​(java.lang.String message,
                                               java.lang.String signatureBase64)
                                        throws java.security.SignatureException
        Given an arbitrary piece of text and a Bitcoin-format message signature encoded in base64, returns an ECKey containing the public key that was used to sign it. This can then be compared to the expected public key to determine if the signature was correct. These sorts of signatures are compatible with the Bitcoin-Qt/bitcoind format generated by signmessage/verifymessage RPCs and GUI menu options. They are intended for humans to verify their communications with each other, hence the base64 format and the fact that the input is text.
        Parameters:
        message - Some piece of human readable text.
        signatureBase64 - The Bitcoin-format message signature in base64
        Throws:
        java.security.SignatureException - If the public key could not be recovered or if there was a signature format error.
      • verifyMessage

        @Deprecated
        public void verifyMessage​(java.lang.String message,
                                  java.lang.String signatureBase64)
                           throws java.security.SignatureException
        Deprecated.
        Use MessageVerifyUtils.verifyMessage(Address, String, String) instead, which works with different address types, which works also with legacy segwit (P2SH-P2WPKH, 3…) and native segwit addresses (P2WPKH, bc1…).
        Convenience wrapper around signedMessageToKey(String, String). If the key derived from the signature is not the same as this one, throws a SignatureException.
        Throws:
        java.security.SignatureException
      • findRecoveryId

        public byte findRecoveryId​(Sha256Hash hash,
                                   ECKey.ECDSASignature sig)
        Returns the recovery ID, a byte with value between 0 and 3, inclusive, that specifies which of 4 possible curve points was used to sign a message. This value is also referred to as "v".
        Throws:
        java.lang.RuntimeException - if no recovery ID can be found.
      • recoverFromSignature

        @Nullable
        public static ECKey recoverFromSignature​(int recId,
                                                 ECKey.ECDSASignature sig,
                                                 Sha256Hash message,
                                                 boolean compressed)

        Given the components of a signature and a selector value, recover and return the public key that generated the signature according to the algorithm in SEC1v2 section 4.1.6.

        The recId is an index from 0 to 3 which indicates which of the 4 possible keys is the correct one. Because the key recovery operation yields multiple potential keys, the correct key must either be stored alongside the signature, or you must be willing to try each recId in turn until you find one that outputs the key you are expecting.

        If this method returns null it means recovery was not possible and recId should be iterated.

        Given the above two points, a correct usage of this method is inside a for loop from 0 to 3, and if the output is null OR a key that is not the one you expect, you try again with the next recId.

        Parameters:
        recId - Which possible key to recover.
        sig - the R and S components of the signature, wrapped.
        message - Hash of the data that was signed.
        compressed - Whether or not the original pubkey was compressed.
        Returns:
        An ECKey containing only the public part, or null if recovery wasn't possible.
      • getPrivKeyBytes

        public byte[] getPrivKeyBytes()
        Returns a 32 byte array containing the private key.
        Throws:
        ECKey.MissingPrivateKeyException - if the private key bytes are missing/encrypted.
      • getPrivateKeyEncoded

        public DumpedPrivateKey getPrivateKeyEncoded​(Network network)
        Exports the private key in the form used by Bitcoin Core's "dumpprivkey" and "importprivkey" commands. Use the DumpedPrivateKey.toString() method to get the string.
        Parameters:
        network - The network this key is intended for use on.
        Returns:
        Private key bytes as a DumpedPrivateKey.
        Throws:
        java.lang.IllegalStateException - if the private key is not available.
      • creationTime

        public java.util.Optional<java.time.Instant> creationTime()
        Returns the creation time of this key, or empty if the key was deserialized from a version that did not store that data.
        Specified by:
        creationTime in interface EncryptableItem
      • setCreationTime

        public void setCreationTime​(java.time.Instant creationTime)
        Sets the creation time of this key. This method can be useful when you have a raw key you are importing from somewhere else.
        Parameters:
        creationTime - creation time of this key
      • clearCreationTime

        public void clearCreationTime()
        Clears the creation time of this key. This is mainly used deserialization and cloning. Normally you should not need to use this, as keys should have proper creation times whenever possible.
      • setCreationTimeSeconds

        @Deprecated
        public void setCreationTimeSeconds​(long creationTimeSecs)
        Deprecated.
      • encrypt

        public ECKey encrypt​(KeyCrypter keyCrypter,
                             AesKey aesKey)
                      throws KeyCrypterException
        Create an encrypted private key with the keyCrypter and the AES key supplied. This method returns a new encrypted key and leaves the original unchanged.
        Parameters:
        keyCrypter - The keyCrypter that specifies exactly how the encrypted bytes are created.
        aesKey - The KeyParameter with the AES encryption key (usually constructed with keyCrypter#deriveKey and cached as it is slow to create).
        Returns:
        encryptedKey
        Throws:
        KeyCrypterException
      • decrypt

        public ECKey decrypt​(KeyCrypter keyCrypter,
                             AesKey aesKey)
                      throws KeyCrypterException
        Create a decrypted private key with the keyCrypter and AES key supplied. Note that if the aesKey is wrong, this has some chance of throwing KeyCrypterException due to the corrupted padding that will result, but it can also just yield a garbage key.
        Parameters:
        keyCrypter - The keyCrypter that specifies exactly how the decrypted bytes are created.
        aesKey - The KeyParameter with the AES encryption key (usually constructed with keyCrypter#deriveKey and cached).
        Throws:
        KeyCrypterException
      • decrypt

        public ECKey decrypt​(AesKey aesKey)
                      throws KeyCrypterException
        Create a decrypted private key with AES key. Note that if the AES key is wrong, this has some chance of throwing KeyCrypterException due to the corrupted padding that will result, but it can also just yield a garbage key.
        Parameters:
        aesKey - The KeyParameter with the AES encryption key (usually constructed with keyCrypter#deriveKey and cached).
        Throws:
        KeyCrypterException
      • encryptionIsReversible

        public static boolean encryptionIsReversible​(ECKey originalKey,
                                                     ECKey encryptedKey,
                                                     KeyCrypter keyCrypter,
                                                     AesKey aesKey)

        Check that it is possible to decrypt the key with the keyCrypter and that the original key is returned.

        Because it is a critical failure if the private keys cannot be decrypted successfully (resulting of loss of all bitcoins controlled by the private key) you can use this method to check when you *encrypt* a wallet that it can definitely be decrypted successfully.

        See Wallet.encrypt(KeyCrypter keyCrypter, AesKey aesKey) for example usage.

        Returns:
        true if the encrypted key can be decrypted back to the original key successfully.
      • isEncrypted

        public boolean isEncrypted()
        Indicates whether the private key is encrypted (true) or not (false). A private key is deemed to be encrypted when there is both a KeyCrypter and the encryptedPrivateKey is non-zero.
        Specified by:
        isEncrypted in interface EncryptableItem
      • getSecretBytes

        @Nullable
        public byte[] getSecretBytes()
        A wrapper for getPrivKeyBytes() that returns null if the private key bytes are missing or would have to be derived (for the HD key case).
        Specified by:
        getSecretBytes in interface EncryptableItem
      • getEncryptedPrivateKey

        @Nullable
        public EncryptedData getEncryptedPrivateKey()
        Returns the the encrypted private key bytes and initialisation vector for this ECKey, or null if the ECKey is not encrypted.
      • getKeyCrypter

        @Nullable
        public KeyCrypter getKeyCrypter()
        Returns the KeyCrypter that was used to encrypt to encrypt this ECKey. You need this to decrypt the ECKey.
      • equals

        public boolean equals​(java.lang.Object o)
        Overrides:
        equals in class java.lang.Object
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class java.lang.Object
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object
      • toStringWithPrivate

        public java.lang.String toStringWithPrivate​(@Nullable
                                                    AesKey aesKey,
                                                    Network network)
        Produce a string rendering of the ECKey INCLUDING the private key. Unless you absolutely need the private key it is better for security reasons to just use toString().
      • toStringWithPrivate

        @Deprecated
        public java.lang.String toStringWithPrivate​(@Nullable
                                                    AesKey aesKey,
                                                    NetworkParameters params)
        Produce a string rendering of the ECKey INCLUDING the private key. Unless you absolutely need the private key it is better for security reasons to just use toString().
      • getPrivateKeyAsHex

        public java.lang.String getPrivateKeyAsHex()
      • getPublicKeyAsHex

        public java.lang.String getPublicKeyAsHex()
      • getPrivateKeyAsWiF

        public java.lang.String getPrivateKeyAsWiF​(Network network)
      • formatKeyWithAddress

        public void formatKeyWithAddress​(boolean includePrivateKeys,
                                         @Nullable
                                         AesKey aesKey,
                                         java.lang.StringBuilder builder,
                                         Network network,
                                         ScriptType outputScriptType,
                                         @Nullable
                                         java.lang.String comment)