From 871a527822ab9f8b98b7096736a13f4deec4c649 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Wed, 26 Feb 2025 15:15:41 -0800 Subject: [PATCH] WIP support for low-R grinding --- .../org/bitcoinj/secp/ffm/Secp256k1Foreign.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/secp-ffm/src/main/java/org/bitcoinj/secp/ffm/Secp256k1Foreign.java b/secp-ffm/src/main/java/org/bitcoinj/secp/ffm/Secp256k1Foreign.java index 8d049d5..2a0ad0c 100644 --- a/secp-ffm/src/main/java/org/bitcoinj/secp/ffm/Secp256k1Foreign.java +++ b/secp-ffm/src/main/java/org/bitcoinj/secp/ffm/Secp256k1Foreign.java @@ -259,7 +259,7 @@ public byte[] ecPubKeySerialize(SecpPubKey pubKey, int flags) { // public SecpPoint.Uncompressed ecPointUncompress(SecpPoint.Compressed compressedPoint) { // return compressedPoint.uncompress(); // } - + /* package */ static MemorySegment pubKeySerializeSegment(MemorySegment pubKeySegment, int flags) { int byteSize = switch(flags) { case 2 -> 65; // SECP256K1_EC_UNCOMPRESSED()) @@ -303,16 +303,24 @@ private MemorySegment pubKeyParse(SecpPubKey pubKeyData) { @Override public SecpResult ecdsaSign(byte[] msg_hash_data, SecpPrivKey seckey) { + return ecdsaSign(msg_hash_data, seckey, secp256k1_h.NULL()); + } + + public SecpResult ecdsaSign(byte[] msg_hash_data, SecpPrivKey seckey, byte[] ndata) { + // TODO: validate ndata is exactly 32-bytes long + return ecdsaSign(msg_hash_data, seckey, arena.allocateFrom(JAVA_BYTE, ndata)); + } + + public SecpResult ecdsaSign(byte[] msg_hash_data, SecpPrivKey seckey, MemorySegment ndataSegment) { /* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a * custom nonce function, passing `NULL` will use the RFC-6979 safe default. * Signing with a valid context, verified secret key * and the default nonce function should never fail. */ MemorySegment msg_hash = arena.allocateFrom(JAVA_BYTE, msg_hash_data); MemorySegment sig = secp256k1_ecdsa_signature.allocate(arena); - MemorySegment nullCallback = secp256k1_h.NULL(); // Double-check this (normally you shouldn't use a NULL pointer for a null callback) - MemorySegment nullPointer = secp256k1_h.NULL(); + MemorySegment nonceFpNull = secp256k1_h.NULL(); // Double-check this (normally you shouldn't use a NULL pointer for a null callback) MemorySegment privKeySeg = arena.allocateFrom(JAVA_BYTE, seckey.getEncoded()); - int return_val = secp256k1_h.secp256k1_ecdsa_sign(ctx, sig, msg_hash, privKeySeg, nullCallback, nullPointer); + int return_val = secp256k1_h.secp256k1_ecdsa_sign(ctx, sig, msg_hash, privKeySeg, nonceFpNull, ndataSegment); privKeySeg.fill((byte) 0x00); return SecpResult.checked(return_val, () -> EcdsaSignature.of(sig.toArray(JAVA_BYTE))); }