h*4z2R      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm0.0.0.0 Safe-Inferred"(Ophkdfadd64WhileLt b c is equivalent to #while (b < c) { b += 64 }; return b    Safe-Inferred phkdfA precomputed HMAC key. Computing an HMAC key costs two SHA256 blocks.No additional blocks are incurred for keys that are 64 bytes or less in length. Keys that are longer than 64 bytes long must be first hashed with SHA256 before the key can be derived, incurring extra blocks.It is not uncommon that implementations of PBKDF2, HKDF, etc unnecessarily redo this computation even though a single HMAC key is used repeatedly.TODO: FIXME: this data structure is way larger than it should be. We can pack this into a single 64-byte bytestring, but right now it's 208 bytes of data plus extra overhead.On the other hand, this approach may actually be more efficient for the core PHKDF algorithm as currently implemented. Reducing the size of this data structure while maintaining tight code involves some additional work on cryptohash-sha256phkdfFixed-size context representing the state of a partial HMAC computation with a complete HMAC key and a partial message parameter.     Safe-Inferredphkdf1Precompute an HMAC key for some literal HMAC key.phkdfphkdf"improperly" close out a * as if it were a call to hmac instead of  phkdfStream+, though with a TupleHash message encoding.?phkdf close out a  phkdfStream% context with a given counter and tagEphkdf close out a  phkdfStream context with a call to phkdfSlowExtract!, providing the counter, tag, fnName0, and number of rounds to compute. Note that fnName is truncated to a length of 25-29 bytes long, depending upon the number of rounds specified. Thus the fnName4 is primarily intended to be a protocol constant.FphkdfAdd a tweak to a call to phkdfSlowExtract.Gphkdf%Add zero or more tweaks to a call to phkdfSlowExtract.Hphkdffinalize a call to phkdfSlowExtract<, discarding all but the first block of the output streamIphkdffinalize a call to phkdfSlowExtract *.56879:;<>=?@%EFGHIACBD *56.879:;<>=?@%EFGHIACBD Safe-Inferred"2Jphkdf=A plain-old-data explicit representation of the intermediate a computation after the Y and T have been processed and key stretching has been completed, but before the tweaks have been applied and the final output generated.If you ever need to serialize or persist a seed, you probably want this.Intended to be generated by b. and then consumed without modification by c.PphkdfThese parameters are used to tweak the final output, without redoing any expensive key stretching. A possible use case is including a high entropy secret in the role itself that isn't available until after a successful stage of authentication.Since these parameters are processed in a context that could conceivably be performance sensitive, we don't apply any length padding or side-channel hardening. Instead we opt for maximizing free tagging space. Thus we want to avoid incurring additional SHA256 block computations, one of the favorite techniques employed by the key-stretching phase of a+ to harden against timing side-channels.A deployment could conceivably harden this expansion phase against timing side channels themselves, if the were sufficiently inclined. There are several techniques. For starters, a deployment could specify an additional variable-length string in the role vector, used to control its relative ending position inside the SHA256 buffer.TphkdfThe username and password are grouped together because they are normally expected to be supplied by users or other observers of a deployment.Furthermore, the credentials vector is here because it is an ideal location to include other user input. For example, one could implement a Two-Secret Key Derivation (2SKD) scheme analogous to 1Password's.A deployment can also specify additional constant tags as part of the credentials vector. As the plaintext of these tags is only ever hashed into the output a single time, this is the least expensive pay-as-you-go option for plaintext tagging.The credentials vector is constant time on 0-63 encoded bytes, incurring one additional SHA256 block every 64 bytes thereafter. This includes a variable-length field that encodes the bit length of each string; this field itself requires 2 or more bytes.The username and password are constant time as long as their encoded lengths add up to less than roughly 3 kilobytes, or the username, password, and domain tag add up to less than roughly 8 kilobytes. The actual numbers are somewhat less in both cases, but this is a good approximation.VphkdfThe name of this parameter is suggestive, but this parameter is functionally identical to a second password. The only difference is the fact that a password can be cracked without knowledge of the plaintext username. By contrast, the password acts as a plaintext tag if one provides the username: guessing the username implies plaintext knowledge of the password.YphkdfThese input parameters are grouped together because the envisioned use for them is that they are constants (or near-constants) specified by a deployment. User-supplied inputs would typically not go here.The seguid parameter acts as a deployment-wide salt. Cryptographically speaking, the most important thing a deployment can do is specify a constant seguid. It is highly recommended that the seguid input be a genuine Self-Documenting Globally Unique Identifier attesting to the parameters, purposes, and public playbook of the protocol for y'all to follow.In more concrete cryptographic terms, the seguid parameter is the constant HMAC key used by the protocol right up until the final output exansion. This design is closely modelled on the HKDF construction. As such, adding null bytes onto the ends of seguids that are less than 64 bytes long should be the only source of trivial collisions in the entire protocol.The remaining parameter strings are all directly-documenting plaintext tags. A deployment can use these tags to encode a message into the password hash function so that it must be known to whomever is hashing a password of their choice.Finally, the rounds parameter determines the latency of the function. At least 250,000 rounds are recommended if PHKDF is used as the sole key stretching component of a password hash database.Unfortunately PHKDF is inexpensively parallelized, so large investments here aren't a good expenditure of a user's latency budget. This is why the G3P integrates bcrypt, and cuts the suggested rounds down to 20,000For comparison, n3 rounds of PHKDF is approximately equivalent to (1.5 + dtl)*n + c rounds of PBKDF2, where dtl is related to the domain tag length, and c is a bit larger than 130 or so.Here, dtl is 0 when the domain tag is between 0 and 19 bytes long, 0.5 when the domain tag is between 20 and 83 bytes long, and an additional 0.5 for every 64 bytes thereafter. Thus these functions exhibit extreme timing side channels on the length of the domain tag.By contrast, the long tag is hardened against timing side channels up to a bit less than 5 kilobytes in length. However, an extremely long tag does reduce the headroom provided to masking the length of the username and password fields, however the minimum headroom allocated to the username and password fields is a bit less than 3 kilobytes./As an alternate tagging location, consider the X vector, which can be used as an inexpensive, pay-as-you-go plaintext tagging location.$If the total encoded byte length of ^ is between 0-63 bytes, then these hash protocols operate in a constant number of SHA256 blocks. Every additional 64 bytes incurs the computation of two or three additional SHA256 blocks, because these tags are hashed into the result two times in the case of a$, and three times in the case of ` (and g3pHash).[phkdfHMAC-SHA256 key, usable as a high-repetition indirect tag via self-documenting globally unique identifiers (seguids).\phkdfplaintext tag with one repetition per round. 0-19 bytes are free, 20-83 bytes cost a additional sha256 block per round, with every 64 bytes thereafter incurring a similar cost.]phkdfplaintext tag with 1x repetition, then cycled for roughly 8 kilobytes. Constant time on inputs up to nearly 5 kilobytes.^phkdf"plaintext tag with 2x repetition (a) or 3x repetition (`). Constant-time on 0-63 encoded bytes, which includes the length encoding of each string. Thus 60 of those bytes are usable if the tags vector is a single string, or less if it contains two or more strings._phkdfhow expensive will this hash function be? An optimal implementation computes exactly three SHA256 blocks per round if the domain tag is 19 bytes or less. It is not recommended that phkdf be used as the primary key-stretching component of a deployment, but if it is used this way, we recommend at least 250,000 rounds. This can be adjusted downward in the case of domain tags longer than 19 bytes.`phkdf3A non-tweakable, complete password prehash protocolaphkdfA tweakable, complete prehash protocol. Note that this function is very intentionally implemented in such a way that the following idiom is efficient, and only performs the expensive key stretching phase once:  let mySeed = phkdfPass block args in [ mySeed tweak1, mySeed tweak2, mySeed tweak3 ] However in the case that you want or need to persist or serialize the intermediate seed, then the plain-old-datatype J and its companion functions b and c& are likely to be more appropriate.bphkdfThis generates a seed, which encapsulates the expensive key-stretching component of a into a reusable, tweakable cryptographic value. This function is way slower than it's companion, c. Broadly comparable to HKDF-Extract, though with key stretching built-in.cphkdfThis consumes a seed and tweaks to produce the final output stream. This function is the output expansion phase of a4. This function is way faster than it's companion b&. Broadly comparable to HKDF-Expand.JONMLKPSRQTXWVUY_^]\[Z`abcY_^]\[ZTXWVUPSRQJONMLK`abc      !"#$%%&'()*++,-.//0123456789:;<=>?@ABCDEFGHIJKLMNNOPQRSSTUVVWXYZZ[\]^_`abcdefghijklm#phkdf-0.0.0.0-LG0iCQ0gVPG5QeTKEoFuMCrypto.Encoding.PHKDFCrypto.PHKDF.HMAC.SubtleCrypto.PHKDF.HMACCrypto.PHKDF.Primitives.SubtleCrypto.PHKDF.Primitives.AssertCrypto.PHKDF.Primitives Crypto.PHKDFphkdfcycleByteStringToListcycleByteStringWithNullToListcycleByteStringcycleByteStringWithNullextendTagToList extendTag trimExtTag add64WhileLt add64WhileLt'usernamePaddingpasswordPaddingBytespasswordPaddingcredentialsPaddingHmacKey hmacKey_runHmacCtx hmacCtx_ipad hmacCtx_opad hmacKey_ipad hmacKey_opad $fEqHmacKey $fEqHmacCtx hmacKey_init hmacCtx_inithmacCtx_initFromHmacKeyhmacCtx_updatehmacCtx_updateshmacCtx_finalizePhkdfGenphkdfGen_hmacKeyphkdfGen_extTagphkdfGen_counterphkdfGen_statephkdfGen_initCtx PhkdfSlowCtxphkdfSlowCtx_phkdfCtxphkdfSlowCtx_counterphkdfSlowCtx_tagPhkdfCtxphkdfCtx_byteLenphkdfCtx_statephkdfCtx_hmacKeyphkdfCtx_unsafeFeedphkdfSlowCtx_liftphkdfCtx_assertBufferPosition'"phkdfSlowCtx_assertBufferPosition'phkdfCtx_assertBufferPosition!phkdfSlowCtx_assertBufferPosition phkdfCtx_initphkdfCtx_initFromHmacKeyphkdfCtx_resetphkdfCtx_resetCtxphkdfCtx_addArgphkdfCtx_addArgsphkdfCtx_addArgsByphkdfCtx_finalizephkdfCtx_finalizeHmacCtxphkdfCtx_finalizeHmacphkdfCtx_finalizeStreamphkdfCtx_finalizeGenphkdfGen_initFromHmacKey phkdfGen_peek phkdfGen_readphkdfGen_finalizeStreamphkdfSlowCtx_extractphkdfSlowCtx_addArgphkdfSlowCtx_addArgsphkdfSlowCtx_finalizephkdfSlowCtx_finalizeStream PhkdfSeedphkdfSeed_seguidphkdfSeed_seguidKeyphkdfSeed_domainTagphkdfSeed_secretPhkdfInputTweakphkdfInputTweak_rolephkdfInputTweak_echoTagPhkdfInputArgsphkdfInputArgs_usernamephkdfInputArgs_passwordphkdfInputArgs_credentialsPhkdfInputBlockphkdfInputBlock_seguidphkdfInputBlock_domainTagphkdfInputBlock_longTagphkdfInputBlock_tagsphkdfInputBlock_rounds phkdfSimple phkdfPassphkdfPass_seedInitphkdfPass_seedFinalize $fEqPhkdfSeed$fEqPhkdfInputTweak$fOrdPhkdfInputTweak$fShowPhkdfInputTweak$fEqPhkdfInputArgs$fOrdPhkdfInputArgs$fShowPhkdfInputArgs$fEqPhkdfInputBlock$fOrdPhkdfInputBlock$fShowPhkdfInputBlock