Thank you embhorn and Jacob!  It works now.

The example is very helpful, can't believe I just ignored it...

Hello,

Here's the background:
We need to send a token which includes something like device information and service information to devices for identification. This token is generated and signed by our service, but maybe verified by 3rd services. We don't want to distribute the private key to the 3rd services' servers.

Now We implement our service using OpenSSL like this:

    b = BIO_new_mem_buf(pem, pem_len);
    pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
    BIO_free(b);

    if (EVP_PKEY_id(pkey) != EVP_PKEY_ED25519) return invalid_key_type;

    size_t sig_len = 64;
    unsigned char sig[64];
    EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
    EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, pkey);
    EVP_DigestSign(md_ctx, sig, &sig_len, tk, tk_len);

We found WolfCrypt ED25519 performance is much better than OpenSSL. But When we did the same thing using WolfCrypt we got a BAD_FUNC_ARG error:

    ed25519_key pkey;

    rc = wc_ed25519_init(&pkey);
    if (rc) goto err;

    rc = wc_Ed25519PrivateKeyDecode(dbuf, &idx, &pkey, dlen);
    if (rc) goto err;

    byte sig[ED25519_SIG_SIZE];
    word32 sig_len = ED25519_SIG_SIZE;

    rc = wc_ed25519_sign_msg(tk, tk_len, sig, &sig_len, &pkey);
    if (rc) goto err; /* BAD_FUNC_ARG here */

I digged the WolfCrypt source code and saw this in wolfcrypt/src/ed25519.c:

int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out,
                            word32 *outLen, ed25519_key* key, byte type,
                            const byte* context, byte contextLen)
{
    /* ... */

    if (!key->pubKeySet)
        return BAD_FUNC_ARG;

    /* ... */
}

It seems we could only use the public key for sign... Is it possible to use ED25519 private key for sign and public key for verification?

THANK YOU VERY MUCH!