Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 190 additions & 62 deletions CoreBitcoin/BTCKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,161 +9,289 @@
@class BTCPrivateKeyAddress;
@class BTCPrivateKeyAddressTestnet;

// BTCKey encapsulates EC public and private keypair (or only public part) on curve secp256k1.
// You can sign data and verify signatures.
// When instantiated with a public key, only signature verification is possible.
// When instantiated with a private key, all operations are available.
/**
* Encapsulates an EC keypair, or public key only, on the secp256k1 curve.
*
* @discussion A key initialized with a public key can only verify signatures.
* A key initialized with a private key can sign, verify, derive addresses, and
* export private-key formats.
*/
@interface BTCKey : NSObject

// Newly generated random key pair.
/** Initializes a newly generated random keypair. */
- (id) init;

// Instantiates a key without a secret counterpart.
// You can use -isValidSignature:hash:
/**
* Initializes a public-only key.
*
* @param publicKey Serialized public key data.
*
* @return Public-only key suitable for signature verification.
*/
- (id) initWithPublicKey:(NSData*)publicKey;

// Initializes public key using a point on elliptic curve secp256k1.
/**
* Initializes a public-only key using a point on secp256k1.
*
* @param curvePoint Curve point representing the public key.
*/
- (id) initWithCurvePoint:(BTCCurvePoint*)curvePoint;

// Instantiates a key with secret parameter (32 bytes).
/**
* Initializes a keypair with a 32-byte secp256k1 secret parameter.
*
* @param privateKey 32-byte private key.
*/
- (id) initWithPrivateKey:(NSData*)privateKey;

// Instantiates with a WIF-encoded private key (52 bytes like 5znkrJzL5GTFCaXWufUCUaPzDmLj2Pe2pWtAcSzg4hRUVxS2XqHa).
// See also -initWithPrivateKeyAddress.
/**
* Initializes a keypair with a WIF-encoded private key.
*
* @param wifString WIF string, such as
* `5znkrJzL5GTFCaXWufUCUaPzDmLj2Pe2pWtAcSzg4hRUVxS2XqHa`.
*
* @see initWithPrivateKeyAddress:
*/
- (id) initWithWIF:(NSString*)wifString;

// Instantiates with a DER-encoded private key (279 bytes).
/**
* Initializes a keypair with a DER-encoded private key.
*
* @param DERPrivateKey DER-encoded private key data.
*/
- (id) initWithDERPrivateKey:(NSData*)DERPrivateKey;

// These properties return mutable copy of data so you can clear it if needed.
/**
* @name Public and Private Key Material
*/

// publicKey is compressed if -publicKeyCompressed is YES.
/**
* Serialized public key.
*
* The returned data is mutable so callers can clear it if needed. The key is
* compressed when `publicKeyCompressed` is `YES`.
*/
@property(nonatomic, readonly) NSMutableData* publicKey;

// These are returning explicitly compressed or uncompressed copies of the public key.
/** Explicitly compressed serialized public key. */
@property(nonatomic, readonly) NSMutableData* compressedPublicKey;

/** Explicitly uncompressed serialized public key. */
@property(nonatomic, readonly) NSMutableData* uncompressedPublicKey;

// 32-byte secret parameter. That's all you need to get full key pair on secp256k1
/**
* 32-byte secret parameter.
*
* This is all that is needed to reconstruct the full keypair on secp256k1.
*/
@property(nonatomic, readonly) NSMutableData* privateKey;

// DER-encoded private key (279-byte) that includes secret and all curve parameters.
/** DER-encoded private key data that includes the secret and curve parameters. */
@property(nonatomic, readonly) NSMutableData* DERPrivateKey;

// Base58-encoded private key (or nil if privkey is not available).
/** Base58Check-encoded mainnet private key, or `nil` when no private key is available. */
@property(nonatomic, readonly) NSString* WIF;

/** Base58Check-encoded testnet private key, or `nil` when no private key is available. */
@property(nonatomic, readonly) NSString* WIFTestnet;

// When you set public key, this property reflects whether it is compressed or not.
// To set this property you must have private counterpart. Then, -publicKey will be compressed/uncompressed accordingly.
/**
* Whether the public key is compressed.
*
* @discussion When a public key is set, this property reflects its serialized
* form. To change it, the receiver must contain a private key. Then
* `-publicKey` returns compressed or uncompressed data accordingly.
*/
@property(nonatomic, getter=isPublicKeyCompressed) BOOL publicKeyCompressed;

