1
$\begingroup$

I'm trying to understand the DER-encoded signatures for the secp256k1 (ECDSA) curve better, so I have the following data array: 000102030405060708090a, which is a hex-encoded version of an array containing the numbers 0 to 10.

Also, I have the signed it with the following private key: fabb33890c65b059996546344a7e8c5adc09167fe9e09ddd6cbcac5a84790f7f, and corresponding public key: {x: '1b6ae9e65a66ee3de4d04d479a806fc0f3266a0aa12e0c03f8c0f31e1bbf98fd', y: 'abc78ffe0a5381472098738d0d14b0c0f1bdda149ccf5866a4b523b8bcc9fba6'}

In Java, I get the following DER signature: 3045022065A67F8FF9CB5EA8BE899E94CB338FE09E2E596BC047D936FC2B96DC013B5DFC022100BE123D3F143AF91E4551AAFAE49C9187F64E323F5660D6C6198A9446C3F818A1, with the following code:

BigInteger priv = new BigInteger("fabb33890c65b059996546344a7e8c5adc09167fe9e09ddd6cbcac5a84790f7f", 16);
PrivateKey privateKey = getPrivateKeyFromECBigIntAndCurve(priv, "secp256k1");
byte[] data = DatatypeConverter.parseHexBinary("000102030405060708090a");

Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(privateKey);
signature.update(data);
byte[] signed = signature.sign();
DatatypeConverter.printHexBinary(signed);

However, in JavaScript using the Elliptic or any other library, I get the following signature: 304502210099d0c79559ab4e5484a116e858ce7f59b91050cf4931a925438d876fad500ed2022067fd6e1012ed7ebcd772546bd5bf130f8af1b8282c5395f4a7164bc55255975c, using the following code:

const ec = new EC('secp256k1');
const key = ec.keyFromPrivate(privateKeyHex, 'hex');
const signature = key.sign(msg, { canonical: true });
signature.toDER('hex');

In C++, using the library botan and with the code beneath I get the following signature: 304402201EE0F965F837E7C0874C99B6C2B8C7475C7DD748AC9521B40A3BEDDB58A7722A02205125EFB0E36F6ABB59A97AFAB5D2795BCBA3D1A181D97D20587B6DC2CED5299A.

Botan::AutoSeeded_RNG rng;
Botan::PK_Signer signer(*privateKey, rng, "EMSA1(SHA-256)", Botan::DER_SEQUENCE);
signer.sign_message(data, rng);

Is there a reason for these differences, because signing it in one language and verifying it in another language will give an error. Also, if possible, how would I get the result of Java using JavaScript? My guess is that it has something to do with the encoding.

Thanks in advance!

$\endgroup$
  • $\begingroup$ "However, in JavaScript using the Elliptic or any other library, I get the following signature..": getting the same signature multiple times, even from the same implementation, is a sure sign that the implementation is a variant of ECDSA, or/and misused, or/and broken: true ECDSA is randomized, so that signing the same message twice will yield different results with overwhelming probability. $\endgroup$ – fgrieu Mar 28 at 16:04
3
$\begingroup$

Is there a reason for these differences

You do realize that ECDSA is randomized [1], that is, signing the same message twice with the same private key will generate two different signatures. This is normal, and not due to you using three different ECDSA implementations.

All three signatures are DER-encodings of 'a list of two integers, both of which are 32 byte positive values', which is the expected encoding of an ECDSA signature. Note: in DER, if you encode a value between $2^{255}$ and $2^{256}-1$, that uses an additional byte. That happens about half the time (for both integers) in an ECDSA secp256k1signature, and accounts for the slight length differences in your examples.

because signing it in one language and verifying it in another language will give an error.

Have you tried it?

I'm trying to understand the DER-encoded signatures for the secp256k1 (ECDSA) curve better,

Ok, here is the break down (using the first signature as an example)

30 - This is a magic number that says "this is a list of objects"

45 - This signifies that the list of objects takes up 45 hex (69 decimal) bytes (not counting the magic number or the length field itself)

02 - This is a magic number that says "this is an integer"

20 - This says that this integer takes up 20 hex (32 decimal) bytes

65A67F8FF9CB5EA8BE899E94CB338FE09E2E596BC047D936FC2B96DC013B5DFC - These 32 bytes are the integer (in bigendian notation)

02 - This is a magic number that says "this is an integer"

21 - This says that this integer takes up 21 hex (33 decimal) bytes. This is one byte longer because DER states that "if the top bit of an integer is a 1, the integer is negative", and so to encode a positive integer with a msbit of 1, we need to prepend a 00 byte (increasing its length by 1)

00BE123D3F143AF91E4551AAFAE49C9187F64E323F5660D6C6198A9446C3F818A1 - These 33 bytes are the integer (again, in bigendian notation).

The two encoded integers are the r, s values of the ECDSA signature


[1]: actually, there are deterministic versions of ECDSA, where the message and the private key are used to generate the 'randomness' used to generate the ECDSA signature - I assume that's not in play here, or at least, your three examples don't use the exact same method of doing determinism.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Thank you for your elaborate explanation, is there a reason why Java verifies the java and c++ signatures, but not the signatures of javascript? Also, the javascript signatures are not random, does that have something to do with it? $\endgroup$ – Tjappo Mar 16 at 15:20
  • $\begingroup$ @Tjappo: I wouldn't know why JavaScript signatures don't verify (my guess - JavaScript might not interpret the private key the same way - can you get what JavaScript thinks the public key is?) Also, the nonrandomness of JavaScript is not likely to be the issue - they've probably implemented something from RFC 6979... $\endgroup$ – poncho Mar 16 at 15:23
  • $\begingroup$ This is the public key: {x: '1b6ae9e65a66ee3de4d04d479a806fc0f3266a0aa12e0c03f8c0f31e1bbf98fd', y: 'abc78ffe0a5381472098738d0d14b0c0f1bdda149ccf5866a4b523b8bcc9fba6'}. $\endgroup$ – Tjappo Mar 16 at 15:35
  • 1
    $\begingroup$ Poncho, thank you for your answer. In the end, the elliptic library was broken and using another library fixed the problem. $\endgroup$ – Tjappo Mar 17 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.