@@ -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