// Returns public key as a point on secp256k1 curve.
/** Public key represented as a point on the secp256k1 curve. */
@property(nonatomic, readonly) BTCCurvePoint* curvePoint;

// Verifies signature for a given hash with a public key.
/**
* Verifies a signature for a 256-bit hash with the receiver's public key.
*
* @param signature DER-encoded signature.
* @param hash 256-bit hash that was signed.
*/
- (BOOL) isValidSignature:(NSData*)signature hash:(NSData*)hash;

// Multiplies a public key of the receiver with a given private key and returns resulting curve point as BTCKey object (pubkey only).
// Pubkey compression flag is the same as on receiver.
/**
* Performs ECDH multiplication with another private key.
*
* @param privkey Private key used as the scalar.
*
* @return Public-only key for the resulting curve point. The public-key
* compression flag matches the receiver.
*/
- (BTCKey*) diffieHellmanWithPrivateKey:(BTCKey*)privkey;

// Returns a signature data for a 256-bit hash using private key.
// Returns nil if signing failed or a private key is not present.
/**
* Signs a 256-bit hash with the receiver's private key.
*
* @return DER-encoded signature, or `nil` if signing fails or no private key is present.
*/
- (NSData*) signatureForHash:(NSData*)hash;

// Same as above, but also appends a hash type byte to the signature.
/**
* Signs a 256-bit hash and appends a Bitcoin signature hash-type byte.
*
* @param hash 256-bit hash to sign.
* @param hashType Signature hash type appended to the returned signature.
*/
- (NSData*) signatureForHash:(NSData*)hash hashType:(BTCSignatureHashType)hashType;

/** Deprecated alias for `-signatureForHash:hashType:`. */
- (NSData*) signatureForHash:(NSData*)hash withHashType:(BTCSignatureHashType)hashType DEPRECATED_ATTRIBUTE;

// [RFC6979 implementation](https://tools.ietf.org/html/rfc6979).
// Returns 32-byte `k` nonce generated deterministically from the `hash` and the private key.
// Returns a mutable data to make it clearable.
/**
* Returns the deterministic RFC6979 signature nonce for a hash.
*
* @param hash 256-bit hash that will be signed.
*
* @return Mutable 32-byte `k` nonce generated from `hash` and the private key,
* so callers can clear it when finished.
*
* @see https://tools.ietf.org/html/rfc6979
*/
- (NSMutableData*) signatureNonceForHash:(NSData*)hash;

// Clears all key data from memory making receiver invalid.
/** Clears all key data from memory and makes the receiver invalid. */
- (void) clear;


// BTCAddress Import/Export

/**
* @name BTCAddress Import and Export
*/

// Instantiate with a private key in a form of address. Also takes care about compressing pubkey if needed.
/**
* Initializes a keypair from a private-key address.
*
* Also configures public-key compression according to the address.
*/
- (id) initWithPrivateKeyAddress:(BTCPrivateKeyAddress*)privateKeyAddress;

// Public key hash.
// IMPORTANT: resulting address depends on whether `publicKeyCompressed` is YES or NO.
/**
* Public-key hash address.
*
* The resulting address depends on whether `publicKeyCompressed` is `YES`.
*/
@property(nonatomic, readonly) BTCPublicKeyAddress* publicKeyAddress DEPRECATED_ATTRIBUTE;

// Public key hash.
// IMPORTANT: resulting address depends on whether `publicKeyCompressed` is YES or NO.
/**
* Public-key hash address.
*
* The resulting address depends on whether `publicKeyCompressed` is `YES`.
*/
@property(nonatomic, readonly) BTCPublicKeyAddress* address;

/** Testnet public-key hash address. */
@property(nonatomic, readonly) BTCPublicKeyAddressTestnet* addressTestnet;

// Returns address for a public key (Hash160(pubkey)).
/** Address for the uncompressed public key: Hash160(public key). */
@property(nonatomic, readonly) BTCPublicKeyAddress* uncompressedPublicKeyAddress;

/** Address for the compressed public key: Hash160(public key). */
@property(nonatomic, readonly) BTCPublicKeyAddress* compressedPublicKeyAddress;

// Private key encoded in sipa format (base58 with compression flag).
/** Mainnet private key address encoded in WIF/SIPA format. */
@property(nonatomic, readonly) BTCPrivateKeyAddress* privateKeyAddress;

/** Testnet private key address encoded in WIF/SIPA format. */
@property(nonatomic, readonly) BTCPrivateKeyAddressTestnet* privateKeyAddressTestnet;





