0

I see a strange behaviour on ECDSA signature verification from the nodejs's secp256k1 package that sometimes fails the signature check. I use the following public key:

33 2E 16 0F 4C 24 1F 50 0B 5A 67 13 EB E1 52 52 
D1 E2 BA A0 0A B9 7B 54 6E 5C CD 32 E4 FE 26 2A 
B5 51 5A BF CA EF D5 9D FD 35 AA 3A 4B 23 1C 7C 
1A 2E 3B 4A B7 84 7C 49 89 66 66 98 E6 4F FA B4

Now, given the message hash

0C 8D 6D 12 60 93 2B 13 04 DA 48 56 F5 DB 14 DE 
E6 51 69 97 5D 04 89 1F 5E F3 56 A5 77 12 31 10

and the signature

989EFF3505B719017F9DC0CB1D46CBC305940CA458742357BABC0E81C306704FE4F1CD5921E42FEC1CD184FBF0D09E82BCCF3B7F8706D15E4B331302F9845A1F

with both Python's ecdsa and ST's X-CUBE-CRYPTOLIB it verifies successfully, instead with nodejs's secp256k1 the signature gets rejected. Any ideas? On nodejs I have to add 0x04 before the publickey and it works perfectly in most of the cases. The following signatures/hash couple for example is accepted:

hash

43 82 6b bf 48 61 77 e7 c9 3e 47 b3 ad cf 80 c2 51 46 29 a1 97 15 13 3b 8c b5 bb a0 89 c5 cb bc

Signature

D5FA95C2B66DA7ECB294E9C677495BC24425076C6C9DE42DAB9C4F0FD25AE854649E6F3042611F8441DAE82A14D6145E3C3EB8504A8F673FADDF94702CF641C3

Thanks

Topaco
  • 40,594
  • 4
  • 35
  • 62
Fabio Angeletti
  • 311
  • 3
  • 12
  • What do you mean by "most cases"? You're just showing us one case. The public key in ECDSA is simply a pair of integers, but there can be different conventions about how to encode them as a list of bytes, and it sounds like the NodeJS library requires a 0x04 byte at the beginning. You could read the documentations of the respective libraries to see what formats they expect. – David Grayson Nov 06 '22 at 21:30
  • I try to clarify myself. Using exactly the same code to generate signatures (from x-cube-cryptolib) often the verification fails but only when verifying with secp256k1 package on nodejs. The exactly same signature is accepted by both python’s ecdsa and x-cube-cryptolib – Fabio Angeletti Nov 07 '22 at 06:34
  • What does "exact same code" mean, since you didn't show any code? Maybe it would help if you could show us two signatures that were generated with the same code, one which fails in nodejs and one which succeeds. Also provide a link to the nodejs library source code so we can inspect how it works. – David Grayson Nov 07 '22 at 08:32

1 Answers1

2

Bitcoin and the secp256k1 library use canonical signatures, while this constraint does not apply to the ecdsa library (and presumably not to X-CUBE-CRYPTOLIB).

Canonical signature: In general, if (r, s) is a valid signature, then (r, -s) = (r, n - s) is also a valid signature (n: order of the base point). A canonical signature uses the value s' = n - s if s > n/2, see here.

Therefore, signatures with s > n/2 are always validated as invalid by the secp256k1 library, while this does not apply to the ecdsa library. Signatures with smaller s are validated identically by both libraries. This is the reason for the sporadic occurrence of the issue.

For the secp256k1 library to verify the posted signature as valid, it must be normalized. The secp256k1 library provides the signatureNormalize() function for this purpose:

const crypto = require('crypto')
const secp256k1 = require('secp256k1')
var signature = Buffer.from('989EFF3505B719017F9DC0CB1D46CBC305940CA458742357BABC0E81C306704FE4F1CD5921E42FEC1CD184FBF0D09E82BCCF3B7F8706D15E4B331302F9845A1F', 'hex');
signature = secp256k1.signatureNormalize(signature); // FIX!
var publicKey = Buffer.from('04332E160F4C241F500B5A6713EBE15252D1E2BAA00AB97B546E5CCD32E4FE262AB5515ABFCAEFD59DFD35AA3A4B231C7C1A2E3B4AB7847C4989666698E64FFAB4', 'hex');
var messageHash = Buffer.from("0C8D6D1260932B1304DA4856F5DB14DEE65169975D04891F5EF356A577123110", 'hex');
console.log(secp256k1.ecdsaVerify(signature, messageHash, publicKey)); // true
Topaco
  • 40,594
  • 4
  • 35
  • 62