Skip to content

Commit 6c779c4

Browse files
committed
add ecdsa signature method
Signed-off-by: garyschulte <garyschulte@gmail.com>
1 parent 3e369d1 commit 6c779c4

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

secp256k1/src/main/java/org/hyperledger/besu/nativelib/secp256k1/LibSecp256k1Graal.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,48 @@ static native int secp256k1EcdsaVerify(
242242
CCharPointer msg32,
243243
CCharPointer pubkey);
244244

245+
/**
246+
* Create an ECDSA signature.
247+
*
248+
* @param ctx a secp256k1 context object, initialized for signing
249+
* @param sig pointer to 64-byte signature buffer (output)
250+
* @param msg32 the 32-byte message hash being signed
251+
* @param seckey pointer to a 32-byte secret key
252+
* @param noncefp pointer to a nonce generation function (can be null for default)
253+
* @param ndata pointer to arbitrary data for nonce generation function (can be null)
254+
* @return 1 if signature created, 0 if nonce generation failed or secret key invalid
255+
*/
256+
@CFunction(value = "secp256k1_ecdsa_sign")
257+
static native int secp256k1EcdsaSign(
258+
PointerBase ctx,
259+
CCharPointer sig,
260+
CCharPointer msg32,
261+
CCharPointer seckey,
262+
PointerBase noncefp,
263+
PointerBase ndata);
264+
245265
// ============ Recoverable Signature Operations ============
246266

267+
/**
268+
* Create a recoverable ECDSA signature.
269+
*
270+
* @param ctx a secp256k1 context object, initialized for signing
271+
* @param sig pointer to 65-byte recoverable signature buffer (output)
272+
* @param msg32 the 32-byte message hash being signed
273+
* @param seckey pointer to a 32-byte secret key
274+
* @param noncefp pointer to a nonce generation function (can be null for default)
275+
* @param ndata pointer to arbitrary data for nonce generation function (can be null)
276+
* @return 1 if signature created, 0 if nonce generation failed or secret key invalid
277+
*/
278+
@CFunction(value = "secp256k1_ecdsa_sign_recoverable")
279+
static native int secp256k1EcdsaSignRecoverable(
280+
PointerBase ctx,
281+
CCharPointer sig,
282+
CCharPointer msg32,
283+
CCharPointer seckey,
284+
PointerBase noncefp,
285+
PointerBase ndata);
286+
247287
/**
248288
* Parse a compact ECDSA signature (64 bytes + recovery id).
249289
*
@@ -639,6 +679,61 @@ public static void ecdsaRecoverableSignatureSerializeCompact(
639679
}
640680
}
641681

682+
/**
683+
* Java-friendly wrapper for creating a recoverable ECDSA signature.
684+
* Uses the default nonce generation function (RFC 6979).
685+
*
686+
* @param ctx context object (must be initialized with SECP256K1_CONTEXT_SIGN)
687+
* @param seckey 32-byte private key
688+
* @param message 32-byte message hash
689+
* @return 65-byte signature (64 bytes compact signature + 1 byte recovery id), or null if signing failed
690+
*/
691+
public static byte[] ecdsaSignRecoverable(PointerBase ctx, byte[] seckey, byte[] message) {
692+
if (seckey.length != 32) {
693+
throw new IllegalArgumentException("Secret key must be 32 bytes");
694+
}
695+
if (message.length != 32) {
696+
throw new IllegalArgumentException("Message must be 32 bytes");
697+
}
698+
699+
byte[] recSig = new byte[SECP256K1_ECDSA_RECOVERABLE_SIGNATURE_SIZE];
700+
try (PinnedObject pinnedRecSig = PinnedObject.create(recSig);
701+
PinnedObject pinnedMessage = PinnedObject.create(message);
702+
PinnedObject pinnedSeckey = PinnedObject.create(seckey)) {
703+
704+
int result = secp256k1EcdsaSignRecoverable(
705+
ctx,
706+
pinnedRecSig.addressOfArrayElement(0),
707+
pinnedMessage.addressOfArrayElement(0),
708+
pinnedSeckey.addressOfArrayElement(0),
709+
PointerBase.nullPointer(), // use default nonce function
710+
PointerBase.nullPointer()); // no extra nonce data
711+
712+
if (result != 1) {
713+
return null;
714+
}
715+
716+
// Serialize to compact format with recovery id
717+
byte[] compact64 = new byte[64];
718+
int[] recid = new int[1];
719+
try (PinnedObject pinnedCompact = PinnedObject.create(compact64);
720+
PinnedObject pinnedRecid = PinnedObject.create(recid)) {
721+
722+
secp256k1EcdsaRecoverableSignatureSerializeCompact(
723+
ctx,
724+
pinnedCompact.addressOfArrayElement(0),
725+
(CIntPointer) pinnedRecid.addressOfArrayElement(0),
726+
pinnedRecSig.addressOfArrayElement(0));
727+
728+
// Return 65 bytes: 64-byte compact + 1-byte recid
729+
byte[] result65 = new byte[65];
730+
System.arraycopy(compact64, 0, result65, 0, 64);
731+
result65[64] = (byte) recid[0];
732+
return result65;
733+
}
734+
}
735+
}
736+
642737
/**
643738
* Convert a recoverable ECDSA signature to a regular ECDSA signature.
644739
*

0 commit comments

Comments
 (0)