// Compact Signature
// 65 byte signature, which allows reconstructing the used public key.
/**
* @name Compact Signatures
*/

// Returns a compact signature for 256-bit hash. Aka "CKey::SignCompact" in BitcoinQT.
// Initially used for signing text messages (see BTCKey+BitcoinSignedMessage).
/**
* Returns a compact signature for a 256-bit hash.
*
* Compact signatures are 65 bytes and allow reconstruction of the public key
* used to sign. This is also known as `CKey::SignCompact` in Bitcoin Core.
*/
- (NSData*) compactSignatureForHash:(NSData*)data;

// Verifies digest against given compact signature. On success returns a public key.
/**
* Verifies a hash against a compact signature.
*
* @return Recovered public key on success, otherwise `nil`.
*/
+ (BTCKey*) verifyCompactSignature:(NSData*)compactSignature forHash:(NSData*)hash;

// Verifies signature of the hash with its public key.
/** Verifies a compact signature for a hash with the receiver's public key. */
- (BOOL) isValidCompactSignature:(NSData*)signature forHash:(NSData*)hash;





// Bitcoin Signed Message
// BitcoinQT-compatible textual message signing API
/**
* @name Bitcoin Signed Messages
*/



// Returns a signature for message prepended with "Bitcoin Signed Message:\n" line.
/**
* Returns a signature for a Bitcoin Signed Message string.
*
* The message is signed using the Bitcoin Signed Message prefix.
*/
- (NSData*) signatureForMessage:(NSString*)message;

/** Returns a signature for binary message data using the Bitcoin Signed Message prefix. */
- (NSData*) signatureForBinaryMessage:(NSData*)data;

// Verifies message against given signature. On success returns a public key.
/**
* Verifies a textual Bitcoin Signed Message.
*
* @return Recovered public key on success, otherwise `nil`.
*/
+ (BTCKey*) verifySignature:(NSData*)signature forMessage:(NSString*)message;

/**
* Verifies a binary Bitcoin Signed Message.
*
* @return Recovered public key on success, otherwise `nil`.
*/
+ (BTCKey*) verifySignature:(NSData*)signature forBinaryMessage:(NSData*)data;

// Verifies signature of the message with its public key.
/** Verifies a textual Bitcoin Signed Message with the receiver's public key. */
- (BOOL) isValidSignature:(NSData*)signature forMessage:(NSString*)message;
- (BOOL) isValidSignature:(NSData*)signature forBinaryMessage:(NSData*)data;

/** Verifies a binary Bitcoin Signed Message with the receiver's public key. */
- (BOOL) isValidSignature:(NSData*)signature forBinaryMessage:(NSData*)data;

// Canonical checks

// Used by BitcoinQT within OP_CHECKSIG to not relay transactions with non-canonical signature or a public key.
// Normally, signatures and pubkeys are encoded in a canonical form and majority of the transactions are good.
// Unfortunately, sometimes OpenSSL segfaults on some garbage data in place of a signature or a pubkey.
// Read more on that here: https://bitcointalk.org/index.php?topic=8392.80
/**
* @name Canonical Encoding Checks
*/

// Note: non-canonical pubkey could still be valid for EC internals of OpenSSL and thus accepted by Bitcoin nodes.
/**
* Checks whether public-key data uses canonical Bitcoin encoding.
*
* @discussion Used by Bitcoin Core within `OP_CHECKSIG` relay policy. A
* non-canonical public key can still be valid to OpenSSL EC internals and may
* be accepted by Bitcoin nodes.
*
* See https://bitcointalk.org/index.php?topic=8392.80
*/
+ (BOOL) isCanonicalPublicKey:(NSData*)data error:(NSError**)errorOut;

// Checks if the script signature is canonical.
// The signature is assumed to include hash type byte (see BTCSignatureHashType).
/**
* Checks whether a script signature uses canonical encoding.
*
* @param data Signature data including the hash-type byte.
* @param verifyLowerS If `YES`, also enforces lower-S normalization.
* @param errorOut Optional error output.
*/
+ (BOOL) isCanonicalSignatureWithHashType:(NSData*)data verifyLowerS:(BOOL)verifyLowerS error:(NSError**)errorOut;

/** Deprecated alias for canonical signature checking with even-S verification. */
+ (BOOL) isCanonicalSignatureWithHashType:(NSData*)data verifyEvenS:(BOOL)verifyEvenS error:(NSError**)errorOut DEPRECATED_ATTRIBUTE;


@end