/// <summary> /// Get compressed and compact signature (possible in not canonical form) /// </summary> /// <param name="data">Hashed data</param> /// <param name="seckey">Private key (32 bytes)</param> /// <returns> 65 bytes compressed / compact</returns> public static byte[] SignCompressedCompact(byte[] data, byte[] seckey) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (data.Length == 0) { throw new ArgumentOutOfRangeException(nameof(data)); } if (seckey == null) { throw new ArgumentNullException(nameof(seckey)); } if (seckey.Length != 32) { throw new ArgumentOutOfRangeException(nameof(seckey)); } byte recoveryId = 0; secp256k1_ecdsa_recoverable_signature sig = new secp256k1_ecdsa_recoverable_signature(); byte loop = 0; int index = 0; bool rec; byte[] extra = null; Random r = new Random(); do { if (loop == 0xff) { index = index + 1; loop = 0; } if (loop > 0) { extra = new byte[32]; r.NextBytes(extra); } loop++; rec = secp256k1_ecdsa_sign_recoverable(Ctx, sig, data, seckey, null, extra); } while (!(rec && is_canonical(sig.data))); var output65 = new byte[65]; secp256k1_ecdsa_recoverable_signature_serialize_compact(Ctx, output65, 1, out recoveryId, sig); //4 - compressed | 27 - compact output65[0] = (byte)(recoveryId + 4 + 27); return(output65); }
private static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature sig, secp256k1_scalar r, secp256k1_scalar s, byte recid) { if (secp256k1_scalar.Size == 32) { Util.Memcpy(r.d, 0, sig.data, 0, 32); // memcpy(&sig.data[0], r, 32); Util.Memcpy(s.d, 0, sig.data, 32, 32); // memcpy(&sig->data[32], s, 32); } else { Scalar.secp256k1_scalar_get_b32(sig.data, 0, r); Scalar.secp256k1_scalar_get_b32(sig.data, 32, s); } sig.data[64] = recid; }
/// <summary>Signs a data and returns the signature in compact form. Returns null on failure.</summary> /// <param name="dataage">The data to sign. This data is not hashed. For use with bitcoins, you probably want to double-SHA256 hash this before calling this method.</param> /// <param name="seckeyeKey">The private key to use to sign the data.</param> /// <param name="recoveryId">This will contain the recovery ID needed to retrieve the key from the compact signature using the RecoverKeyFromCompact method.</param> public static byte[] SignCompact(byte[] data, byte[] seckey, out int recoveryId) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (data.Length == 0) { throw new ArgumentOutOfRangeException(nameof(data)); } if (seckey == null) { throw new ArgumentNullException(nameof(seckey)); } if (seckey.Length != 32) { throw new ArgumentOutOfRangeException(nameof(seckey)); } recoveryId = 0; secp256k1_ecdsa_recoverable_signature sig = new secp256k1_ecdsa_recoverable_signature(); { if (!secp256k1_ecdsa_sign_recoverable(Ctx, sig, data, seckey, null, null)) { return(null); } } var sigbytes = new byte[64]; byte recid; { if (!secp256k1_ecdsa_recoverable_signature_serialize_compact(Ctx, sigbytes, out recid, sig)) { return(null); } } recoveryId = recid; return(sigbytes); }
private static byte[] sign_compact(byte[] data, byte[] seckey, out byte recoveryId) { secp256k1_ecdsa_recoverable_signature sig = new secp256k1_ecdsa_recoverable_signature(); byte loop = 0; int index = 0; bool rec; var extra = new byte[32]; do { extra[index] = loop++; if (loop == 0xff) { index = index + 1; loop = 0; } rec = secp256k1_ecdsa_sign_recoverable(Ctx, sig, data, seckey, null, extra); } while (!rec); var output64 = new byte[64]; secp256k1_ecdsa_recoverable_signature_serialize_compact(Ctx, output64, out recoveryId, sig); return(output64); }
private static int sign_compact(secp256k1_context ctx, byte[] msg32, byte[] seckey, byte[] output64, out byte recid) { secp256k1_ecdsa_recoverable_signature sig = new secp256k1_ecdsa_recoverable_signature(); byte loop = 0; int index = 0; bool rec = false; var extra = new byte[32]; do { extra[index] = loop; loop++; if (extra[index] == 0xff) { index = index + 1; } rec = secp256k1_ecdsa_sign_recoverable(ctx, sig, msg32, seckey, null, extra); } while (!rec); secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, output64, out recid, sig); return(loop); }
private static void secp256k1_ecdsa_recoverable_signature_load(secp256k1_context ctx, secp256k1_scalar r, secp256k1_scalar s, out byte recid, secp256k1_ecdsa_recoverable_signature sig) { //(void)ctx; if (secp256k1_scalar.Size == 32) { /* When the secp256k1_scalar type is exactly 32 byte, use its * representation inside secp256k1_ecdsa_signature, as conversion is very fast. * Note that secp256k1_ecdsa_signature_save must use the same representation. */ Util.Memcpy(sig.data, 0, r.d, 0, 32); //memcpy(r, &sig->data[0], 32); Util.Memcpy(sig.data, 32, s.d, 0, 32); //memcpy(s, &sig->data[32], 32); } else { Scalar.secp256k1_scalar_set_b32(r, sig.data, 0); Scalar.secp256k1_scalar_set_b32(s, sig.data, 32); } recid = sig.data[64]; }
private static bool secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context ctx, byte[] outputxx, int skip, out byte recid, secp256k1_ecdsa_recoverable_signature sig) { secp256k1_scalar r = new secp256k1_scalar(); secp256k1_scalar s = new secp256k1_scalar(); recid = 0; if (outputxx == null) { ctx.illegal_callback?.Invoke(null, new secp256k1_callback("(outputxx != null)")); return(false); } //___________________________________________________________________________________________________________________________________ if (sig == null) { ctx.illegal_callback?.Invoke(null, new secp256k1_callback("(sig != null)")); return(false); } //___________________________________________________________________________________________________________________________________ secp256k1_ecdsa_recoverable_signature_load(ctx, r, s, out recid, sig); Scalar.secp256k1_scalar_get_b32(outputxx, skip + 0, r); Scalar.secp256k1_scalar_get_b32(outputxx, skip + 32, s); return(true); }
private static bool secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context ctx, byte[] output64, out byte recid, secp256k1_ecdsa_recoverable_signature sig) { return(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, output64, 0, out recid, sig)); }
private static bool secp256k1_ecdsa_sign_recoverable(secp256k1_context ctx, secp256k1_ecdsa_recoverable_signature signature, byte[] msg32, byte[] seckey, secp256k1_nonce_function noncefp, byte[] noncedata) { if (ctx == null || msg32 == null || signature == null || seckey == null) { throw new NullReferenceException(); } if (!ECMultGen.secp256k1_ecmult_gen_context_is_built(ctx.ecmult_gen_ctx)) { throw new ArithmeticException(); } if (noncefp == null) { noncefp = Secp256k1.secp256k1_nonce_function_default; } secp256k1_scalar r, s; secp256k1_scalar sec, non, msg; byte recid = 1; bool ret = false; var overflow = false; sec = new secp256k1_scalar(); Scalar.secp256k1_scalar_set_b32(sec, seckey, ref overflow); r = new secp256k1_scalar(); s = new secp256k1_scalar(); /* Fail if the secret key is invalid. */ if (!overflow && !Scalar.secp256k1_scalar_is_zero(sec)) { var nonce32 = new byte[32]; uint count = 0; msg = new secp256k1_scalar(); Scalar.secp256k1_scalar_set_b32(msg, msg32); non = new secp256k1_scalar(); while (true) { ret = noncefp(nonce32, msg32, seckey, null, noncedata, count); if (!ret) { break; } Scalar.secp256k1_scalar_set_b32(non, nonce32, ref overflow); if (!Scalar.secp256k1_scalar_is_zero(non) && !overflow) { if (secp256k1_ecdsa_sig_sign(ctx.ecmult_gen_ctx, r, s, sec, msg, non, out recid)) { break; } } count++; } Util.MemSet(nonce32, 0, 32); //memset(nonce32, 0, 32); Scalar.secp256k1_scalar_clear(msg); Scalar.secp256k1_scalar_clear(non); Scalar.secp256k1_scalar_clear(sec); } if (ret) { secp256k1_ecdsa_recoverable_signature_save(signature, r, s, recid); } else { Util.MemSet(signature.data, 0, secp256k1_ecdsa_recoverable_signature.Size); //memset(signature, 0, sizeof(* signature)); } return(ret); }