static
int SM2_sig_verify(const EC_KEY *key, const ECDSA_SIG *sig, const BIGNUM *e)
{
    int ret = 0;
    const EC_GROUP *group = EC_KEY_get0_group(key);
    const BIGNUM *order = EC_GROUP_get0_order(group);
    BN_CTX *ctx = NULL;
    EC_POINT *pt = NULL;

    BIGNUM *t = NULL;
    BIGNUM *x1 = NULL;
    const BIGNUM *r = NULL;
    const BIGNUM *s = NULL;

    ctx = BN_CTX_new();
    if (ctx == NULL)
        goto done;
    pt = EC_POINT_new(group);
    if (pt == NULL)
        goto done;

    BN_CTX_start(ctx);

    t = BN_CTX_get(ctx);
    x1 = BN_CTX_get(ctx);

    if (x1 == NULL)
        goto done;

    /*
       B1: verify whether r' in [1,n-1], verification failed if not
       B2: vefify whether s' in [1,n-1], verification failed if not
       B3: set M'~=ZA || M'
       B4: calculate e'=Hv(M'~)
       B5: calculate t = (r' + s') modn, verification failed if t=0
       B6: calculate the point (x1', y1')=[s']G + [t]PA
       B7: calculate R=(e'+x1') modn, verfication pass if yes, otherwise failed
     */

    ECDSA_SIG_get0(sig, &r, &s);

    if (BN_cmp(r, BN_value_one()) < 0)
        goto done;
    if (BN_cmp(s, BN_value_one()) < 0)
        goto done;

    if (BN_cmp(order, r) <= 0)
        goto done;
    if (BN_cmp(order, s) <= 0)
        goto done;

    if (BN_mod_add(t, r, s, order, ctx) == 0)
        goto done;

    if (BN_is_zero(t) == 1)
        goto done;

    if (EC_POINT_mul(group, pt, s, EC_KEY_get0_public_key(key), t, ctx) == 0)
        goto done;

    if (EC_POINT_get_affine_coordinates_GFp(group, pt, x1, NULL, ctx) == 0)
        goto done;

    if (BN_mod_add(t, e, x1, order, ctx) == 0)
        goto done;

    if (BN_cmp(r, t) == 0)
        ret = 1;

 done:
    EC_POINT_free(pt);
    BN_CTX_free(ctx);
    return ret;
}