rfc9106xml2.original.xml   rfc9106.xml 
<?xml version="1.0"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY RFC4086 PUBLIC '' 'http://xml2rfc.ietf.org/public/rfc/bibxml/reference.
RFC.4086.xml'>
<!ENTITY RFC4634 PUBLIC '' 'http://xml2rfc.ietf.org/public/rfc/bibxml/reference.
RFC.4634.xml'>
<!ENTITY BLAKE2 PUBLIC '' 'http://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.7693.xml'>
]>
<?rfc compact="no"?> <!DOCTYPE rfc SYSTEM "rfc2629-xhtml.ent">
<?rfc toc="yes"?>
<?rfc symrefs="yes"?>
<rfc category="info" ipr="trust200902" <rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft
docName="draft-irtf-cfrg-argon2-13"> -irtf-cfrg-argon2-13" number="9106" obsoletes="" updates="" submissionType="IRTF
" category="info" consensus="true" xml:lang="en" tocInclude="true" sortRefs="tru
e" symRefs="true" version="3">
<front> <front>
<title abbrev="Argon2"> <title abbrev="Argon2">
The memory-hard Argon2 password hash and proof-of-work function Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applica tions
</title> </title>
<seriesInfo name="RFC" value="9106"/>
<author initials="A." surname="Biryukov" fullname="Alex Biryukov"> <author initials="A." surname="Biryukov" fullname="Alex Biryukov">
<organization>University of Luxembourg</organization> <organization>University of Luxembourg</organization>
<address> <address>
<email>alex.biryukov@uni.lu</email> <email>alex.biryukov@uni.lu</email>
</address> </address>
</author> </author>
<author initials="D." surname="Dinu" fullname="Daniel Dinu"> <author initials="D." surname="Dinu" fullname="Daniel Dinu">
<organization>University of Luxembourg</organization> <organization>University of Luxembourg</organization>
<address> <address>
<email>daniel.dinu@intel.com</email> <email>daniel.dinu@intel.com</email>
</address> </address>
</author> </author>
<author initials="D." surname="Khovratovich" fullname="Dmitry Khovratovich">
<author initials="D." surname="Khovratovich"
fullname="Dmitry Khovratovich">
<organization>ABDK Consulting</organization> <organization>ABDK Consulting</organization>
<address> <address>
<email>khovratovich@gmail.com</email> <email>khovratovich@gmail.com</email>
</address> </address>
</author> </author>
<author initials="S." surname="Josefsson" fullname="Simon Josefsson">
<author initials="S." surname="Josefsson"
fullname="Simon Josefsson">
<organization>SJD AB</organization> <organization>SJD AB</organization>
<address> <address>
<email>simon@josefsson.org</email> <email>simon@josefsson.org</email>
<uri>http://josefsson.org/</uri> <uri>http://josefsson.org/</uri>
</address> </address>
</author> </author>
<date month="September" year="2021"/>
<workgroup>Crypto Forum</workgroup>
<date day="11" month="March" year="2021"/> <keyword>Argon2d</keyword>
<workgroup>CFRG</workgroup> <keyword>Argon2i</keyword>
<keyword>Argon2id</keyword>
<keyword>KDF</keyword>
<keyword>Cryptocurrency</keyword>
<keyword>Time-Space Trade-Off Attacks</keyword>
<keyword>Security</keyword>
<abstract> <abstract>
<t>This document describes the Argon2 memory-hard function for <t>This document describes the Argon2 memory-hard function for
password hashing and proof-of-work applications. We provide an password hashing and proof-of-work applications. We provide an
implementer-oriented description with implementer-oriented description with
test vectors. The purpose is to simplify adoption of Argon2 for test vectors. The purpose is to simplify adoption of Argon2 for
Internet protocols. This document is a product of the Crypto Forum Resear ch Group (CFRG) Internet protocols. This document is a product of the Crypto Forum Resear ch Group (CFRG)
in the IRTF.</t> in the IRTF.</t>
</abstract> </abstract>
</front> </front>
<middle> <middle>
<section anchor="intro" numbered="true" toc="default">
<section anchor="intro" <name>Introduction</name>
title="Introduction"> <t>This document describes the <xref target="ARGON2ESP" format="default">A
rgon2</xref> memory-hard function for
<t>This document describes the <xref
target="ARGON2ESP">Argon2</xref> memory-hard function for
password hashing and proof-of-work applications. We provide an password hashing and proof-of-work applications. We provide an
implementer oriented description with implementer-oriented description with
test vectors. The purpose is to simplify adoption of Argon2 for test vectors. The purpose is to simplify adoption of Argon2 for
Internet protocols. This document corresponds to version 1.3 of the Argon2 hash Internet protocols. This document corresponds to version 1.3 of the Argon2 hash
function.</t> function.</t>
<t>Argon2 is a <xref target="HARD" format="default">memory-hard function</
<t>Argon2 is a traditional xref>. It is a streamlined design.
<xref It aims at the highest memory-filling rate and effective use of
target="HARD">memory-hard function</xref>. It is a streamlined design.
It aims at the highest memory filling rate and effective use of
multiple computing units, while still providing defense against multiple computing units, while still providing defense against
tradeoff attacks. Argon2 is optimized for the x86 architecture trade-off attacks. Argon2 is optimized for the x86 architecture
and exploits the cache and memory organization of the recent and exploits the cache and memory organization of the recent
Intel and AMD processors. Argon2 has one primary variant: Argon2id and tw o supplementary variants: Argon2d and Intel and AMD processors. Argon2 has one primary variant, Argon2id, and t wo supplementary variants, Argon2d and
Argon2i. Argon2d uses data-dependent memory Argon2i. Argon2d uses data-dependent memory
access, which makes it suitable for cryptocurrencies and access, which makes it suitable for cryptocurrencies and
proof-of-work applications with no threats from side-channel proof-of-work applications with no threats from side-channel
timing attacks. Argon2i uses data-independent memory access, timing attacks. Argon2i uses data-independent memory access,
which is preferred for password hashing and password-based key which is preferred for password hashing and password-based key
derivation. Argon2id works as Argon2i for the first half of the first pass over the derivation. Argon2id works as Argon2i for the first half of the first pass over the
memory, and as Argon2d for the rest, thus providing both side-channel attack pro memory and as Argon2d for the rest, thus providing both side-channel attack prot
tection and ection and
brute-force cost savings due to time-memory tradeoffs. Argon2i ma brute-force cost savings due to time-memory trade-offs. Argon2i m
kes more passes over the akes more passes over the
memory to protect from <xref memory to protect from <xref target="AB15" format="default">trade-off atta
target="AB15">tradeoff attacks</xref>.</t> cks</xref>.</t>
<t>Argon2id <bcp14>MUST</bcp14> be supported by any implementation of this
<t> Argon2id MUST be supported by any implementation of this document, whe document, whereas Argon2d and Argon2i <bcp14>MAY</bcp14> be supported.
reas Argon2d and Argon2i MAY be supported. </t>
</t> <t> Argon2 is also a mode of operation over a fixed-input-length compressi
on function G and
<t> Argon2 is also a mode of operation over a fixed-input-length compre
ssion function G and
a variable-input-length hash function H. Even though Argon2 can be pote ntially used with an arbitrary function H, a variable-input-length hash function H. Even though Argon2 can be pote ntially used with an arbitrary function H,
as long as it provides outputs up to 64 bytes, in this document it is < as long as it provides outputs up to 64 bytes, the <xref target="RFC769
xref 3" format="default">BLAKE2b function</xref> is used in this document.</t>
target="BLAKE2">BLAKE2b</xref>.</t> <t>For further background and discussion, see the <xref target="ARGON2" fo
rmat="default">Argon2 paper</xref>.</t>
<t>For further background and discussion, see the <xref
target="ARGON2">Argon2 paper</xref>.</t>
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in <xref
target="RFC2119">RFC 2119</xref>.</t>
<t> This document represents the consensus of the Crypto Forum Research <t> This document represents the consensus of the Crypto Forum Research
Group (CFRG).</t> Group (CFRG).</t>
<section anchor="reqs">
<name>Requirements Language</name>
<t>
The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQU
IRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>
RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to
be interpreted as
described in BCP&nbsp;14 <xref target="RFC2119"/> <xref target="RFC8174"/>
when, and only when, they appear in all capitals, as shown here.
</t>
</section>
</section> </section>
<section numbered="true" toc="default">
<section title="Notation and Conventions"> <name>Notation and Conventions</name>
<dl indent="15">
<t>x^y --- integer x multiplied by itself integer y times</t> <dt>x^y</dt><dd>integer x multiplied by itself integer y times</dd>
<dt>a*b</dt><dd>multiplication of integer a and integer b</dd>
<t>a*b --- multiplication of integer a and integer b</t> <dt>c-d</dt><dd>subtraction of integer d from integer c</dd>
<dt>E_f</dt><dd>variable E with subscript index f</dd>
<t>c-d --- subtraction of integer d from integer c</t> <dt>g / h</dt><dd>integer g divided by integer h. The result is a rational
number.</dd>
<t>E_f --- variable E with subscript index f</t> <dt>I(j)</dt><dd>function I evaluated at j</dd>
<dt>K || L</dt><dd>string K concatenated with string L</dd>
<t>g / h --- integer g divided by integer h. The result is a rational numb <dt>a XOR b</dt><dd>bitwise exclusive-or between bitstrings a and b</dd>
er</t> <dt>a mod b</dt><dd>remainder of integer a modulo integer b, always in ran
ge [0, b-1]</dd>
<t>I(j) --- function I evaluated at j</t> <dt>a &gt;&gt;&gt; n</dt><dd>rotation of 64-bit string a to the right by n
bits</dd>
<t>K || L --- string K concatenated with string L</t> <dt>trunc(a)</dt><dd>the 64-bit value, truncated to the 32 least significa
nt
<t>a XOR b --- bitwise exclusive-or between bitstrings a and b</t> bits</dd>
<dt>floor(a)</dt><dd>the largest integer not bigger than a</dd>
<t>a mod b --- remainder of integer a modulo integer b, always in range [0 <dt>ceil(a)</dt><dd>the smallest integer not smaller than a</dd>
, b-1]</t> <dt>extract(a, i)</dt><dd>the i-th set of 32 bits from bitstring a, starti
ng from 0-th</dd>
<t>a >>> n --- rotation of 64-bit string a to the right by n bits</t> <dt>|A|</dt><dd>the number of elements in set A</dd>
<dt>LE32(a)</dt><dd>32-bit integer a converted to a byte string in little
<t>trunc(a) --- the 64-bit value, truncated to the 32 least significant endian (for example, 123456 (decimal) is 40 E2 01 00)</dd>
bits</t> <dt>LE64(a)</dt><dd>64-bit integer a converted to a byte string in little
endian (for example, 123456 (decimal) is 40 E2 01 00 00 00 00 00)</dd>
<t>floor(a) --- the largest integer not bigger than a</t> <dt>int32(s)</dt><dd>32-bit string s is converted to a non-negative intege
r in little endian</dd>
<t>ceil(a) --- the smallest integer not smaller than a</t> <dt>int64(s)</dt><dd>64-bit string s is converted to a non-negative intege
r in little endian</dd>
<t>extract(a, i) --- the i-th set of 32-bits from bitstring a, starting fr <dt>length(P)</dt><dd>the byte length of string P expressed as 32-bit inte
om 0-th</t> ger</dd>
<dt>ZERO(P)</dt><dd>the P-byte zero string</dd>
<t>|A| --- the number of elements in set A</t> </dl>
<t>LE32(a) --- 32-bit integer a converted to a bytestring in little end
ian. Example: 123456 (decimal) is 40 E2 01 00.</t>
<t>LE64(a) --- 64-bit integer a converted to a bytestring in little end
ian. Example: 123456 (decimal) is 40 E2 01 00 00 00 00 00.</t>
<t>int32(s) --- 32-bit string s is converted to non-negative integer in
little endian.</t>
<t>int64(s) --- 64-bit string s is converted to non-negative integer in
little endian.</t>
<t>length(P) --- the bytelength of string P expressed as 32-bit integer
</t>
<t>ZERO(P) --- the P-byte zero string</t>
</section> </section>
<section anchor="argon2-algorithm" numbered="true" toc="default">
<name>Argon2 Algorithm</name>
<section anchor="argon2-inouts" numbered="true" toc="default">
<name>Argon2 Inputs and Outputs</name>
<t>Argon2 has the following input parameters:
<section anchor="argon2-algorithm" </t>
title="Argon2 Algorithm"> <ul spacing="normal">
<li>Message string P, which is a password for password hashing
<section anchor="argon2-inouts" applications. It <bcp14>MUST</bcp14> have a length not greater than 2^(
title="Argon2 Inputs and Outputs"> 32)-1 bytes.</li>
<li>Nonce S, which is a salt for password hashing applications. It <bc
<t>Argon2 has the following input parameters: p14>MUST</bcp14> have a length not greater than 2^(32)-1 bytes. 16 bytes is <bc
p14>RECOMMENDED</bcp14> for
<list style="symbols"> password hashing. The salt <bcp14>SHOULD</bcp14> be unique for each pa
ssword.</li>
<t>Message string P, which is a password for password hashing <li>Degree of parallelism p determines how many independent
applications. MUST have length not greater than 2^(32) - 1 bytes.</t>
<t>Nonce S, which is a salt for password hashing applications.
MUST have length not greater than 2^(32)-1 bytes. 16 bytes is RECOMME
NDED for
password hashing. Salt SHOULD be unique for each password.</t>
<t>Degree of parallelism p determines how many independent
(but synchronizing) computational chains (lanes) can be (but synchronizing) computational chains (lanes) can be
run. It MUST be an integer value from 1 to 2^(24)-1.</t> run. It <bcp14>MUST</bcp14> be an integer value from 1 to 2^(24)-1.</li
>
<t>Tag length T MUST be an integer number of bytes from 4 to <li>Tag length T <bcp14>MUST</bcp14> be an integer number of bytes fro
2^(32)-1.</t> m 4 to
2^(32)-1.</li>
<t>Memory size m MUST be an integer number of kibibytes from <li>Memory size m <bcp14>MUST</bcp14> be an integer number of kibibyte
s from
8*p to 2^(32)-1. The actual number of blocks is m', which is 8*p to 2^(32)-1. The actual number of blocks is m', which is
m rounded down to the nearest multiple of 4*p.</t> m rounded down to the nearest multiple of 4*p.</li>
<li>Number of passes t (used to tune the running time
<t>Number of passes t (used to tune the running time independently of the memory size) <bcp14>MUST</bcp14> be an integer num
independently of the memory size) MUST be an integer number ber
from 1 to 2^(32)-1.</t> from 1 to 2^(32)-1.</li>
<li>Version number v <bcp14>MUST</bcp14> be one byte 0x13.</li>
<t>Version number v MUST be one byte 0x13.</t> <li>Secret value K is <bcp14>OPTIONAL</bcp14>. If used, it <bcp14>MUST
</bcp14> have a length not greater than
<t>Secret value K is OPTIONAL. If used, it MUST have length not great 2^(32)-1 bytes.</li>
er than <li>Associated data X is <bcp14>OPTIONAL</bcp14>. If used, it <bcp14>M
2^(32)-1 bytes.</t> UST</bcp14> have a length not greater than 2^(32)-1
bytes.</li>
<t>Associated data X is OPTIONAL. If used, it MUST have length not gre <li>Type y <bcp14>MUST</bcp14> be 0 for Argon2d, 1 for Argon2i, or 2 f
ater than 2^(32)-1 or Argon2id.</li>
bytes.</t> </ul>
<t>Type y of Argon2: MUST be 0 for Argon2d, 1 for Argon2i, 2 for Argon2
id.</t>
</list></t>
<t>The Argon2 output, or "tag" is a string T bytes long.</t>
<t>The Argon2 output, or "tag", is a string T bytes long.</t>
</section> </section>
<section anchor="argon2-operation" numbered="true" toc="default">
<section anchor="argon2-operation" <name>Argon2 Operation</name>
title="Argon2 Operation"> <t>Argon2 uses an internal compression function G with two
1024-byte inputs, a 1024-byte output, and an internal hash
<t>Argon2 uses an internal compression function G with two function H^x(), with x being its output length in bytes. Here, H^x() app
1024-byte inputs and a 1024-byte output, and an internal hash lied to string A is the BLAKE2b (<xref target="RFC7693" section="3.3" sectionFor
function H^x() with x being its output length in bytes. Here H^x() appli mat="comma"/>) function, which takes (d,ll,kk=0,nn=x) as parameters,
ed to string A is the <xref
target="BLAKE2">BLAKE2b (Section 3.3)</xref> function, which takes (d,ll,
kk=0,nn=x) as parameters
where d is A padded to a multiple of 128 bytes where d is A padded to a multiple of 128 bytes
and ll is the length of d in bytes. The compression function G is based o n its internal and ll is the length of d in bytes. The compression function G is based o n its internal
permutation. A variable-length hash function H' built upon H permutation. A variable-length hash function H' built upon H
is also used. G is described in <xref target="G-function"></xref> and H is also used. G is described in <xref target="G-function" format="defau
' is described in lt"/>, and H' is described in
<xref target="H-function"></xref>.</t> <xref target="H-function" format="default"/>.</t>
<t>The Argon2 operation is as follows.
<t>The Argon2 operation is as follows.
<list style="numbers">
<t>Establish H_0 as the 64-byte value as shown
below. If K, X, or S has zero length it is just absent but its lengt
h field remains.
<figure title="H_0 generation"> </t>
<artwork> <ol spacing="normal" type="1"><li>
H_0 = H^(64)(LE32(p) || LE32(T) || LE32(m) || LE32(t) || <t>Establish H_0 as the 64-byte value as shown
LE32(v) || LE32(y) || LE32(length(P)) || P || below. If K, X, or S has zero length, it is just absent, but its leng
LE32(length(S)) || S || LE32(length(K)) || K || th field remains.
LE32(length(X)) || X)
</artwork>
</figure></t>
<t>Allocate the memory as m' 1024-byte blocks where m' is </t>
<figure>
<name>H_0 Generation</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
H_0 = H^(64)(LE32(p) || LE32(T) || LE32(m) || LE32(t) ||
LE32(v) || LE32(y) || LE32(length(P)) || P ||
LE32(length(S)) || S || LE32(length(K)) || K ||
LE32(length(X)) || X)
]]></artwork>
</figure>
</li>
<li>
<t>Allocate the memory as m' 1024-byte blocks, where m' is
derived as: derived as:
<figure title="Memory allocation"> </t>
<artwork> <figure>
m' = 4 * p * floor (m / 4p) <name>Memory Allocation</name>
</artwork> <artwork name="" type="" align="left" alt=""><![CDATA[
</figure> m' = 4 * p * floor (m / 4p)
]]></artwork>
</figure>
<t>
For p lanes, the memory is For p lanes, the memory is
organized in a matrix B[i][j] of blocks with p rows (lanes) organized in a matrix B[i][j] of blocks with p rows (lanes)
and q = m' / p columns.</t> and q = m' / p columns.</t>
</li>
<t>Compute B[i][0] for all i ranging from (and including) 0 <li>
<t>Compute B[i][0] for all i ranging from (and including) 0
to (not including) p. to (not including) p.
<figure title="Lane starting blocks"> </t>
<artwork> <figure>
B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i)) <name>Lane Starting Blocks</name>
</artwork> <artwork name="" type="" align="left" alt=""><![CDATA[
</figure> B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i))
]]></artwork>
</t> </figure>
</li>
<t>Compute B[i][1] for all i ranging from (and including) 0 <li>
<t>Compute B[i][1] for all i ranging from (and including) 0
to (not including) p. to (not including) p.
<figure title ="Second lane blocks"> </t>
<artwork> <figure>
B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i)) <name>Second Lane Blocks</name>
</artwork> <artwork name="" type="" align="left" alt=""><![CDATA[
</figure> B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i))
]]></artwork>
</t> </figure>
</li>
<li>
<t>Compute B[i][j] for all i ranging from (and including) 0 <t anchor="step5">Compute B[i][j] for all i ranging from (and includ
to (not including) p, and for all j ranging from (and ing) 0
including) 2) to (not including) q. The computation MUST proceed slice to (not including) p and for all j ranging from (and
wise (<xref target="indexing"></xref>): first blocks from slice 0 are computed including) 2 to (not including) q. The computation <bcp14>MUST</bcp14>
for all lanes (in an arbitrary order of lanes), then blocks from slice 1 are proceed slicewise (<xref target="indexing" format="default"/>): first, blocks
computed etc. The block indices l from slice 0 are computed
for all lanes (in an arbitrary order of lanes), then blocks from slice 1 are
computed, etc. The block indices l
and z are determined for each i, j differently for Argon2d, Argon2i, an d Argon2id. and z are determined for each i, j differently for Argon2d, Argon2i, an d Argon2id.
<figure title="Further block generation"> </t>
<artwork> <figure>
B[i][j] = G(B[i][j-1], B[l][z]) <name>Further Block Generation</name>
</artwork> <artwork name="" type="" align="left" alt=""><![CDATA[
</figure></t> B[i][j] = G(B[i][j-1], B[l][z])
]]></artwork>
<t>If the number of passes t is larger than 1, we repeat </figure>
the steps. However blocks are computed differently as the old value is </li>
XORed with the new one: <li>
<figure title="Further passes"> <t>If the number of passes t is larger than 1, we repeat
<artwork> <xref target="step5" format="none">step 5</xref>. We compute B[i][0] an
B[i][0] = G(B[i][q-1], B[l][z]) XOR B[i][0]; d B[i][j] for all i raging from (and including) 0 to (not including) p and for a
B[i][j] = G(B[i][j-1], B[l][z]) XOR B[i][j]. ll j ranging from
</artwork> (and including) 1 to (not including) q. However, blocks are computed differen
</figure></t> tly as the old value is XORed with the new one:
</t>
<t>After t steps have been iterated, the final block C is computed as <figure>
<name>Further Passes</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
B[i][0] = G(B[i][q-1], B[l][z]) XOR B[i][0];
B[i][j] = G(B[i][j-1], B[l][z]) XOR B[i][j].
]]></artwork>
</figure>
</li>
<li>
<t>After t steps have been iterated, the final block C is computed a
s
the XOR of the last column: the XOR of the last column:
<figure title="Final block"> </t>
<artwork> <figure>
C = B[0][q-1] XOR B[1][q-1] XOR ... XOR B[p-1][q-1] <name>Final Block</name>
</artwork> <artwork name="" type="" align="left" alt=""><![CDATA[
</figure></t> C = B[0][q-1] XOR B[1][q-1] XOR ... XOR B[p-1][q-1]
]]></artwork>
<t>The output tag is computed as H'^T(C).</t> </figure>
</li>
</list></t> <li>The output tag is computed as H'^T(C).</li>
</ol>
</section> </section>
<section anchor="H-function" numbered="true" toc="default">
<section anchor="H-function" title="Variable-length hash function H'"> <name>Variable-Length Hash Function H'</name>
<t>Let V_i be a 64-byte block and W_i be its first 32 bytes. Then we de
<t>Let V_i be a 64-byte block, and W_i be its first 32 bytes. Then we de fine function H' as follows:
fine: </t>
<figure>
<figure title="Function H' for tag and initial block computations"> <name>Function H' for Tag and Initial Block Computations</name>
<artwork> <sourcecode type="pseudocode">
if T &lt;= 64 if T &lt;= 64
H'^T(A) = H^T(LE32(T)||A) H'^T(A) = H^T(LE32(T)||A)
else else
r = ceil(T/32)-2 r = ceil(T/32)-2
V_1 = H^(64)(LE32(T)||A) V_1 = H^(64)(LE32(T)||A)
V_2 = H^(64)(V_1) V_2 = H^(64)(V_1)
... ...
V_r = H^(64)(V_{r-1}) V_r = H^(64)(V_{r-1})
V_{r+1} = H^(T-32*r)(V_{r}) V_{r+1} = H^(T-32*r)(V_{r})
H'^T(X) = W_1 || W_2 || ... || W_r || V_{r+1} H'^T(X) = W_1 || W_2 || ... || W_r || V_{r+1}
</artwork> </sourcecode>
</figure> </figure>
</t>
</section> </section>
<section anchor="indexing" numbered="true" toc="default">
<section anchor="indexing" title="Indexing"> <name>Indexing</name>
<t>To enable parallel block computation, we further partition the
<t>To enable parallel block computation, we further partition the
memory matrix into SL = 4 vertical slices. The intersection of a memory matrix into SL = 4 vertical slices. The intersection of a
slice and a lane is called a segment, which has length q/SL. Segments of t he slice and a lane is called a segment, which has a length of q/SL. Segments of the
same slice can be computed in parallel and do not reference blocks same slice can be computed in parallel and do not reference blocks
from each other. All other blocks can be referenced.</t> from each other. All other blocks can be referenced.</t>
<figure>
<figure title="Single-pass Argon2 with p lanes and 4 slices"> <name>Single-Pass Argon2 with p Lanes and 4 Slices</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
<artwork> slice 0 slice 1 slice 2 slice 3
slice 0 slice 1 slice 2 slice 3 ___/\___ ___/\___ ___/\___ ___/\___
___/\___ ___/\___ ___/\___ ___/\___ / \ / \ / \ / \
/ \ / \ / \ / \ +----------+----------+----------+----------+
+----------+----------+----------+----------+ | | | | | > lane 0
| | | | | > lane 0 +----------+----------+----------+----------+
+----------+----------+----------+----------+ | | | | | > lane 1
| | | | | > lane 1 +----------+----------+----------+----------+
+----------+----------+----------+----------+ | | | | | > lane 2
| | | | | > lane 2 +----------+----------+----------+----------+
+----------+----------+----------+----------+ | ... ... ... | ...
| ... ... ... | ... +----------+----------+----------+----------+
+----------+----------+----------+----------+ | | | | | > lane p - 1
| | | | | > lane p - 1 +----------+----------+----------+----------+
+----------+----------+----------+----------+ ]]></artwork>
</artwork> </figure>
</figure> <section numbered="true" toc="default">
<name>Computing the 32-Bit Values J_1 and J_2</name>
<section title="Computing the 32-bit values J_1 and J_2"> <section numbered="true" toc="default">
<section title="Argon2d"> <name>Argon2d</name>
<t>J_1 is given by the first 32 bits of block B[i][j-1], <t>J_1 is given by the first 32 bits of block B[i][j-1],
while J_2 is given by the next 32-bits of block B[i][j-1]: while J_2 is given by the next 32 bits of block B[i][j-1]:
<figure title ="Deriving J1,J2 in Argon2d"> </t>
<artwork> <figure>
J_1 = int32(extract(B[i][j-1], 0)) <name>Deriving J1,J2 in Argon2d</name>
J_2 = int32(extract(B[i][j-1], 1)) <artwork name="" type="" align="left" alt=""><![CDATA[
</artwork> J_1 = int32(extract(B[i][j-1], 0))
</figure></t> J_2 = int32(extract(B[i][j-1], 1))
]]></artwork>
</figure>
</section> </section>
<section numbered="true" toc="default">
<name>Argon2i</name>
<t>For each segment, we do the following. First, we compute the valu
e Z as:
<section title="Argon2i"> </t>
<t>For each segment we do the following. First we compute the va <figure>
lue Z as <name>Input to Compute J1,J2 in Argon2i</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
<figure title="Input to compute J1,J2 in Argon2i"> Z= ( LE64(r) || LE64(l) || LE64(sl) || LE64(m') ||
<artwork> LE64(t) || LE64(y) )
Z= ( LE64(r) || LE64(l) || LE64(sl) || LE64(m') || ]]></artwork>
LE64(t) || LE64(y) ), where </figure>
<t>where</t>
r -- the pass number <dl indent="5" spacing="compact">
l -- the lane number <dt>r:</dt><dd>the pass number</dd>
sl -- the slice number <dt>l:</dt><dd>the lane number</dd>
m' -- the total number of memory blocks <dt>sl:</dt><dd>the slice number</dd>
t -- the total number of passes <dt>m':</dt><dd>the total number of memory blocks</dd>
y -- the Argon2 type (0 for Argon2d, <dt>t:</dt><dd>the total number of passes</dd>
1 for Argon2i, 2 for Argon2id) <dt>y:</dt><dd>the Argon2 type (0 for Argon2d,
</artwork> 1 for Argon2i, 2 for Argon2id)</dd>
</figure> </dl>
Then we compute q/(128*SL) 1024-byte values G(ZERO(1024),G(ZERO(1024), Z || LE6 <t>
4(1) || ZERO(968) )), Then we compute:</t>
G(ZERO(1024),G(ZERO(1024), Z || LE64(2) || ZERO(968) )),... ,
G(ZERO(1024),G(ZERO(1024), Z || LE64(q/(128*SL)) || ZERO(968) )), which are part
itioned into q/(SL) 8-byte values X, which are viewed as X1||X2
and converted to J_1=int32(X1) and J_2=int32(X2).
The values r, l, sl, m', t, y, i are represented as 8 bytes in
little-endian.</t>
<artwork name="" type="" align="left" alt=""><![CDATA[
q/(128*SL) 1024-byte values
G(ZERO(1024),G(ZERO(1024),
Z || LE64(1) || ZERO(968) )),
G(ZERO(1024),G(ZERO(1024),
Z || LE64(2) || ZERO(968) )),... ,
G(ZERO(1024),G(ZERO(1024),
Z || LE64(q/(128*SL)) || ZERO(968) )),
]]></artwork><t>
which are partitioned into q/(SL) 8-byte values X, which are viewed as X1||X2 a
nd converted to J_1=int32(X1) and J_2=int32(X2).</t>
<t>
The values r, l, sl, m', t, y, and i are represented as 8 bytes in
little endian.</t>
</section> </section>
<section title="Argon2id"> <section numbered="true" toc="default">
<name>Argon2id</name>
<t>If the pass number is 0 and the slice number is 0 or 1, then comp ute J_1 and J_2 as <t>If the pass number is 0 and the slice number is 0 or 1, then comp ute J_1 and J_2 as
for Argon2i, else compute J_1 and J_2 as for Argon2d.</t> for Argon2i, else compute J_1 and J_2 as for Argon2d.</t>
</section> </section>
</section> </section>
<section numbered="true" toc="default">
<section title="Mapping J_1 and J_2 to reference block index [l][z]"> <name>Mapping J_1 and J_2 to Reference Block Index [l][z]</name>
<t>The value of l = J_2 mod p gives the index of the lane from <t>The value of l = J_2 mod p gives the index of the lane from
which the block will be taken. For the first pass (r=0) and which the block will be taken. For the first pass (r=0) and
the first slice (sl=0) the block is taken from the current lane.</t> the first slice (sl=0), the block is taken from the current lane.</t
>
<t>The set W contains the indices that are referenced <t>The set W contains the indices that are referenced
according to the following rules: according to the following rules:
<list style="numbers"> </t>
<t>If l is the current lane, then W includes the indices of <ol spacing="normal" type="1"><li>If l is the current lane, then W inc
ludes the indices of
all blocks in the last SL - 1 = 3 segments computed and finished , as well as all blocks in the last SL - 1 = 3 segments computed and finished , as well as
the blocks computed in the current segment in the current pass the blocks computed in the current segment in the current pass
excluding B[i][j-1].</t> excluding B[i][j-1].</li>
<t>If l is not the current lane, then W includes the indices of <li>If l is not the current lane, then W includes the indices of
all blocks in the last SL - 1 = 3 segments computed and finished all blocks in the last SL - 1 = 3 segments computed and finished
in lane l. If B[i][j] is the first block of a segment, then the in lane l. If B[i][j] is the first block of a segment, then the
very last index from W is excluded.</t> very last index from W is excluded.</li>
</list> </ol>
</t> <t>Then take a block from W with a nonuniform
distribution over [0, |W|) using the following mapping:
<t>Then take a block from W with a non-uniform
distribution over [0, |W|) using the mapping
<figure title="Computing J1">
<artwork>
J_1 -> |W|(1 - J_1^2 / 2^(64))
</artwork>
</figure></t>
<t>To avoid floating point computation, the following approximation </t>
<figure>
<name>Computing J1</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
J_1 -> |W|(1 - J_1^2 / 2^(64))
]]></artwork>
</figure>
<t>To avoid floating point computation, the following approximation
is used: is used:
<figure title="Computing J1, part 2"> </t>
<artwork> <figure>
x = J_1^2 / 2^(32) <name>Computing J1, Part 2</name>
y = (|W| * x) / 2^(32) <artwork name="" type="" align="left" alt=""><![CDATA[
zz = |W| - 1 - y x = J_1^2 / 2^(32)
</artwork> y = (|W| * x) / 2^(32)
</figure></t> zz = |W| - 1 - y
]]></artwork>
<t>Then take the zz-th index from W, it will be the z value for the </figure>
reference block index [l][z].</t> <t>Then take the zz-th index from W; it will be the z value for the re
ference block index [l][z].</t>
</section> </section>
</section> </section>
<section anchor="G-function" numbered="true" toc="default">
<section anchor="G-function" title="Compression function G"> <name>Compression Function G</name>
<t>The compression function G is built upon the BLAKE2b-based transform
<t>The compression function G is built upon the BLAKE2b-based transforma ation P.
tion P.
P operates on the 128-byte input, which can be P operates on the 128-byte input, which can be
viewed as 8 16-byte registers: viewed as eight 16-byte registers:
<figure title="Blake round function P">
<artwork>
P(A_0, A_1, ... ,A_7) = (B_0, B_1, ... ,B_7)
</artwork>
</figure></t>
<t>The compression function G(X, Y) operates on two 1024-byte </t>
<figure>
<name>Blake Round Function P</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
P(A_0, A_1, ... ,A_7) = (B_0, B_1, ... ,B_7)
]]></artwork>
</figure>
<t>The compression function G(X, Y) operates on two 1024-byte
blocks X and Y. It first computes R = X XOR Y. Then R is blocks X and Y. It first computes R = X XOR Y. Then R is
viewed as a 8x8 matrix of 16-byte registers R_0, R_1, ... , viewed as an 8x8 matrix of 16-byte registers R_0, R_1, ... ,
R_63. Then P is first applied to each row, and then to each column to R_63. Then P is first applied to each row, and then to each column to
get Z: get Z:
<figure title="Core of compression function G"> </t>
<artwork> <figure>
( Q_0, Q_1, Q_2, ... , Q_7) &lt;- P( R_0, R_1, R_2, ... , R_7) <name>Core of Compression Function G</name>
( Q_8, Q_9, Q_10, ... , Q_15) &lt;- P( R_8, R_9, R_10, ... , R_15) <artwork name="" type="" align="left" alt=""><![CDATA[
( Q_0, Q_1, Q_2, ... , Q_7) <- P( R_0, R_1, R_2, ... , R_7)
( Q_8, Q_9, Q_10, ... , Q_15) <- P( R_8, R_9, R_10, ... , R_15)
... ...
(Q_56, Q_57, Q_58, ... , Q_63) &lt;- P(R_56, R_57, R_58, ... , R_63) (Q_56, Q_57, Q_58, ... , Q_63) <- P(R_56, R_57, R_58, ... , R_63)
( Z_0, Z_8, Z_16, ... , Z_56) &lt;- P( Q_0, Q_8, Q_16, ... , Q_56) ( Z_0, Z_8, Z_16, ... , Z_56) <- P( Q_0, Q_8, Q_16, ... , Q_56)
( Z_1, Z_9, Z_17, ... , Z_57) &lt;- P( Q_1, Q_9, Q_17, ... , Q_57) ( Z_1, Z_9, Z_17, ... , Z_57) <- P( Q_1, Q_9, Q_17, ... , Q_57)
... ...
( Z_7, Z_15, Z 23, ... , Z_63) &lt;- P( Q_7, Q_15, Q_23, ... , Q_63) ( Z_7, Z_15, Z 23, ... , Z_63) <- P( Q_7, Q_15, Q_23, ... , Q_63)
</artwork> ]]></artwork>
</figure></t> </figure>
<t>Finally, G outputs Z XOR R:
<t>Finally, G outputs Z XOR R:
<figure>
<artwork>
G: (X, Y) -> R -> Q -> Z -> Z XOR R
</artwork>
</figure>
<figure title="Argon2 compression function G."> </t>
<artwork> <artwork name="" type="" align="left" alt=""><![CDATA[
G: (X, Y) -> R -> Q -> Z -> Z XOR R
]]></artwork>
<figure>
<name>Argon2 Compression Function G</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
+---+ +---+ +---+ +---+
| X | | Y | | X | | Y |
+---+ +---+ +---+ +---+
| | | |
---->XOR&lt;---- ---->XOR<----
--------| --------|
| \ / | \ /
| +---+ | +---+
| | R | | | R |
| +---+ | +---+
| | | |
| \ / | \ /
| P rowwise | P rowwise
| | | |
| \ / | \ /
skipping to change at line 527 skipping to change at line 494
| | | |
| \ / | \ /
| +---+ | +---+
| | Z | | | Z |
| +---+ | +---+
| | | |
| \ / | \ /
------>XOR ------>XOR
| |
\ / \ /
</artwork> ]]></artwork>
</figure></t> </figure>
</section> </section>
<section anchor="P-permutation" numbered="true" toc="default">
<section anchor="P-permutation" title="Permutation P"> <name>Permutation P</name>
<t>Permutation P is based on the round function of BLAKE2b. The eight
<t>Permutation P is based on the round function of BLAKE2b. The 8
16-byte inputs S_0, S_1, ... , S_7 are viewed as a 4x4 matrix of 16-byte inputs S_0, S_1, ... , S_7 are viewed as a 4x4 matrix of
64-bit words, where S_i = (v_{2*i+1} || v_{2*i}): 64-bit words, where S_i = (v_{2*i+1} || v_{2*i}):
<figure title="Matrix element labeling"> </t>
<artwork> <figure>
<name>Matrix Element Labeling</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
v_0 v_1 v_2 v_3 v_0 v_1 v_2 v_3
v_4 v_5 v_6 v_7 v_4 v_5 v_6 v_7
v_8 v_9 v_10 v_11 v_8 v_9 v_10 v_11
v_12 v_13 v_14 v_15 v_12 v_13 v_14 v_15
</artwork> ]]></artwork>
</figure> </figure>
<t>
It works as follows: It works as follows:
<figure title="Feeding matrix elements to GB"> </t>
<artwork> <figure>
<name>Feeding Matrix Elements to GB</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
GB(v_0, v_4, v_8, v_12) GB(v_0, v_4, v_8, v_12)
GB(v_1, v_5, v_9, v_13) GB(v_1, v_5, v_9, v_13)
GB(v_2, v_6, v_10, v_14) GB(v_2, v_6, v_10, v_14)
GB(v_3, v_7, v_11, v_15) GB(v_3, v_7, v_11, v_15)
GB(v_0, v_5, v_10, v_15) GB(v_0, v_5, v_10, v_15)
GB(v_1, v_6, v_11, v_12) GB(v_1, v_6, v_11, v_12)
GB(v_2, v_7, v_8, v_13) GB(v_2, v_7, v_8, v_13)
GB(v_3, v_4, v_9, v_14) GB(v_3, v_4, v_9, v_14)
</artwork> ]]></artwork>
</figure> </figure>
<t>
GB(a, b, c, d) is defined as follows: GB(a, b, c, d) is defined as follows:
<figure title="Details of GB"> </t>
<artwork> <figure>
<name>Details of GB</name>
<artwork name="" type="" align="left" alt=""><![CDATA[
a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64) a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64)
d = (d XOR a) >>> 32 d = (d XOR a) >>> 32
c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64) c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64)
b = (b XOR c) >>> 24 b = (b XOR c) >>> 24
a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64) a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64)
d = (d XOR a) >>> 16 d = (d XOR a) >>> 16
c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64) c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64)
b = (b XOR c) >>> 63 b = (b XOR c) >>> 63
</artwork> ]]></artwork>
</figure> </figure>
<t>
The modular additions in GB are combined with 64-bit multiplications. The modular additions in GB are combined with 64-bit multiplications.
Multiplications are the only difference to the original BLAKE2b design. Multiplications are the only difference from the original BLAKE2b design .
This choice is done to increase the circuit depth and thus the running This choice is done to increase the circuit depth and thus the running
time of ASIC implementations, while having roughly the same running time of ASIC implementations, while having roughly the same running
time on CPUs thanks to parallelism and pipelining. time on CPUs thanks to parallelism and pipelining.
</t> </t>
</section> </section>
</section> </section>
<section anchor="parameter-choice" numbered="true" toc="default">
<section anchor="parameter-choice" <name>Parameter Choice</name>
title="Parameter Choice">
<t>Argon2d is optimized for settings where the adversary does <t>Argon2d is optimized for settings where the adversary does
not get regular access to system memory or CPU, i.e. he can not not get regular access to system memory or CPU, i.e., they cannot
run side-channel attacks based on the timing information, nor he run side-channel attacks based on the timing information, nor can they
can recover the password much faster using garbage recover the password much faster using garbage
collection. These settings are more typical for backend servers collection. These settings are more typical for backend servers
and cryptocurrency minings. For practice we suggest the and cryptocurrency minings. For practice, we suggest the
following settings: following settings:
<list style="symbols"> </t>
<ul spacing="normal">
<t>Cryptocurrency mining, that takes 0.1 seconds on a 2 Ghz <li>Cryptocurrency mining, which takes 0.1 seconds on a 2 GHz
CPU using 1 core — Argon2d with 2 lanes and 250 MB of RAM.</t> CPU using 1 core -- Argon2d with 2 lanes and 250 MB of RAM.</li>
</ul>
</list></t>
<t>Argon2id is optimized for more realistic settings, where the <t>Argon2id is optimized for more realistic settings, where the
adversary possibly can access the same machine, use its CPU or adversary can possibly access the same machine, use its CPU, or
mount cold-boot attacks. We suggest the following mount cold-boot attacks. We suggest the following
settings: settings:
<list style="symbols"> </t>
<t>Backend server authentication, that takes 0.5 seconds on a <ul spacing="normal">
2 GHz CPU using 4 cores — Argon2id with 8 lanes and 4 GiB of <li>Backend server authentication, which takes 0.5 seconds on a
RAM.</t> 2 GHz CPU using 4 cores -- Argon2id with 8 lanes and 4 GiB of
RAM.</li>
<t>Key derivation for hard-drive encryption, that takes 3 <li>Key derivation for hard-drive encryption, which takes 3
seconds on a 2 GHz CPU using 2 cores - Argon2id with 4 lanes seconds on a 2 GHz CPU using 2 cores -- Argon2id with 4 lanes
and 6 GiB of RAM.</t> and 6 GiB of RAM.</li>
<li>Frontend server authentication, which takes 0.5 seconds on a
<t>Frontend server authentication, that takes 0.5 seconds on a 2 GHz CPU using 2 cores -- Argon2id with 4 lanes and 1 GiB of
2 GHz CPU using 2 cores - Argon2id with 4 lanes and 1 GiB of RAM.</li>
RAM.</t> </ul>
</list></t>
<t>We recommend the following procedure to select the type and <t>We recommend the following procedure to select the type and
the parameters for practical use of Argon2. the parameters for practical use of Argon2.
<list style="numbers"> </t>
<t> If you are OK with a uniformly safe option, but not tailored to your appli
cation or hardware,
select Argon2id with t=1 iteration, p=4 lanes and m=2^(21) (2 GiB of RAM), 128
-bit salt, 256-bit tag size.
This is the FIRST RECOMMENDED option.</t>
<t> If much less memory is available, a uniformly safe option is Argon2id wit
h t=3 iterations, p=4 lanes and m=2^(16)
(64 MiB of RAM), 128-bit salt, 256-bit tag size.
This is the SECOND RECOMMENDED option.</t>
<t>Otherwise, start with selecting the type y. If you do not know the dif
ference
between them or you consider side-channel attacks as viable
threat, choose Argon2id.</t>
<t>Select p=4 lanes.</t>
<t>Figure out the maximum amount of memory that each call
can afford and translate it to the parameter m.</t>
<t>Figure out the maximum amount of time (in seconds) that
each call can afford.</t>
<t>Select the salt length. 128 bits is sufficient for all <ol spacing="normal" type="1"><li> If a uniformly safe option that is not
applications, but can be reduced to 64 bits in the case of tailored to your application or hardware is acceptable,
space constraints.</t> select Argon2id with t=1 iteration, p=4 lanes, m=2^(21) (2 GiB of RAM), 128-bi
t salt, and 256-bit tag size.
This is the FIRST <bcp14>RECOMMENDED</bcp14> option.</li>
<li> If much less memory is available, a uniformly safe option is Argon2
id with t=3 iterations, p=4 lanes, m=2^(16)
(64 MiB of RAM), 128-bit salt, and 256-bit tag size.
This is the SECOND <bcp14>RECOMMENDED</bcp14> option.</li>
<t>Select the tag length. 128 bits is sufficient for most <li>Otherwise, start with selecting the type y. If you do not know the d
ifference
between the types or you consider side-channel attacks to be a viable
threat, choose Argon2id.</li>
<li>Select p=4 lanes.</li>
<li>Figure out the maximum amount of memory that each call
can afford and translate it to the parameter m.</li>
<li>Figure out the maximum amount of time (in seconds) that
each call can afford.</li>
<li>Select the salt length. A length of 128 bits is sufficient for all
applications but can be reduced to 64 bits in the case of
space constraints.</li>
<li>Select the tag length. A length of 128 bits is sufficient for most
applications, including key derivation. If longer keys are applications, including key derivation. If longer keys are
needed, select longer tags.</t> needed, select longer tags.</li>
<li>If side-channel attacks are a viable threat or if you're uncertain,
<t>If side-channel attacks are a viable threat, or if you're uncertain, e enable the
nable the memory-wiping option in the library call.</li>
memory wiping option in the library call.</t> <li>Run the scheme of type y, memory m, and p lanes
using a different number of passes t. Figure out the maximum t
<t>Run the scheme of type y, memory m and p lanes, such that the running time does not exceed the affordable time. If it eve
using different number of passes t. Figure out the maximum t n exceeds for t = 1, reduce m accordingly.</li>
such that the running time does not exceed the affordable time. If it exc <li> Use Argon2 with determined values m,
eeds p, and t.</li>
even for t = 1, reduce m accordingly.</t> </ol>
<t> Use Argon2 with determined values m,
p, and t.</t>
</list></t>
</section> </section>
<section anchor="test-vectors" numbered="true" toc="default">
<section anchor="test-vectors" <name>Test Vectors</name>
title="Test Vectors">
<t>This section contains test vectors for Argon2.</t> <t>This section contains test vectors for Argon2.</t>
<section anchor="argon2d-test-vectors" numbered="true" toc="default">
<section anchor="argon2d-test-vectors" <name>Argon2d Test Vectors</name>
title="Argon2d Test Vectors"> <t>We provide test vectors with complete outputs (tags). For the conveni
ence of developers, we also provide some interim variables -- concretely, the fi
<t>We provide test vectors with complete outputs (tags). For the convenie rst and last memory blocks of each pass.</t>
nce of developers, we also provide some interim variables, concretely, first and <sourcecode type="test-vectors">
last memory blocks of each pass.</t>
<figure>
<artwork>
======================================= =======================================
Argon2d version number 19 Argon2d version number 19
======================================= =======================================
Memory: 32 KiB Memory: 32 KiB
Passes: 3 Passes: 3
Parallelism: 4 lanes Parallelism: 4 lanes
Tag length: 32 bytes Tag length: 32 bytes
Password[32]: 01 01 01 01 01 01 01 01 Password[32]: 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
skipping to change at line 745 skipping to change at line 695
Block 0000 [ 3]: 7486a73f62f9b142 Block 0000 [ 3]: 7486a73f62f9b142
... ...
Block 0031 [124]: 57cfb9d20479da49 Block 0031 [124]: 57cfb9d20479da49
Block 0031 [125]: 4099654bc6607f69 Block 0031 [125]: 4099654bc6607f69
Block 0031 [126]: f142a1126075a5c8 Block 0031 [126]: f142a1126075a5c8
Block 0031 [127]: c341b3ca45c10da5 Block 0031 [127]: c341b3ca45c10da5
Tag: 51 2b 39 1b 6f 11 62 97 Tag: 51 2b 39 1b 6f 11 62 97
53 71 d3 09 19 73 42 94 53 71 d3 09 19 73 42 94
f8 68 e3 be 39 84 f3 c1 f8 68 e3 be 39 84 f3 c1
a1 3a 4d b9 fa be 4a cb a1 3a 4d b9 fa be 4a cb
</artwork> </sourcecode>
</figure>
</section> </section>
<section anchor="argon2i-test-vectors" numbered="true" toc="default">
<section anchor="argon2i-test-vectors" <name>Argon2i Test Vectors</name>
title="Argon2i Test Vectors"> <sourcecode type="test-vectors">
<figure>
<artwork>
======================================= =======================================
Argon2i version number 19 Argon2i version number 19
======================================= =======================================
Memory: 32 KiB Memory: 32 KiB
Passes: 3 Passes: 3
Parallelism: 4 lanes Parallelism: 4 lanes
Tag length: 32 bytes Tag length: 32 bytes
Password[32]: 01 01 01 01 01 01 01 01 Password[32]: 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
skipping to change at line 814 skipping to change at line 759
Block 0000 [ 3]: 25a1c1f5bb953766 Block 0000 [ 3]: 25a1c1f5bb953766
... ...
Block 0031 [124]: 68cf72fccc7112b9 Block 0031 [124]: 68cf72fccc7112b9
Block 0031 [125]: 91e8c6f8bb0ad70d Block 0031 [125]: 91e8c6f8bb0ad70d
Block 0031 [126]: 4f59c8bd65cbb765 Block 0031 [126]: 4f59c8bd65cbb765
Block 0031 [127]: 71e436f035f30ed0 Block 0031 [127]: 71e436f035f30ed0
Tag: c8 14 d9 d1 dc 7f 37 aa Tag: c8 14 d9 d1 dc 7f 37 aa
13 f0 d7 7f 24 94 bd a1 13 f0 d7 7f 24 94 bd a1
c8 de 6b 01 6d d3 88 d2 c8 de 6b 01 6d d3 88 d2
99 52 a4 c4 67 2b 6c e8 99 52 a4 c4 67 2b 6c e8
</artwork> </sourcecode>
</figure>
</section> </section>
<section anchor="argon2id-test-vectors" numbered="true" toc="default">
<section anchor="argon2id-test-vectors" <name>Argon2id Test Vectors</name>
title="Argon2id Test Vectors"> <sourcecode type="test-vectors">
<figure>
<artwork>
======================================= =======================================
Argon2id version number 19 Argon2id version number 19
======================================= =======================================
Memory: 32 KiB, Passes: 3, Memory: 32 KiB, Passes: 3,
Parallelism: 4 lanes, Tag length: 32 bytes Parallelism: 4 lanes, Tag length: 32 bytes
Password[32]: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 Password[32]: 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
Salt[16]: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 Salt[16]: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
Secret[8]: 03 03 03 03 03 03 03 03 Secret[8]: 03 03 03 03 03 03 03 03
Associated data[12]: 04 04 04 04 04 04 04 04 04 04 04 04 Associated data[12]: 04 04 04 04 04 04 04 04 04 04 04 04
skipping to change at line 873 skipping to change at line 813
Block 0000 [ 1]: a22448c0bdad5760 Block 0000 [ 1]: a22448c0bdad5760
Block 0000 [ 2]: a5f80662b6fa8748 Block 0000 [ 2]: a5f80662b6fa8748
Block 0000 [ 3]: a0f9b9ce392f719f Block 0000 [ 3]: a0f9b9ce392f719f
... ...
Block 0031 [124]: d723359b485f509b Block 0031 [124]: d723359b485f509b
Block 0031 [125]: cb78824f42375111 Block 0031 [125]: cb78824f42375111
Block 0031 [126]: 35bc8cc6e83b1875 Block 0031 [126]: 35bc8cc6e83b1875
Block 0031 [127]: 0b012846a40f346a Block 0031 [127]: 0b012846a40f346a
Tag: 0d 64 0d f5 8d 78 76 6c 08 c0 37 a3 4a 8b 53 c9 d0 Tag: 0d 64 0d f5 8d 78 76 6c 08 c0 37 a3 4a 8b 53 c9 d0
1e f0 45 2d 75 b6 5e b5 25 20 e9 6b 01 e6 59 1e f0 45 2d 75 b6 5e b5 25 20 e9 6b 01 e6 59
</artwork> </sourcecode>
</figure>
</section> </section>
</section> </section>
<section anchor="iana" numbered="true" toc="default">
<section anchor="iana" <name>IANA Considerations</name>
title="IANA Considerations"> <t>This document has no IANA actions.</t>
<t>None.</t>
</section> </section>
<section anchor="security" numbered="true" toc="default">
<section anchor="security" <name>Security Considerations</name>
title="Security Considerations"> <section anchor="security-hash" numbered="true" toc="default">
<section anchor="security-hash" <name>Security as a Hash Function and KDF</name>
title="Security as hash function and KDF"> <t>The collision and preimage resistance levels of Argon2 are equivalent
<t>The collision and preimage resistance levels of Argon2 are equiv to those of the underlying BLAKE2b hash function.
alent to those of the underlying BLAKE2b hash function.
To produce a collision, 2^(256) inputs are needed. To find a preima ge, 2^(512) inputs must be tried.</t> To produce a collision, 2^(256) inputs are needed. To find a preima ge, 2^(512) inputs must be tried.</t>
<t>The KDF security is determined by the key length
<t>The KDF security is determined by the key length
and the size of the internal state of hash function H'. and the size of the internal state of hash function H'.
To distinguish the output of keyed Argon2 from random, minimum of ( To distinguish the output of the keyed Argon2 from random, a minimu
2^(128),2^length(K)) calls to BLAKE2b are needed. </t> m of (2^(128),2^length(K)) calls to BLAKE2b are needed. </t>
</section> </section>
<section anchor="security-tradeoff" numbered="true" toc="default">
<section anchor="security-tradeoff" <name>Security against Time-Space Trade-off Attacks</name>
title="Security against time-space tradeoff attacks"> <t>Time-space trade-offs allow computing a memory-hard function storing
<t>Time-space tradeoffs allow computing a memory-hard function sto fewer memory blocks at the cost of more calls to
ring fewer memory blocks at the cost of more calls to the internal compression function. The advantage of trade-off attac
the internal comression function. The advantage of tradeoff attacks ks is measured in the reduction factor to the time-area
is measured in the reduction factor to the time-area product, where memory and extra compression function cores contribu
product, where memory and extra compression function cores contribu te to the area and time is increased to accommodate the recomputation
te to the area, and time is increased to accomodate the recomputation of missed blocks. A high reduction factor may potentially speed up
of missed blocks. A high reduction factor may potentially speed up the preimage search.
preimage search. </t>
</t> <t>The best-known attack on the 1-pass and 2-pass Argon2i is the low-sto
<t>The best known attacks on the 1-pass and 2-pass Argon2i is the low-stor rage
age attack described in <xref target="CBS16" format="default"/>, which reduces
attack described in <xref target="CBS16"></xref>, which reduces the the
time-area product (using the peak memory value) by the factor of 5. time-area product (using the peak memory value) by the factor of 5.
The best attack on 3-pass and more Argon2i is <xref target="AB16"></xref>
with reduction factor being a function of
memory size and the number of passes. For 1 gibibyte of memory: 3 for 3
passes, 2.5 for 4 passes, 2 for 6 passes. The reduction
factor grows by about 0.5 with every doubling the memory size.
To completely prevent time-space tradeoffs from <xref target="AB16"></x
ref>, the
number of passes MUST exceed binary logarithm of memory minus 26.
Asymptotically, the best attack on 1-pass Argon2i is given in <xref tar
get="BZ17"></xref> with maximal advantage
of the adversary upper bounded by O(m^(0.233)) where m is the number of
blocks. This attack is also asymptotically optimal as <xref target="BZ17"></xre
f> also prove the upper bound on any attack of O(m^(0.25)).
</t>
<t>The best tradeoff attack on t-pass Argon2d is the ranking tradeoff atta The best attack on Argon2i with 3 passes or more is described in <xref tar
ck, get="AB16" format="default"/>, with the reduction factor being a function of
memory size and the number of passes (e.g., for 1 gibibyte of memory, a
reduction factor of 3 for 3 passes, 2.5 for 4 passes, 2 for 6 passes). The redu
ction
factor grows by about 0.5 with every doubling of the memory size.
To completely prevent time-space trade-offs from <xref target="AB16" fo
rmat="default"/>, the
number of passes <bcp14>MUST</bcp14> exceed the binary logarithm of memory
minus 26.
Asymptotically, the best attack on 1-pass Argon2i is given in <xref tar
get="BZ17" format="default"/>, with maximal advantage
of the adversary upper bounded by O(m^(0.233)), where m is the number of
blocks. This attack is also asymptotically optimal as <xref target="BZ17" format
="default"/> also proves the upper bound on any attack is O(m^(0.25)).
</t>
<t>The best trade-off attack on t-pass Argon2d is the ranking trade-off
attack,
which reduces the time-area product by the factor of 1.33. which reduces the time-area product by the factor of 1.33.
</t> </t>
<t>The best attack on Argon2id can be obtained by complementing the best
attack
on the 1-pass Argon2i with the best attack on a multi-pass Argon2d.
<t>The best attack on Argon2id can be obtained by complementing the bes Thus, the best trade-off attack on 1-pass Argon2id is the combined low-storage a
t attack ttack (for the first half of the memory) and
on the 1-pass Argon2i with the best attack on a multi-pass Argon2d. Thu the ranking attack (for the second half), which generate the factor of
s the best tradeoff attack on 1-pass Argon2id is the combined low-storage attack about 2.1. The best trade-off attack on
(for the first half of the memory) and t-pass Argon2id is the ranking trade-off attack,
the ranking attack (for the second half), which bring together the fact
or of about 2.1. The best tradeoff attack on
t-pass Argon2id is the ranking tradeoff attack,
which reduces the time-area product by the factor of 1.33. which reduces the time-area product by the factor of 1.33.
</t> </t>
</section> </section>
<section anchor="security-general" numbered="true" toc="default">
<section anchor="security-general" title="Security for time-bounded <name>Security for Time-Bounded Defenders</name>
defenders"> <t>A bottleneck in a system employing the password hashing function
<t>A bottleneck in a system employing the password-hashi
ng function
is often the function latency rather than memory costs. A rational is often the function latency rather than memory costs. A rational
defender would then maximize the bruteforce costs for th defender would then maximize the brute-force costs for t
e attacker equipped he attacker equipped
with a list of hashes, salts, and timing information, fo with a list of hashes, salts, and timing information for
r fixed computing time fixed computing time
on the defender’s machine. The attack cost estimates fr on the defender's machine. The attack cost estimates fr
om <xref target="AB16"></xref> om <xref target="AB16" format="default"/>
imply that for Argon2i, 3 passes is almost optimal for t imply that for Argon2i, 3 passes is almost optimal for m
he most of reasonable memory sizes, ost reasonable memory sizes; for Argon2d and Argon2id, 1 pass maximizes the atta
and that for Argon2d and Argon2id, 1 pass maximizes the ck costs for the constant defender time.
attack costs for the constant defender time. </t>
</t> </section>
</section> <section anchor="security-recommend" numbered="true" toc="default">
<name>Recommendations</name>
<section anchor="security-recommend" <t>
title="Recommendations"> The Argon2id variant with t=1 and 2 GiB memory is the FIRST <bcp14>RECOMMENDED</
<t> bcp14> option and is suggested
The Argon2id variant with t=1 and 2GiB memory is FIRST RECOMMENDED option and is as a default setting for all environments. This setting is secure against side-c
suggested hannel attacks
as a default setting for all environments. This setting is secure against side- and maximizes adversarial costs on dedicated brute-force hardware. The Argon2id
channel attacks variant with t=3 and 64 MiB memory is the SECOND <bcp14>RECOMMENDED</bcp14> opti
and maximizes adversarial costs on dedicated bruteforce hardware. The Argon2id v on and is suggested
ariant with t=3 and 64 MiB memory is
SECOND RECOMMENDED option and is suggested
as a default setting for memory-constrained environments. as a default setting for memory-constrained environments.
</t> </t>
</section> </section>
</section> </section>
<section anchor="ack"
title="Acknowledgements">
<t>We thank greatly the following authors who helped a lot in preparing an
d reviewing
this document: Jean-Philippe Aumasson,
Samuel Neves, Joel Alwen, Jeremiah Blocki, Bill Cox, Arnold Reinhold, S
olar Designer, Russ Housley,
Stanislav Smyshlyaev, Kenny Paterson, Alexey Melnikov, Gwynne Raskind.</t>
</section>
</middle> </middle>
<back> <back>
<references title="Normative References"> <displayreference target="RFC7693" to="BLAKE2"/>
<reference anchor="RFC2119" target = "http://www.rfc-editor.org/info/rf
c2119">
<front>
<title>Key words for use in RFCs to Indicate
Requirement Levels</title>
<author surname="Bradner" initials ="S."/>
<date month="March" year="1997" />
</front>
<seriesInfo name="RFC" value="2119"/>
</reference>
<reference anchor="BLAKE2" target="https://www.rfc-editor.org/info/rfc769
3">
<front>
<title>
The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)
</title>
<author initials="M-J." surname="Saarinen" fullname="M-J. Saarinen" role=
"editor">
<organization/>
</author>
<author initials="J-P." surname="Aumasson" fullname="J-P. Aumasson">
<organization/>
</author>
<date year="2015" month="November"/>
<abstract>
<t>
This document describes the cryptographic hash function BLAKE2 and makes
the algorithm specification and C source code conveniently available to the Inte
rnet community. BLAKE2 comes in two main flavors: BLAKE2b is optimized for 64-bi
t platforms and BLAKE2s for smaller architectures. BLAKE2 can be directly keyed,
making it functionally equivalent to a Message Authentication Code (MAC).
</t>
</abstract>
</front>
<seriesInfo name="RFC" value="7693"/>
</reference>
</references>
<references title="Informative References">
<!-- &RFC4086; --> <references>
<name>References</name>
<references>
<name>Normative References</name>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.2119.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.8174.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.7693.xml"/>
</references>
<references>
<name>Informative References</name>
<reference anchor="ARGON2" target = "https://www.cryptolux.org/images/0/0d <reference anchor="ARGON2" target="https://www.cryptolux.org/images/0/0d/A
/Argon2.pdf"> rgon2.pdf">
<front> <front>
<title>Argon2: the memory-hard function for password hashing <title>Argon2: the memory-hard function for password hashing
and other applications</title> and other applications</title>
<author initials="A." surname="Biryukov" fullname="Alex Biryukov"/> <author initials="A." surname="Biryukov" fullname="Alex Biryukov"/>
<author initials="D." surname="Dinu" fullname="Daniel Dinu"/> <author initials="D." surname="Dinu" fullname="Daniel Dinu"/>
<author initials="D." surname="Khovratovich" <author initials="D." surname="Khovratovich" fullname="Dmitry Khovra
fullname="Dmitry Khovratovich"/> tovich"/>
<date month="October" year="2015" /> <date month="March" year="2017"/>
</front> </front>
<seriesInfo name="WWW" </reference>
value="www.cryptolux.org" />
</reference>
<reference anchor="HARD" target="https://eprint.iacr.org/2014/238.pdf"> <reference anchor="HARD" target="https://eprint.iacr.org/2014/238.pdf">
<front> <front>
<title>High Parallel Complexity Graphs and Memory-Hard Functions</title <title>High Parallel Complexity Graphs and Memory-Hard Functions</ti
> tle>
<author initials="J." surname="Alwen" fullname="Joel Alwen"/> <author initials="J." surname="Alwen" fullname="Joel Alwen"/>
<author initials="V." surname="Serbinenko" fullname="Vladimir Serbinenk <author initials="V." surname="Serbinenko" fullname="Vladimir Serbin
o"/> enko"/>
<date year="2014" /> <date year="2015" month="June"/>
</front> </front>
<seriesInfo name="STOC" value="2015"/> <seriesInfo name="DOI" value="10.1145/2746539.2746622"/>
</reference> <refcontent>STOC '15</refcontent>
</reference>
<reference anchor="CBS16" target="https://eprint.iacr.org/2016/027.pdf"> <reference anchor="CBS16" target="https://eprint.iacr.org/2016/027.pdf">
<front> <front>
<title>Balloon Hashing: Provably Space-Hard Hash Functions with <title>Balloon Hashing: A Memory-Hard Function Providing Provable Pr
Data-Independent Access Patterns</title> otection Against Sequential Attacks</title>
<author initials="H." surname="Corrigan-Gibbs" <author initials="D." surname="Boneh" fullname="Dan Boneh"/>
fullname="Henry Corrigan-Gibs"/> <author initials="H." surname="Corrigan-Gibbs" fullname="Henry Corri
<author initials="D." surname="Boneh" fullname="Dan Boneh"/> gan-Gibbs"/>
<author initials="S." surname="Schechter" fullname="Stuart Schechter"/> <author initials="S." surname="Schechter" fullname="Stuart Schechter
<date month="January" year="2016" /> "/>
</front> <date month="May" year="2017"/>
<seriesInfo name="Asiacrypt" value="2016"/> </front>
</reference> <seriesInfo name="DOI" value="10.1007/978-3-662-53887-6_8"/>
<refcontent>ASIACRYPT 2016</refcontent>
</reference>
<reference anchor="AB16" target="https://eprint.iacr.org/2016/115.pdf"> <reference anchor="AB16" target="https://eprint.iacr.org/2016/115.pdf">
<front> <front>
<title>Efficiently Computing Data-Independent Memory-Hard Functions</tit <title>Efficiently Computing Data-Independent Memory-Hard Functions<
le> /title>
<author initials="J." surname="Alwen" <author initials="J." surname="Alwen" fullname="Joel Alwen"/>
fullname="Joel Alwen"/> <author initials="J." surname="Blocki" fullname="Jeremiah Blocki"/>
<author initials="J." surname="Blocki" fullname="Jeremiah Blocki"/> <date month="March" year="2016"/>
<date month="December" year="2015" /> </front>
</front> <seriesInfo name="DOI" value="10.1007/978-3-662-53008-5_9"/>
<seriesInfo name="Crypto" value="2016"/> <refcontent>CRYPTO 2016</refcontent>
</reference> </reference>
<reference anchor="BZ17" target="https://eprint.iacr.org/2017/442.pdf"> <reference anchor="BZ17" target="https://eprint.iacr.org/2017/442.pdf">
<front> <front>
<title>On the Depth-Robustness and Cumulative Pebbling Cost of Argon2i</ <title>On the Depth-Robustness and Cumulative Pebbling Cost of Argon
title> 2i</title>
<author initials="J." surname="Blocki" <author initials="J." surname="Blocki" fullname="Jeremiah Blocki"/>
fullname="Jeremiah Blocki"/> <author initials="S." surname="Zhou" fullname="Samson Zhou"/>
<author initials="S." surname="Zhou" fullname="Samson Zhou"/> <date month="May" year="2017"/>
<date month="May" year="2017" /> </front>
</front> <seriesInfo name="DOI" value="10.1007/978-3-319-70500-2_15"/>
<seriesInfo name="TCC" value="2017"/> <refcontent>TCC 2017</refcontent>
</reference> </reference>
<reference anchor="ARGON2ESP" target="https://www.cryptolux.org/imag <reference anchor="ARGON2ESP" target="https://www.cryptolux.org/images/d
es/d/d0/Argon2ESP.pdf"> /d0/Argon2ESP.pdf">
<front> <front>
<title>Argon2: New Generation of Memory-Hard Functions for Password Has <title>Argon2: New Generation of Memory-Hard Functions for Password
hing Hashing
and Other Applications</title> and Other Applications</title>
<author initials="A." surname="Biryukov" fullname="Alex Biryukov"/> <author initials="A." surname="Biryukov" fullname="Alex Biryukov"/>
<author initials="D." surname="Dinu" fullname="Daniel Dinu"/> <author initials="D." surname="Dinu" fullname="Daniel Dinu"/>
<author initials="D." surname="Khovratovich" <author initials="D." surname="Khovratovich" fullname="Dmitry Khovra
fullname="Dmitry Khovratovich"/> tovich"/>
<date month="March" year="2016" /> <date month="March" year="2016"/>
</front> </front>
<seriesInfo name="Euro SnP" value="2016"/> <seriesInfo name="DOI" value="10.1109/EuroSP.2016.31"/>
</reference> <refcontent>Euro SnP 2016</refcontent>
</reference>
<reference anchor="AB15" target="https://eprint.iacr.org/2015/227.pdf">
<front>
<title>Tradeoff Cryptanalysis of Memory-Hard Functions</title>
<author initials="A." surname="Biryukov"
fullname="Alex Biryukov"/>
<author initials="D." surname="Khovratovich" fullname="Dmitry Khovratovi
ch"/>
<date month="December" year="2015" />
</front>
<seriesInfo name="Asiacrypt" value="2015"/>
</reference>
<reference anchor="AB15" target="https://eprint.iacr.org/2015/227.pdf">
<front>
<title>Tradeoff Cryptanalysis of Memory-Hard Functions</title>
<author initials="A." surname="Biryukov" fullname="Alex Biryukov"/>
<author initials="D." surname="Khovratovich" fullname="Dmitry Khovra
tovich"/>
<date month="December" year="2015"/>
</front>
<seriesInfo name="DOI" value="10.1007/978-3-662-48800-3_26"/>
<refcontent>ASIACRYPT 2015</refcontent>
</reference>
</references>
</references> </references>
<section anchor="ack" numbered="false" toc="default">
<name>Acknowledgements</name>
<t>We greatly thank the following individuals who helped in preparing and
reviewing
this document: <contact fullname="Jean-Philippe Aumasson"/>,
<contact fullname="Samuel Neves"/>, <contact fullname="Joel Alwen"/>, <
contact fullname="Jeremiah Blocki"/>, <contact fullname="Bill Cox"/>, <contact f
ullname="Arnold Reinhold"/>, <contact fullname="Solar Designer"/>, <contact full
name="Russ Housley"/>,
<contact fullname="Stanislav Smyshlyaev"/>, <contact fullname="Kenny Paters
on"/>, <contact fullname="Alexey Melnikov"/>, and <contact fullname="Gwynne Rask
ind"/>.</t>
<t>The work described in this document was done before <contact fullname="Daniel
Dinu"/> joined Intel, while he was at the University of Luxembourg.</t>
</section>
</back> </back>
</rfc> </rfc>
 End of changes. 126 change blocks. 
770 lines changed or deleted 692 lines changed or added

This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/