public static byte[] ecdh(XECPrivateKey privateKey, XECPublicKey publicKey) {
        try {
            var keyAgreement = KeyAgreement.getInstance("XDH");
            keyAgreement.init(privateKey);
            keyAgreement.doPhase(publicKey, true);
            byte[] sharedSecret = keyAgreement.generateSecret();
            // RFC 7748 recommends checking that the shared secret is not all zero bytes.
            // Furthermore, RFC 9180 states "For X25519 and X448, public keys and Diffie-Hellman
            // outputs MUST be validated as described in [RFC7748]".
            // Usually we won't get here at all since Java will throw an InvalidKeyException
            // from detecting a key with a low order point. But in case we _do_ get here, fail fast.
            if (SideChannelSafe.allZeros(sharedSecret)) {
                throw new IllegalArgumentException("Computed shared secret is all zeroes");
            }
            return sharedSecret;
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException(e);
        }
    }
@Test
    void x25519_ecdh_fails_if_shared_secret_is_all_zeros_case_2() {
        var alice_priv = xecPrivFromHex("e0f978dfcd3a8f1a5093418de54136a584c20b7b349afdf6c0520886f95b1272");
        var bob_public = xecPubFromHex( "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800");
        // This actually internally fails with an InvalidKeyException due to small point order
        assertThrows(RuntimeException.class, () -> KeyUtils.ecdh(alice_priv, bob_public));
    }