public static HKDF extractedFrom(byte[] salt, byte[] ikm) {
        validateExtractionParams(salt, ikm);
        /*
          RFC-5869, Step 2.2, Extract:

          HKDF-Extract(salt, IKM) -> PRK

          Options:
             Hash     a hash function; HashLen denotes the length of the
                      hash function output in octets

          Inputs:
             salt     optional salt value (a non-secret random value);
                      if not provided, it is set to a string of HashLen zeros.
             IKM      input keying material

          Output:
             PRK      a pseudorandom key (of HashLen octets)

          The output PRK is calculated as follows:

          PRK = HMAC-Hash(salt, IKM)
        */
        var mac = createKeyedHmacSha256(salt); // Note: HKDF is initially keyed on the salt, _not_ on ikm!
        mac.update(ikm);
        return new HKDF(/*PRK = */ mac.doFinal());
    }
@Test
    void missing_salt_to_salted_factory_function_throws_exception() {
        var ikm  = unhex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
        assertThrows(NullPointerException.class, () -> HKDF.extractedFrom(null, ikm));
        assertThrows(IllegalArgumentException.class, () -> HKDF.extractedFrom(new byte[0], ikm));
    }