private static secp256k1_context secp256k1_context_create(Secp256K1Options flags)
        {
            var ret = new secp256k1_context
            {
                illegal_callback = IllegalCallback,
                error_callback   = ErrorCallback
            };

            if ((flags & Secp256K1Options.FlagsTypeMask) != Secp256K1Options.FlagsTypeContext)
            {
                ret.illegal_callback?.Invoke(null, new secp256k1_callback("Invalid flags"));
                return(null);
            }

            ECMult.secp256k1_ecmult_context_init(ret.ecmult_ctx);
            ECMultGen.secp256k1_ecmult_gen_context_init(ret.ecmult_gen_ctx);

            if (flags.HasFlag(Secp256K1Options.FlagsBitContextSign))
            {
                ECMultGen.secp256k1_ecmult_gen_context_build(ret.ecmult_gen_ctx, ret.error_callback);
            }
            if (flags.HasFlag(Secp256K1Options.FlagsBitContextVerify))
            {
                ECMult.secp256k1_ecmult_context_build(ret.ecmult_ctx, ret.error_callback);
            }

            return(ret);
        }
        private static bool secp256k1_ecdsa_sig_sign(secp256k1_ecmult_gen_context ctx, secp256k1_scalar sigr, secp256k1_scalar sigs, secp256k1_scalar seckey,
                                                     secp256k1_scalar message, secp256k1_scalar nonce, out byte recid)
        {
            var              b = new byte[32];
            secp256k1_gej    rp;
            secp256k1_ge     r        = new secp256k1_ge();
            secp256k1_scalar n        = new secp256k1_scalar();
            bool             overflow = false;

            ECMultGen.secp256k1_ecmult_gen(ctx, out rp, nonce);
            Group.secp256k1_ge_set_gej(r, rp);
            Field.secp256k1_fe_normalize(r.x);
            Field.secp256k1_fe_normalize(r.y);
            Field.secp256k1_fe_get_b32(b, r.x);
            Scalar.secp256k1_scalar_set_b32(sigr, b, ref overflow);
            /* These two conditions should be checked before calling */
            Util.VERIFY_CHECK(!Scalar.secp256k1_scalar_is_zero(sigr));
            Util.VERIFY_CHECK(!overflow);


            // The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
            // of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
            recid = (byte)((overflow ? 2 : 0) | (Field.secp256k1_fe_is_odd(r.y) ? 1 : 0));

            Scalar.secp256k1_scalar_mul(n, sigr, seckey);
            Scalar.secp256k1_scalar_add(n, n, message);
            Scalar.secp256k1_scalar_inverse(sigs, nonce);
            Scalar.secp256k1_scalar_mul(sigs, sigs, n);
            Scalar.secp256k1_scalar_clear(n);
            Group.secp256k1_gej_clear(rp);
            Group.secp256k1_ge_clear(r);
            if (Scalar.secp256k1_scalar_is_zero(sigs))
            {
                return(false);
            }
            if (Scalar.secp256k1_scalar_is_high(sigs))
            {
                Scalar.secp256k1_scalar_negate(sigs, sigs);
                recid ^= 1;
            }
            return(true);
        }
        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);
        }