I am trying to create a signature in Dart using secp256k1
. But I am generating different signature as compared to javascript. JavaScript Method as follows:
import * as secp from "@noble/secp256k1";
const signature = await secp.sign(msgHash, hashingPrivateKey, {
der: false,
recovered: true,
});
I need to pass these der
and recovered
parameters in my Dart code. I wasn’t able to find any option to add those params in my Dart code. My code is as follows:
import 'package:secp256k1/secp256k1.dart' as secp;
var pk = secp.PrivateKey.fromHex(hashingPrivateKey);
var pub = pk.publicKey;
final signature = pk.signature(msgHash);
Each time I run this function in dart , different signature.R and different signature.S are returning.Could you please explain ?
Javascript library version is "@noble/secp256k1": "^1.7.0",
input values are
msgHash : fea272bf4112f825697cfebe6f8f7dd8de1726d0c62ab45b78de4cb62f99a8dc
hashingPrivateKey : bf751b9f4cacc36548c56a88dc47aa87b93b415705b9a62aa0a669d98381f619
result signature from javascript is A2Mt3EHNy1HHgBwt46PSUBJG0BdyPs326hoixd6/AJdaY9axCXwEQRHgt4Xb1dr9LLr5r+C/fRM24ySeioOBWAA=
result signature from dart is D+ZSaLNGbFiAinyJ/B5GcLwI7dl1NqyHDkKG34iUXvlUhQ7Q6LF2gR94Nbyx2JZ3TH0fVZ4mU4MGAyWxtEDJeA==
generated from
var sig = Uint8List.fromList([
...NanoHelpers.bigIntToBytes(signature.R),
...NanoHelpers.bigIntToBytes(signature.S)
]);
using pointycaslte
I tried the below function which also couldn’t able to generate same signature.
ECSignature createSignature(String msgHash, String hashingPrivateKey) {
var domain = ECDomainParameters('secp256k1');
ECPrivateKey ecPrivateKey = ECPrivateKey(
NanoHelpers.byteToBigInt(
Uint8List.fromList(hex.decode(hashingPrivateKey))),
domain);
ECSignature signature = CryptoUtils.ecSign(
ecPrivateKey, Uint8List.fromList(hex.decode(msgHash)),
algorithmName: 'SHA-256/DET-ECDSA');
var g = ecPrivateKey.parameters?.G;
var ecPublicKey = ECPublicKey(
g! *
NanoHelpers.byteToBigInt(
Uint8List.fromList(hex.decode(hashingPrivateKey))),
domain,
);
var verify = CryptoUtils.ecVerify(
ecPublicKey, Uint8List.fromList(hex.decode(msgHash)), signature,
algorithm: 'SHA-256/DET-ECDSA');
print('verify====$verify');
print('ECSignature.R===${signature.r.toRadixString(16)}');
print('ECSignature.S===${signature.s.toRadixString(16)}');
var sig = Uint8List.fromList([
...NanoHelpers.bigIntToBytes(signature.r),
...NanoHelpers.bigIntToBytes(signature.s)
]);
print('sig=createSignature==1==${base64.encode(sig)}');
print('sig==createSignature=1==${base64.encode(sig).length}');
return signature;
}
2
Answers
finally able to resolve it by creating custom Signature with recoveryId and DeterministicSignature method .the code as follows.
custom Signature class is given below.
and finally
It worked well.Thank you.
It is more convenient to use existing libraries instead of implementing all from scratch. In addition, there is an increased risk of side-channel attacks with custom implementations.
A deterministic ECDSA signature can be implemented with PointyCastle:
The Recovery ID can be determined with the sec package:
Test:
Running the JavaScript code with the @noble/secp256k1 library and v1.7.0 results in an array with 2 elements. The first element contains the signature in IEEE P1363 format as Uint8Array, the second element contains the recovery ID as int:
The result is the same as that of the Dart code!
Note that the result does not follow the format you posted. You may have applied a conversion function. To get the result you posted, the signature and recovery ID must be concatenated and must be Base64 encoded (this is not a standard format):