-
Notifications
You must be signed in to change notification settings - Fork 400
Home
Dylan Sharhon edited this page Apr 10, 2020
·
2 revisions
There are some quirks and important undocumented APIs that people keep stumbling on. Examples use hexadecimal string i/o and the Bitcoin-compatible secp256k1 curve (others are similar...but different)
Instantiation shortcut
ec = elliptic.ec('secp256k1')
Calculate a private key's 33-byte compressed public key
compressed = true
pub = ec.keyFromPrivate(pri, 'hex').getPublic(compressed, 'hex')
Hash a UTF-8 string or hex using the hash.js library
// utf8 input
msg = hash.sha256().update(string).digest('hex')
// hex input
msg = hash.sha256().update(hex, 'hex').digest('hex')
Generate a Bitcoin-compatible DER-encoded signature with canonical (aka normalized) S values
canonical = { canonical: true }
der = ec.sign(msg, pri, 'hex', canonical).toDER('hex')
Verify a DER-encoded signature
bool = ec.verify(msg, der, pub, 'hex')
Generate a recoverable signature in libsecp256k1 65-byte { R | S | index } format
canonical = { canonical: true }
array = elliptic.utils.toArray(msg, 'hex') // HASHED MSG MUST BE BYTE ARRAY
sig_obj = ec.sign(array, pri, 'hex', canonical)
r = sig_obj.r.toString('hex', 32) // MUST SPECIFY 32 BYTES TO KEEP LEADING ZEROS
s = sig_obj.s.toString('hex', 32)
i = sig_obj.recoveryParam.toString(16).padStart(2, '0')
sig = r + s + i
Recover the compressed public key from a 65-byte recoverable signature
compressed = true
sig_obj = { r: sig.slice(0, 64), s: sig.slice(64, 128) }
recoveryParam = parseInt(sig.slice(128, 130), 16)
array = elliptic.utils.toArray(msg, 'hex') // HASHED MSG MUST BE BYTE ARRAY
pub = ec.recoverPubKey(array, sig_obj, recoveryParam, 'hex').encode('hex', compressed)