Skip to content

Instantly share code, notes, and snippets.

@nakov
Last active April 9, 2024 16:32
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save nakov/1dcbe26988e18f7a4d013b65d8803ffc to your computer and use it in GitHub Desktop.
Save nakov/1dcbe26988e18f7a4d013b65d8803ffc to your computer and use it in GitHub Desktop.
ECDSA in JavaScript: secp256k1-based sign / verify / recoverPubKey
let elliptic = require('elliptic');
let sha3 = require('js-sha3');
let ec = new elliptic.ec('secp256k1');
// let keyPair = ec.genKeyPair();
let keyPair = ec.keyFromPrivate("97ddae0f3a25b92268175400149d65d6887b9cefaf28ea2c078e05cdc15a3c0a");
let privKey = keyPair.getPrivate("hex");
let pubKey = keyPair.getPublic();
console.log(`Private key: ${privKey}`);
console.log("Public key :", pubKey.encode("hex").substr(2));
console.log("Public key (compressed):",
pubKey.encodeCompressed("hex"));
console.log();
let msg = 'Message for signing';
let msgHash = sha3.keccak256(msg);
let signature = ec.sign(msgHash, privKey, "hex", {canonical: true});
console.log(`Msg: ${msg}`);
console.log(`Msg hash: ${msgHash}`);
console.log("Signature:", signature);
console.log();
let hexToDecimal = (x) => ec.keyFromPrivate(x, "hex").getPrivate().toString(10);
let pubKeyRecovered = ec.recoverPubKey(
hexToDecimal(msgHash), signature, signature.recoveryParam, "hex");
console.log("Recovered pubKey:", pubKeyRecovered.encodeCompressed("hex"));
let validSig = ec.verify(msgHash, signature, pubKeyRecovered);
console.log("Signature valid?", validSig);
@nakov
Copy link
Author

nakov commented Apr 4, 2018

The output of the above is:

Private key: 97ddae0f3a25b92268175400149d65d6887b9cefaf28ea2c078e05cdc15a3c0a
Public key : 7b83ad6afb1209f3c82ebeb08c0c5fa9bf6724548506f2fb4f991e2287a77090177316ca82b0bdf70cd9dee145c3002c0da1d92626449875972a27807b73b42e
Public key (compressed): 027b83ad6afb1209f3c82ebeb08c0c5fa9bf6724548506f2fb4f991e2287a77090

Msg: Message for signing
Msg hash: ce7df6b1b2852c5c156b683a9f8d4a8daeda2f35f025cb0cf34943dcac70d6a3
Signature: Signature {
  r: <BN: 6f0156091cbe912f2d5d1215cc3cd81c0963c8839b93af60e0921b61a19c5430>,
  s: <BN: c71006dd93f3508c432daca21db0095f4b16542782b7986f48a5d0ae3c583d4>,
  recoveryParam: 1 }

Recovered pubKey: 027b83ad6afb1209f3c82ebeb08c0c5fa9bf6724548506f2fb4f991e2287a77090
Signature valid? true

@qisbic
Copy link

qisbic commented Jun 7, 2018

I found your examples very helpful. But I am struggling on 1 thing..

How do I pass the "signature" in your example in javascript here to the

C# ECDSA-secp256k1-example.cs and verify with signature and the public key?

--Javascript --
var derSign = signature.toDER()

-- C# --
The derSign is loaded into C# from Javascript over the internet.

EthECDSASignature signatureNew = EthECDSASignature.FromDER(derSign);
var pubKeyRecovered = EthECKey.RecoverFromSignature(signatureNew, msgHash);

This would produce error, V is null. Therefore I can't verify the signature with publickey.

bool validSig = pubKeyRecovered.Verify(msgBytes, signature);
.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment