<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.19 (Ruby 3.3.3) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-connolly-cfrg-xwing-kem-06" category="info" consensus="true" submissionType="IRTF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.23.2 -->
  <front>
    <title abbrev="xwing">X-Wing: general-purpose hybrid post-quantum KEM</title>
    <seriesInfo name="Internet-Draft" value="draft-connolly-cfrg-xwing-kem-06"/>
    <author fullname="Deirdre Connolly">
      <organization>SandboxAQ</organization>
      <address>
        <email>durumcrustulum@gmail.com</email>
      </address>
    </author>
    <author fullname="Peter Schwabe">
      <organization>MPI-SP &amp; Radboud University</organization>
      <address>
        <email>peter@cryptojedi.org</email>
      </address>
    </author>
    <author initials="B. E." surname="Westerbaan" fullname="Bas Westerbaan">
      <organization>Cloudflare</organization>
      <address>
        <email>bas@cloudflare.com</email>
      </address>
    </author>
    <date year="2024" month="August" day="19"/>
    <area>IRTF</area>
    <workgroup>Crypto Forum</workgroup>
    <keyword>post quantum</keyword>
    <keyword>kem</keyword>
    <keyword>PQ/T hybrid</keyword>
    <abstract>
      <?line 103?>

<t>This memo defines X-Wing, a general-purpose post-quantum/traditional
hybrid key encapsulation mechanism (PQ/T KEM) built on X25519 and
ML-KEM-768.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://dconnolly.github.io/draft-connolly-cfrg-xwing-kem/draft-connolly-cfrg-xwing-kem.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Crypto Forum Research Group mailing list (<eref target="mailto:cfrg@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/search/?email_list=cfrg"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/cfrg/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/dconnolly/draft-connolly-cfrg-xwing-kem"/>.</t>
    </note>
  </front>
  <middle>
    <?line 109?>

<section anchor="intro">
      <name>Introduction</name>
      <section anchor="motivation">
        <name>Motivation</name>
        <t>There are many choices that can be made when specifying a hybrid KEM:
the constituent KEMs; their security levels; the combiner; and the hash
within, to name but a few. Having too many similar options are a burden
to the ecosystem.</t>
        <t>The aim of X-Wing is to provide a concrete, simple choice for
post-quantum hybrid KEM, that should be suitable for the vast majority
of use cases.</t>
      </section>
      <section anchor="goals">
        <name>Design goals</name>
        <t>By making concrete choices, we can simplify and improve many aspects of
X-Wing.</t>
        <ul spacing="normal">
          <li>
            <t>Simplicity of definition. Because all shared secrets and cipher texts
are fixed length, we do not need to encode the length. Using SHA3-256,
we do not need HMAC-based construction. For the concrete choice of
ML-KEM-768, we do not need to mix in its ciphertext, see <xref target="secc"/>.</t>
          </li>
          <li>
            <t>Security analysis. Because ML-KEM-768 already assumes the Quantum Random
Oracle Model (QROM), we do not need to complicate the analysis
of X-Wing by considering stronger models.</t>
          </li>
          <li>
            <t>Performance. Not having to mix in the ML-KEM-768 ciphertext is a nice
performance benefit. Furthermore, by using SHA3-256 in the combiner,
which matches the hashing in ML-KEM-768, this hash can be computed in
one go on platforms where two-way Keccak is available.</t>
          </li>
        </ul>
        <t>We aim for "128 bits" security (NIST PQC level 1). Although at the
moment there is no peer-reviewed evidence that ML-KEM-512 does not reach
this level, we would like to hedge against future cryptanalytic
improvements, and feel ML-KEM-768 provides a comfortable margin.</t>
        <t>We aim for X-Wing to be usable for most applications, including
specifically HPKE <xref target="RFC9180"/>.</t>
      </section>
      <section anchor="not-an-interactive-key-agreement">
        <name>Not an interactive key-agreement</name>
        <t>Traditionally most protocols use a Diffie-Hellman (DH) style
non-interactive key-agreement.  In many cases, a DH key agreement can be
replaced by the interactive key-agreement afforded by a KEM without
change in the protocol flow.  One notable example is TLS <xref target="HYBRID"/>
          <xref target="XYBERTLS"/>.  However, not all uses of DH can be replaced in a
straight-forward manner by a plain KEM.</t>
      </section>
      <section anchor="auth">
        <name>Not an authenticated KEM</name>
        <t>In particular, X-Wing is not, borrowing the language of <xref target="RFC9180"/>, an
<em>authenticated</em> KEM.</t>
      </section>
      <section anchor="comparisons">
        <name>Comparisons</name>
        <section anchor="with-hpke-x25519kyber768draft00">
          <name>With HPKE X25519Kyber768Draft00</name>
          <t>X-Wing is most similar to HPKE's X25519Kyber768Draft00
<xref target="XYBERHPKE"/>. The key differences are:</t>
          <ul spacing="normal">
            <li>
              <t>X-Wing uses the final version of ML-KEM-768.</t>
            </li>
            <li>
              <t>X-Wing hashes the shared secrets, to be usable outside of HPKE.</t>
            </li>
            <li>
              <t>X-Wing has a simpler combiner by flattening DHKEM(X25519) into the
final hash.</t>
            </li>
            <li>
              <t>X-Wing does not hash in the ML-KEM-768 ciphertext.</t>
            </li>
          </ul>
          <t>There is also a different KEM called X25519Kyber768Draft00 <xref target="XYBERTLS"/>
which is used in TLS. This one should not be used outside of TLS, as it
assumes the presence of the TLS transcript to ensure non malleability.</t>
        </section>
        <section anchor="with-generic-combiner">
          <name>With generic combiner</name>
          <t>The generic combiner of <xref target="I-D.ounsworth-cfrg-kem-combiners"/> can be
instantiated with ML-KEM-768 and DHKEM(X25519). That achieves similar
security, but:</t>
          <ul spacing="normal">
            <li>
              <t>X-Wing is more performant, not hashing in the ML-KEM-768 ciphertext,
and flattening the DHKEM construction, with the same level of
security.</t>
            </li>
            <li>
              <t>X-Wing has a fixed 32 byte shared secret, instead of a variable shared
secret.</t>
            </li>
            <li>
              <t>X-Wing does not accept the optional counter and fixedInfo arguments.</t>
            </li>
          </ul>
        </section>
      </section>
    </section>
    <section anchor="requirements-notation">
      <name>Requirements Notation</name>
      <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</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 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
      <?line -18?>

</section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>This document is consistent with all terminology defined in
<xref target="I-D.driscoll-pqt-hybrid-terminology"/>.</t>
      <t>The following terms are used throughout this document to describe the
operations, roles, and behaviors of HPKE:</t>
      <ul spacing="normal">
        <li>
          <t><tt>concat(x0, ..., xN)</tt>: returns the concatenation of byte
strings. <tt>concat(0x01, 0x0203, 0x040506) = 0x010203040506</tt>.</t>
        </li>
        <li>
          <t><tt>random(n)</tt>: return a pseudorandom byte string of length <tt>n</tt> bytes produced by
a cryptographically-secure random number generator.</t>
        </li>
      </ul>
    </section>
    <section anchor="base-crypto">
      <name>Cryptographic Dependencies</name>
      <t>X-Wing relies on the following primitives:</t>
      <ul spacing="normal">
        <li>
          <t>ML-KEM-768 post-quantum key-encapsulation mechanism (KEM) <xref target="MLKEM"/>:  </t>
          <ul spacing="normal">
            <li>
              <t><tt>ML-KEM-768.KeyGen_internal(d, z)</tt>: Deterministic algorithm to generate an
ML-KEM-768 key pair <tt>(pk_M, sk_M)</tt> of an encapsulation key <tt>pk_M</tt>
and decapsulation key <tt>sk_M</tt>.
It is the derandomized version of <tt>ML-KEM-768.KeyGen</tt>.
Note that <tt>ML-KEM-768.KeyGen_internal()</tt> returns the keys in reverse
order of <tt>GenerateKeyPair()</tt> defined below.
<tt>d</tt> and <tt>z</tt> are both 32 byte strings.</t>
            </li>
            <li>
              <t><tt>ML-KEM-768.Encaps(pk_M)</tt>: Randomized algorithm to generate <tt>(ss_M,
ct_M)</tt>, an ephemeral 32 byte shared key <tt>ss_M</tt>, and a fixed-length
encapsulation (ciphertext) of that key <tt>ct_M</tt> for encapsulation key <tt>pk_M</tt>.      </t>
              <t><tt>ML-KEM-768.Encaps(pk_M)</tt> <bcp14>MUST</bcp14> perform the encapsulation key check
of <xref target="MLKEM"/> §7.2 and raise an error if it fails.</t>
            </li>
            <li>
              <t><tt>ML-KEM-768.Decap(ct_M, sk_M)</tt>: Deterministic algorithm using the
decapsulation key <tt>sk_M</tt> to recover the shared key from <tt>ct_M</tt>.      </t>
              <t><tt>ML-KEM-768.Decap(ct_M, sk_M)</tt> is NOT required  to perform the
decapsulation key check of <xref target="MLKEM"/> §7.3.</t>
            </li>
          </ul>
          <t>
To generate deterministic test vectors, we also use  </t>
          <ul spacing="normal">
            <li>
              <t><tt>ML-KEM-768.Encaps_internal(pk_M, m)</tt>: Algorithm to generate <tt>(ss_M, ct_M)</tt>,
an ephemeral 32 byte shared key <tt>ss_M</tt>, and a fixed-length
encapsulation (ciphertext) of that key <tt>ct_M</tt> for encapsulation key
<tt>pk_M</tt>. <tt>m</tt> is a 32 byte string.      </t>
              <t><tt>ML-KEM-768.Encaps_internal(pk_M)</tt> <bcp14>MUST</bcp14> perform the encapsulation key check
of <xref target="MLKEM"/> §7.2 and raise an error if it fails.</t>
            </li>
          </ul>
        </li>
        <li>
          <t>X25519 elliptic curve Diffie-Hellman key-exchange defined in <xref section="5" sectionFormat="of" target="RFC7748"/>:  </t>
          <ul spacing="normal">
            <li>
              <t><tt>X25519(k,u)</tt>: takes 32 byte strings k and u representing a
Curve25519 scalar and curvepoint respectively, and returns
the 32 byte string representing their scalar multiplication.</t>
            </li>
            <li>
              <t><tt>X25519_BASE</tt>: the 32 byte string representing the standard base point
of Curve25519. In hex
it is given by <tt>0900000000000000000000000000000000000000000000000000000000000000</tt>.</t>
            </li>
          </ul>
        </li>
      </ul>
      <t>Note that 9 is the standard basepoint for X25519, cf <xref section="6.1" sectionFormat="of" target="RFC7748"/>.</t>
      <ul spacing="normal">
        <li>
          <t>Symmetric cryptography.  </t>
          <ul spacing="normal">
            <li>
              <t><tt>SHAKE256(message, outlen)</tt>: The extendable-output function (XOF)
with that name defined in Section 6.2 of <xref target="FIPS202"/>.</t>
            </li>
            <li>
              <t><tt>SHA3-256(message)</tt>: The hash with that name
defined in Section 6.1 of <xref target="FIPS202"/>.</t>
            </li>
          </ul>
        </li>
      </ul>
    </section>
    <section anchor="x-wing-construction">
      <name>X-Wing Construction</name>
      <section anchor="encoding">
        <name>Encoding and sizes</name>
        <t>X-Wing encapsulation key, decapsulation key, ciphertexts and shared secrets are all
fixed length byte strings.</t>
        <dl>
          <dt>Decapsulation key (private):</dt>
          <dd>
            <t>32 bytes</t>
          </dd>
          <dt>Encapsulation key (public):</dt>
          <dd>
            <t>1216 bytes</t>
          </dd>
          <dt>Ciphertext:</dt>
          <dd>
            <t>1120 bytes</t>
          </dd>
          <dt>Shared secret:</dt>
          <dd>
            <t>32 bytes</t>
          </dd>
        </dl>
      </section>
      <section anchor="key-generation">
        <name>Key generation</name>
        <t>An X-Wing keypair (decapsulation key, encapsulation key) is generated as
follows.</t>
        <artwork><![CDATA[
def expandDecapsulationKey(sk):
  expanded = SHAKE256(sk, 96)
  (pk_M, sk_M) = ML-KEM-768.KeyGen_internal(expanded[0:32], expanded[32:64])
  sk_X = expanded[64:96]
  pk_X = X25519(sk_X, X25519_BASE)
  return (sk_M, sk_X, pk_M, pk_X)

def GenerateKeyPair():
  sk = random(32)
  (sk_M, sk_X, pk_M, pk_X) = expandDecapsulationKey(sk)
  return sk, concat(pk_M, pk_X)
]]></artwork>
        <t><tt>GenerateKeyPair()</tt> returns the 32 byte secret decapsulation key <tt>sk</tt>
and the 1216 byte encapsulation key <tt>pk</tt>.</t>
        <t>Here and in the balance of the document for clarity we use
the <tt>M</tt> and <tt>X</tt>subscripts for ML-KEM-768 and X25519 components respectively.</t>
        <section anchor="derive-key-pair">
          <name>Key derivation</name>
          <t>For testing, it is convenient to have a deterministic version
of key generation. An X-Wing implementation <bcp14>MAY</bcp14> provide the following
derandomized variant of key generation.</t>
          <artwork><![CDATA[
def GenerateKeyPairDerand(sk):
  sk_M, sk_X, pk_M, pk_X = expandDecapsulationKey(sk)
  return sk, concat(pk_M, pk_X)
]]></artwork>
          <t><tt>sk</tt> must be 32 bytes.</t>
          <t><tt>GenerateKeyPairDerand()</tt> returns the 32 byte secret encapsulation key
<tt>sk</tt> and the 1216 byte decapsulation key <tt>pk</tt>.</t>
        </section>
      </section>
      <section anchor="combiner">
        <name>Combiner</name>
        <t>Given 32 byte strings <tt>ss_M</tt>, <tt>ss_X</tt>, <tt>ct_X</tt>, <tt>pk_X</tt>, representing the
ML-KEM-768 shared secret, X25519 shared secret, X25519 ciphertext
(ephemeral public key) and X25519 public key respectively, the 32 byte
combined shared secret is given by:</t>
        <artwork><![CDATA[
def Combiner(ss_M, ss_X, ct_X, pk_X):
  return SHA3-256(concat(
    ss_M,
    ss_X,
    ct_X,
    pk_X,
    XWingLabel
  ))
]]></artwork>
        <t>where XWingLabel is the following 6 byte ASCII string</t>
        <artwork><![CDATA[
XWingLabel = concat(
    "\./",
    "/^\",
)
]]></artwork>
        <t>In hex XWingLabel is given by <tt>5c2e2f2f5e5c</tt>.</t>
      </section>
      <section anchor="encaps">
        <name>Encapsulation</name>
        <t>Given an X-Wing encapsulation key <tt>pk</tt>, encapsulation proceeds as follows.</t>
        <artwork><![CDATA[
def Encapsulate(pk):
  pk_M = pk[0:1184]
  pk_X = pk[1184:1216]
  ek_X = random(32)
  ct_X = X25519(ek_X, X25519_BASE)
  ss_X = X25519(ek_X, pk_X)
  (ss_M, ct_M) = ML-KEM-768.Encaps(pk_M)
  ss = Combiner(ss_M, ss_X, ct_X, pk_X)
  ct = concat(ct_M, ct_X)
  return (ss, ct)
]]></artwork>
        <t><tt>pk</tt> is a 1216 byte X-Wing encapsulation key resulting from <tt>GeneratePublicKey()</tt></t>
        <t><tt>Encapsulate()</tt> returns the 32 byte shared secret <tt>ss</tt> and the 1120 byte
ciphertext <tt>ct</tt>.</t>
        <t>Note that <tt>Encapsulate()</tt> may raise an error if the ML-KEM encapsulation
does not pass the check of <xref target="MLKEM"/> §7.2.</t>
        <section anchor="derandomized">
          <name>Derandomized</name>
          <t>For testing, it is convenient to have a deterministic version
of encapsulation. An X-Wing implementation <bcp14>MAY</bcp14> provide
the following derandomized function.</t>
          <artwork><![CDATA[
def EncapsulateDerand(pk, eseed):
  pk_M = pk[0:1184]
  pk_X = pk[1184:1216]
  ek_X = eseed[32:64]
  ct_X = X25519(ek_X, X25519_BASE)
  ss_X = X25519(ek_X, pk_X)
  (ss_M, ct_M) = ML-KEM-768.EncapsDerand(pk_M, eseed[0:32])
  ss = Combiner(ss_M, ss_X, ct_X, pk_X)
  ct = concat(ct_M, ct_X)
  return (ss, ct)
]]></artwork>
          <t><tt>pk</tt> is a 1216 byte X-Wing encapsulation key resulting from <tt>GeneratePublicKey()</tt>
            <tt>eseed</tt> <bcp14>MUST</bcp14> be 64 bytes.</t>
          <t><tt>EncapsulateDerand()</tt> returns the 32 byte shared secret <tt>ss</tt> and the 1120 byte
ciphertext <tt>ct</tt>.</t>
        </section>
      </section>
      <section anchor="decaps">
        <name>Decapsulation</name>
        <artwork><![CDATA[
def Decapsulate(ct, sk):
  (sk_M, sk_X, pk_M, pk_X) = expandDecapsulationKey(sk)
  ct_M = ct[0:1088]
  ct_X = ct[1088:1120]
  ss_M = ML-KEM-768.Decapsulate(ct_M, sk_M)
  ss_X = X25519(sk_X, ct_X)
  return Combiner(ss_M, ss_X, ct_X, pk_X)
]]></artwork>
        <t><tt>ct</tt> is the 1120 byte ciphertext resulting from <tt>Encapsulate()</tt>
          <tt>sk</tt> is a 32 byte X-Wing decapsulation key resulting from <tt>GenerateKeyPair()</tt></t>
        <t><tt>Decapsulate()</tt> returns the 32 byte shared secret.</t>
        <section anchor="keeping-expanded-decapsulation-key-around">
          <name>Keeping expanded decapsulation key around</name>
          <t>For efficiency, an implementation <bcp14>MAY</bcp14> cache the result of <tt>expandDecapsulationKey</tt>.
This is useful in two cases:</t>
          <ol spacing="normal" type="1"><li>
              <t>If multiple ciphertexts for the same key are decapsulated.</t>
            </li>
            <li>
              <t>If a ciphertext is decapsulated for a key that has just been generated.
This happen on the client-side for TLS.</t>
            </li>
          </ol>
          <t>A typical API pattern to achieve this optimization is to have an
opaque decapsulation key object that hides the cached values.
For instance, such an API could have the following functions.</t>
          <ol spacing="normal" type="1"><li>
              <t><tt>GenerateKeyPair()</tt> returns an encapsulation key and an opaque
 object that contains the expanded decapsulation key.</t>
            </li>
            <li>
              <t><tt>Decapsulate(ct, esk)</tt> takes a ciphertext and an expanded decapsulation key.</t>
            </li>
            <li>
              <t><tt>PackDecapsulationKey(sk)</tt> takes an expanded decapsulation key,
 and returns the packed decapsulation key.</t>
            </li>
            <li>
              <t><tt>UnpackDecapsulationKey(sk)</tt> takes a packed decapsulation key, and returns
 the expanded decapsulation key. In the case of X-Wing this would
 be the same as a derandomized <tt>GenerateKeyPair()</tt>.</t>
            </li>
          </ol>
          <t>The expanded decapsulation key could cache even more computation,
such as the expanded matrix A in ML-KEM.</t>
          <t>Any such expanded decapsulation key <bcp14>MUST NOT</bcp14> be transmitted between
implementations, as this could break the security analysis of X-Wing.
In particular, the MAL-BIND-K-PK and MAL-BIND-K-CT binding
properties of X-Wing do not hold when transmitting the regular ML-KEM
decapsulation key.</t>
        </section>
      </section>
      <section anchor="use-in-hpke">
        <name>Use in HPKE</name>
        <t>X-Wing satisfies the HPKE KEM interface as follows.</t>
        <t>The <tt>SerializePublicKey</tt>, <tt>SerializePrivateKey</tt>,
and <tt>DeserializePrivateKey</tt> are the identity functions,
as X-Wing keys are fixed-length byte strings, see <xref target="encoding"/>.</t>
        <t><tt>DeriveKeyPair()</tt> is given by</t>
        <artwork><![CDATA[
def DeriveKeyPair(ikm):
  return GenerateKeyPairDerand(SHAKE256(ikm, 32))
]]></artwork>
        <t>where the HPKE private key and public key are the X-Wing decapsulation
key and encapsulation key respectively.</t>
        <t><tt>Encap()</tt> is <tt>Encapsulate()</tt> from <xref target="encaps"/>, where an
ML-KEM encapsulation key check failure causes an HPKE <tt>EncapError</tt>.</t>
        <t><tt>Decap()</tt> is <tt>Decapsulate()</tt> from <xref target="decaps"/>.</t>
        <t>X-Wing is not an authenticated KEM: it does not support <tt>AuthEncap()</tt>
and <tt>AuthDecap()</tt>, see <xref target="auth"/>.</t>
        <t>Nsecret, Nenc, Npk, and Nsk are defined in <xref target="iana"/>.</t>
      </section>
      <section anchor="use-in-tls-13">
        <name>Use in TLS 1.3</name>
        <t>For the client's share, the key_exchange value contains
the X-Wing encapsulation key.</t>
        <t>For the server's share, the key_exchange value contains
the X-Wing ciphertext.</t>
        <t>On ML-KEM encapsulation key check failure, the server <bcp14>MUST</bcp14>
abort with an illegal_parameter alert.</t>
      </section>
      <section anchor="use-in-x509-public-key-infrastructure">
        <name>Use in X.509 Public Key Infrastructure</name>
        <t>We use the OID 1.3.6.1.4.1.62253.25722 to identify X-Wing keys
as described below. In ASN.1 notation:</t>
        <artwork><![CDATA[
id-XWing OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
        dod(6) internet(1) private(4) enterprise(1) 62253 25722 }
]]></artwork>
        <section anchor="certificate">
          <name>Certificate</name>
          <t>In a X.509 certificate, the subjectPublicKeyInfo field
has the SubjectPublicKeyInfo type, which has the following ASN.1 syntax.</t>
          <artwork><![CDATA[
SubjectPublicKeyInfo  ::=  SEQUENCE  {
      algorithm         AlgorithmIdentifier,
      subjectPublicKey  BIT STRING
  }

AlgorithmIdentifier{ALGORITHM-TYPE, ALGORITHM-TYPE:AlgorithmSet} ::=
  SEQUENCE {
    algorithm   ALGORITHM-TYPE."&"id({AlgorithmSet}),
    parameters  ALGORITHM-TYPE.
                  "&"Params({AlgorithmSet}{@algorithm}) OPTIONAL
  }
]]></artwork>
          <t>An X-Wing encapsulation key <bcp14>MUST</bcp14> be encoded directly
using the ASN.1 type XWingPublicKey.</t>
          <artwork><![CDATA[
XWingPublicKey ::= OCTET STRING
]]></artwork>
          <t>The X-Wing encapsulation key is mapped to a subjectPublicKey (a
value of type BIT STRING) as follows: the most significant bit of
the OCTET STRING value becomes the most significant bit of the BIT
STRING value, and so on; the least significant bit of the OCTET
STRING becomes the least significant bit of the BIT STRING.</t>
          <t>The id-XWing identifier <bcp14>MUST</bcp14> be used as the algorithm field in
the SubjectPublicKeyInfo to identify an X-Wing encapsulation key.</t>
          <t>The contents of the parameters component <bcp14>MUST</bcp14> be absent.</t>
        </section>
        <section anchor="private-key">
          <name>Private key</name>
          <t>Below we replicate part of the definition of OneAsymmetricKey
from <xref target="RFC5958"/>.</t>
          <artwork><![CDATA[
OneAsymmetricKey ::= SEQUENCE {
  version                  Version,
  privateKeyAlgorithm      SEQUENCE {
  algorithm                PUBLIC-KEY.&id({PublicKeySet}),
  parameters               PUBLIC-KEY.&Params({PublicKeySet}
                             {@privateKeyAlgorithm.algorithm})
                                OPTIONAL}
  privateKey               OCTET STRING (CONTAINING
                             PUBLIC-KEY.&PrivateKey({PublicKeySet}
                               {@privateKeyAlgorithm.algorithm})),
  attributes           [0] Attributes OPTIONAL,
  ...,
  [[2: publicKey       [1] BIT STRING (CONTAINING
                             PUBLIC-KEY.&Params({PublicKeySet}
                               {@privateKeyAlgorithm.algorithm})
                               OPTIONAL,
  ...
}
]]></artwork>
          <t>When storing an X-Wing decapsulation key in a OneAsymmetricKey,
the privateKey OCTET STRING contains the raw octet string encoding
the X-Wing decapsulation key.</t>
          <t>The id-XWing identifier <bcp14>MUST</bcp14> be used as the algorithm field in
the OneAsymmetricKey to identify an X-Wing decapsulation key.</t>
          <t>The publicKey component <bcp14>MUST</bcp14> be absent.</t>
        </section>
      </section>
    </section>
    <section anchor="secc">
      <name>Security Considerations</name>
      <t>Informally, X-Wing is secure if SHA3 is secure, and either X25519 is
secure, or ML-KEM-768 is secure.</t>
      <t>More precisely, if SHA3-256, SHA3-512, and SHAKE-256 may be
modelled as a random oracle, then the IND-CCA security of X-Wing is
bounded by the IND-CCA security of ML-KEM-768, and the gap-CDH security
of Curve25519, see <xref target="PROOF"/>.</t>
      <t>The security of X-Wing relies crucially on the specifics of the
Fujisaki-Okamoto transformation used in ML-KEM-768: the X-Wing
combiner cannot be assumed to be secure, when used with different
KEMs. In particular it is not known to be safe to leave
out the post-quantum ciphertext from the combiner in the general case.</t>
      <section anchor="binding-properties">
        <name>Binding properties</name>
        <t>Some protocols rely on further properties of the KEM.
X-Wing satisfies the binding properties MAL-BIND-K-PK and MAL-BIND-K-CT
(TODO: reference to proof).
This implies <xref target="KSMW"/> X-Wing also satisfies</t>
        <ul spacing="normal">
          <li>
            <t>MAL-BIND-K,CT-PK</t>
          </li>
          <li>
            <t>MAL-BIND-K,PK-CT</t>
          </li>
          <li>
            <t>LEAK-BIND-K-PK</t>
          </li>
          <li>
            <t>LEAK-BIND-K-CT</t>
          </li>
          <li>
            <t>LEAK-BIND-K,CT-PK</t>
          </li>
          <li>
            <t>LEAK-BIND-K,PK-CT</t>
          </li>
          <li>
            <t>HON-BIND-K-PK</t>
          </li>
          <li>
            <t>HON-BIND-K-CT</t>
          </li>
          <li>
            <t>HON-BIND-K,CT-PK</t>
          </li>
          <li>
            <t>HON-BIND-K,PK-CT</t>
          </li>
        </ul>
        <t>In contrast, ML-KEM on its own does not achieve
MAL-BIND-K-PK, MAL-BIND-K-CT, nor MAL-BIND-K,PK-CT. <xref target="SCHMIEG"/></t>
      </section>
    </section>
    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>This document requests/registers a new entry to the "HPKE KEM Identifiers"
registry.</t>
      <dl>
        <dt>Value:</dt>
        <dd>
          <t>25722 = 25519 + 203 = 0x647a (please)</t>
        </dd>
        <dt>KEM:</dt>
        <dd>
          <t>X-Wing</t>
        </dd>
        <dt>Nsecret:</dt>
        <dd>
          <t>32</t>
        </dd>
        <dt>Nenc:</dt>
        <dd>
          <t>1120</t>
        </dd>
        <dt>Npk:</dt>
        <dd>
          <t>1216</t>
        </dd>
        <dt>Nsk:</dt>
        <dd>
          <t>32</t>
        </dd>
        <dt>Auth:</dt>
        <dd>
          <t>no</t>
        </dd>
        <dt>Reference:</dt>
        <dd>
          <t>This document</t>
        </dd>
      </dl>
      <t>Furthermore, this document requests/registers a new entry to the TLS
Named Group (or Supported Group) registry, according to the procedures
in <xref section="6" sectionFormat="of" target="TLSIANA"/>.</t>
      <dl>
        <dt>Value:</dt>
        <dd>
          <t>25722 = 25519 + 203 = 0x647a (please)</t>
        </dd>
        <dt>Description:</dt>
        <dd>
          <t>X-Wing</t>
        </dd>
        <dt>DTLS-OK:</dt>
        <dd>
          <t>Y</t>
        </dd>
        <dt>Recommended:</dt>
        <dd>
          <t>N</t>
        </dd>
        <dt>Reference:</dt>
        <dd>
          <t>This document</t>
        </dd>
        <dt>Comment:</dt>
        <dd>
          <t>PQ/T hybrid of X25519 and ML-KEM-768</t>
        </dd>
      </dl>
    </section>
  </middle>
  <back>
    <references anchor="sec-combined-references">
      <name>References</name>
      <references anchor="sec-normative-references">
        <name>Normative References</name>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner"/>
            <date month="March" year="1997"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba"/>
            <date month="May" year="2017"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="RFC5958">
          <front>
            <title>Asymmetric Key Packages</title>
            <author fullname="S. Turner" initials="S." surname="Turner"/>
            <date month="August" year="2010"/>
            <abstract>
              <t>This document defines the syntax for private-key information and a content type for it. Private-key information includes a private key for a specified public-key algorithm and a set of attributes. The Cryptographic Message Syntax (CMS), as defined in RFC 5652, can be used to digitally sign, digest, authenticate, or encrypt the asymmetric key format content type. This document obsoletes RFC 5208. [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="5958"/>
          <seriesInfo name="DOI" value="10.17487/RFC5958"/>
        </reference>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="I-D.driscoll-pqt-hybrid-terminology">
          <front>
            <title>Terminology for Post-Quantum Traditional Hybrid Schemes</title>
            <author fullname="Florence D" initials="F." surname="D">
              <organization>UK National Cyber Security Centre</organization>
            </author>
            <date day="7" month="March" year="2023"/>
            <abstract>
              <t>   One aspect of the transition to post-quantum algorithms in
   cryptographic protocols is the development of hybrid schemes that
   incorporate both post-quantum and traditional asymmetric algorithms.
   This document defines terminology for such schemes.  It is intended
   to be used as a reference and, hopefully, to ensure consistency and
   clarity across different protocols, standards, and organisations.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-driscoll-pqt-hybrid-terminology-02"/>
        </reference>
        <reference anchor="I-D.ounsworth-cfrg-kem-combiners">
          <front>
            <title>Combiner function for hybrid key encapsulation mechanisms (Hybrid KEMs)</title>
            <author fullname="Mike Ounsworth" initials="M." surname="Ounsworth">
              <organization>Entrust Limited</organization>
            </author>
            <author fullname="Aron Wussler" initials="A." surname="Wussler">
              <organization>Proton AG</organization>
            </author>
            <author fullname="Stavros Kousidis" initials="S." surname="Kousidis">
              <organization>BSI</organization>
            </author>
            <date day="31" month="January" year="2024"/>
            <abstract>
              <t>   The migration to post-quantum cryptography often calls for performing
   multiple key encapsulations in parallel and then combining their
   outputs to derive a single shared secret.

   This document defines a comprehensible and easy to implement Keccak-
   based KEM combiner to join an arbitrary number of key shares, that is
   compatible with NIST SP 800-56Cr2 [SP800-56C] when viewed as a key
   derivation function.  The combiners defined here are practical split-
   key PRFs and are CCA-secure as long as at least one of the ingredient
   KEMs is.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ounsworth-cfrg-kem-combiners-05"/>
        </reference>
        <reference anchor="FIPS202" target="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf">
          <front>
            <title>FIPS 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions</title>
            <author initials="" surname="National Institute of Standards and Technology">
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="MLKEM" target="https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.203.pdf">
          <front>
            <title>FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard</title>
            <author initials="" surname="National Institute of Standards and Technology">
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="RFC9180">
          <front>
            <title>Hybrid Public Key Encryption</title>
            <author fullname="R. Barnes" initials="R." surname="Barnes"/>
            <author fullname="K. Bhargavan" initials="K." surname="Bhargavan"/>
            <author fullname="B. Lipp" initials="B." surname="Lipp"/>
            <author fullname="C. Wood" initials="C." surname="Wood"/>
            <date month="February" year="2022"/>
            <abstract>
              <t>This document describes a scheme for hybrid public key encryption (HPKE). This scheme provides a variant of public key encryption of arbitrary-sized plaintexts for a recipient public key. It also includes three authenticated variants, including one that authenticates possession of a pre-shared key and two optional ones that authenticate possession of a key encapsulation mechanism (KEM) private key. HPKE works for any combination of an asymmetric KEM, key derivation function (KDF), and authenticated encryption with additional data (AEAD) encryption function. Some authenticated variants may not be supported by all KEMs. We provide instantiations of the scheme using widely used and efficient primitives, such as Elliptic Curve Diffie-Hellman (ECDH) key agreement, HMAC-based key derivation function (HKDF), and SHA2.</t>
              <t>This document is a product of the Crypto Forum Research Group (CFRG) in the IRTF.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9180"/>
          <seriesInfo name="DOI" value="10.17487/RFC9180"/>
        </reference>
        <reference anchor="RFC7748">
          <front>
            <title>Elliptic Curves for Security</title>
            <author fullname="A. Langley" initials="A." surname="Langley"/>
            <author fullname="M. Hamburg" initials="M." surname="Hamburg"/>
            <author fullname="S. Turner" initials="S." surname="Turner"/>
            <date month="January" year="2016"/>
            <abstract>
              <t>This memo specifies two elliptic curves over prime fields that offer a high level of practical security in cryptographic applications, including Transport Layer Security (TLS). These curves are intended to operate at the ~128-bit and ~224-bit security level, respectively, and are generated deterministically based on a list of required properties.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="7748"/>
          <seriesInfo name="DOI" value="10.17487/RFC7748"/>
        </reference>
        <reference anchor="HYBRID">
          <front>
            <title>Hybrid key exchange in TLS 1.3</title>
            <author fullname="Douglas Stebila" initials="D." surname="Stebila">
              <organization>University of Waterloo</organization>
            </author>
            <author fullname="Scott Fluhrer" initials="S." surname="Fluhrer">
              <organization>Cisco Systems</organization>
            </author>
            <author fullname="Shay Gueron" initials="S." surname="Gueron">
              <organization>University of Haifa and Amazon Web Services</organization>
            </author>
            <date day="12" month="February" year="2020"/>
            <abstract>
              <t>   Hybrid key exchange refers to using multiple key exchange algorithms
   simultaneously and combining the result with the goal of providing
   security even if all but one of the component algorithms is broken.
   It is motivated by transition to post-quantum cryptography.  This
   document provides a construction for hybrid key exchange in the
   Transport Layer Security (TLS) protocol version 1.3.

   Discussion of this work is encouraged to happen on the TLS IETF
   mailing list tls@ietf.org or on the GitHub repository which contains
   the draft: https://github.com/dstebila/draft-stebila-tls-hybrid-
   design.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-stebila-tls-hybrid-design-03"/>
        </reference>
        <reference anchor="XYBERHPKE">
          <front>
            <title>X25519Kyber768Draft00 hybrid post-quantum KEM for HPKE</title>
            <author fullname="Bas Westerbaan" initials="B." surname="Westerbaan">
              <organization>Cloudflare</organization>
            </author>
            <author fullname="Christopher A. Wood" initials="C. A." surname="Wood">
              <organization>Cloudflare</organization>
            </author>
            <date day="14" month="May" year="2024"/>
            <abstract>
              <t>   This memo defines X25519Kyber768Draft00, a hybrid post-quantum KEM,
   for HPKE (RFC9180).  This KEM does not support the authenticated
   modes of HPKE.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-westerbaan-cfrg-hpke-xyber768d00-03"/>
        </reference>
        <reference anchor="XYBERTLS">
          <front>
            <title>X25519Kyber768Draft00 hybrid post-quantum key agreement</title>
            <author fullname="Bas Westerbaan" initials="B." surname="Westerbaan">
              <organization>Cloudflare</organization>
            </author>
            <author fullname="Douglas Stebila" initials="D." surname="Stebila">
              <organization>University of Waterloo</organization>
            </author>
            <date day="24" month="September" year="2023"/>
            <abstract>
              <t>   This memo defines X25519Kyber768Draft00, a hybrid post-quantum key
   exchange for TLS 1.3.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-tls-westerbaan-xyber768d00-03"/>
        </reference>
        <reference anchor="TLSIANA">
          <front>
            <title>IANA Registry Updates for TLS and DTLS</title>
            <author fullname="Joseph A. Salowey" initials="J. A." surname="Salowey">
              <organization>Venafi</organization>
            </author>
            <author fullname="Sean Turner" initials="S." surname="Turner">
              <organization>sn3rd</organization>
            </author>
            <date day="30" month="April" year="2024"/>
            <abstract>
              <t>   This document updates the changes to TLS and DTLS IANA registries
   made in RFC 8447.  It adds a new value "D" for discouraged to the
   recommended column of the selected TLS registries.

   This document updates the following RFCs: 3749, 5077, 4680, 5246,
   5705, 5878, 6520, 7301, and 8447.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-tls-rfc8447bis-09"/>
        </reference>
        <reference anchor="SCHMIEG" target="https://eprint.iacr.org/2024/523">
          <front>
            <title>Unbindable Kemmy Schmidt: ML-KEM is neither MAL-BIND-K-CT nor MAL-BIND-K-PK</title>
            <author initials="S." surname="Schmieg">
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="KSMW" target="https://eprint.iacr.org/2024/1233">
          <front>
            <title>Binding Security of Implicitly-Rejecting KEMs and Application to BIKE and HQC</title>
            <author initials="J." surname="Kraemer">
              <organization/>
            </author>
            <author initials="P." surname="Struck">
              <organization/>
            </author>
            <author initials="M." surname="Weishaupl">
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="PROOF" target="https://eprint.iacr.org/2024/039">
          <front>
            <title>X-Wing: The Hybrid KEM You’ve Been Looking For</title>
            <author initials="M." surname="Barbosa">
              <organization/>
            </author>
            <author initials="D." surname="Connolly">
              <organization/>
            </author>
            <author initials="J." surname="Duarte">
              <organization/>
            </author>
            <author initials="A." surname="Kaiser">
              <organization/>
            </author>
            <author initials="P." surname="Schwabe">
              <organization/>
            </author>
            <author initials="K." surname="Varner">
              <organization/>
            </author>
            <author initials="B. E." surname="Westerbraan">
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
      </references>
    </references>
    <?line 691?>

<section anchor="implementations">
      <name>Implementations</name>
      <ul spacing="normal">
        <li>
          <t>Go  </t>
          <ul spacing="normal">
            <li>
              <t><eref target="https://github.com/cloudflare/circl/pull/471">CIRCL</eref></t>
            </li>
            <li>
              <t><eref target="https://github.com/FiloSottile/mlkem768">Filippo</eref>      </t>
              <t>
Note: implements the older <tt>-04</tt> version of this memo at the time of
writing.</t>
            </li>
          </ul>
        </li>
        <li>
          <t>Rust  </t>
          <ul spacing="normal">
            <li>
              <t><eref target="https://github.com/rugo/xwing-kem.rs">xwing-kem.rs</eref>      </t>
              <t>
Note: implements the older <tt>-00</tt> version of this memo at the time of
writing.</t>
            </li>
          </ul>
        </li>
      </ul>
    </section>
    <section anchor="S-spec">
      <name>Machine-readable specification</name>
      <t>For the convenience of implementors, we provide a reference specification
in Python. This is a specification; not production ready code:
it should not be deployed as-is, as it leaks the private key by its runtime.</t>
      <section anchor="xwingpy">
        <name>xwing.py</name>
        <artwork><![CDATA[
# WARNING This is a specification of X-Wing; not a production-ready
# implementation. It is slow and does not run in constant time.

# Requires the CryptoDome for SHAKE, and pytest for testing. To install, run
#
#   pip install pycryptodome pytest

import binascii
import hashlib

import mlkem
import x25519

XWingLabel = br"""
                \./
                /^\
              """.replace(b'\n', b'').replace(b' ', b'')

assert len(XWingLabel) == 6
assert binascii.hexlify(XWingLabel) == b'5c2e2f2f5e5c'

def expandDecapsulationKey(seed):
    expanded = hashlib.shake_256(seed).digest(length=96)
    pkM, skM = mlkem.KeyGen(expanded[0:64], mlkem.params768)
    skX = expanded[64:96]
    pkX = x25519.X(skX, x25519.BASE)
    return skM, skX, pkM, pkX

def GenerateKeyPairDerand(seed):
    assert len(seed) == 32
    skM, skX, pkM, pkX = expandDecapsulationKey(seed)
    return seed, pkM + pkX

def Combiner(ssM, ssX, ctX, pkX):
    return hashlib.sha3_256(
        ssM +
        ssX +
        ctX +
        pkX +
        XWingLabel
    ).digest()

def EncapsulateDerand(pk, eseed):
    assert len(eseed) == 64
    assert len(pk) == 1216
    pkM = pk[0:1184]
    pkX = pk[1184:1216]
    ekX = eseed[32:64]
    ctX = x25519.X(ekX, x25519.BASE)
    ssX = x25519.X(ekX, pkX)
    ctM, ssM = mlkem.Enc(pkM, eseed[0:32], mlkem.params768)
    ss = Combiner(ssM, ssX, ctX, pkX)
    return ss, ctM + ctX

def Decapsulate(ct, sk):
    assert len(ct) == 1120
    assert len(sk) == 32
    ctM = ct[0:1088]
    ctX = ct[1088:1120]
    skM, skX, pkM, pkX = expandDecapsulationKey(sk)
    ssM = mlkem.Dec(skM, ctM, mlkem.params768)
    ssX = x25519.X(skX, ctX)
    return Combiner(ssM, ssX, ctX, pkX)
]]></artwork>
      </section>
      <section anchor="x25519py">
        <name>x25519.py</name>
        <artwork><![CDATA[
# WARNING This is a specification of X25519; not a production-ready
# implementation. It is slow and does not run in constant time.

p = 2**255 - 19
a24 = 121665

BASE = b'\x09' + b'\x00'*31

def decode(bs):
    return sum(bs[i] << 8*i for i in range(32)) % p

def decodeScalar(k):
    bs = list(k)
    bs[0] &= 248
    bs[31] &= 127
    bs[31] |= 64
    return decode(bs)

# See rfc7748 §5.
def X(k, u):
    assert len(k) == 32
    assert len(u) == 32

    k = decodeScalar(k)
    u = decode(u)
    x1, x2, x3, z2, z3, swap = u, 1, u, 0, 1, 0

    for t in range(255, -1, -1):
        kt = (k >> t) & 1
        swap ^= kt
        if swap == 1:
            x3, x2 = x2, x3
            z3, z2 = z2, z3
        swap = kt

        A = x2 + z2
        AA = (A*A) % p
        B = x2 - z2
        BB = (B*B) % p
        E = AA - BB
        C = x3 + z3
        D = x3 - z3
        DA = (D*A) % p
        CB = (C*B) % p
        x3 = DA + CB
        x3 = (x3 * x3) % p
        z3 = DA - CB
        z3 = (x1 * z3 * z3) % p
        x2 = (AA * BB) % p
        z2 = (E * (AA + (a24 * E) % p)) % p

    if swap == 1:
        x3, x2 = x2, x3
        z2, z3 = z3, z2

    ret = (x2 * pow(z2, p-2, p)) % p
    return bytes((ret >> 8*i) & 255 for i in range(32))
]]></artwork>
      </section>
      <section anchor="mlkempy">
        <name>mlkem.py</name>
        <artwork><![CDATA[
# WARNING This is a specification of Kyber; not a production ready
# implementation. It is slow and does not run in constant time.

# Requires the CryptoDome for SHAKE. To install, run
#
#   pip install pycryptodome pytest
from Crypto.Hash import SHAKE128, SHAKE256

import io
import hashlib
import functools
import collections

from math import floor

q = 3329
nBits = 8
zeta = 17
eta2 = 2

n = 2**nBits
inv2 = (q+1)//2 # inverse of 2

params = collections.namedtuple('params', ('k', 'du', 'dv', 'eta1'))

params512  = params(k = 2, du = 10, dv = 4, eta1 = 3)
params768  = params(k = 3, du = 10, dv = 4, eta1 = 2)
params1024 = params(k = 4, du = 11, dv = 5, eta1 = 2)

def smod(x):
    r = x % q
    if r > (q-1)//2:
        r -= q
    return r

# Rounds to nearest integer with ties going up
def Round(x):
    return int(floor(x + 0.5))

def Compress(x, d):
    return Round((2**d / q) * x) % (2**d)

def Decompress(y, d):
    assert 0 <= y and y <= 2**d
    return Round((q / 2**d) * y)

def BitsToWords(bs, w):
    assert len(bs) % w == 0
    return [sum(bs[i+j] * 2**j for j in range(w))
            for i in range(0, len(bs), w)]

def WordsToBits(bs, w):
    return sum([[(b >> i) % 2 for i in range(w)] for b in bs], [])

def Encode(a, w):
    return bytes(BitsToWords(WordsToBits(a, w), 8))

def Decode(a, w):
    return BitsToWords(WordsToBits(a, 8), w)

def brv(x):
    """ Reverses a 7-bit number """
    return int(''.join(reversed(bin(x)[2:].zfill(nBits-1))), 2)

class Poly:
    def __init__(self, cs=None):
        self.cs = (0,)*n if cs is None else tuple(cs)
        assert len(self.cs) == n

    def __add__(self, other):
        return Poly((a+b) % q for a,b in zip(self.cs, other.cs))

    def __neg__(self):
        return Poly(q-a for a in self.cs)
    def __sub__(self, other):
        return self + -other

    def __str__(self):
        return f"Poly({self.cs}"

    def __eq__(self, other):
        return self.cs == other.cs

    def NTT(self):
        cs = list(self.cs)
        layer = n // 2
        zi = 0
        while layer >= 2:
            for offset in range(0, n-layer, 2*layer):
                zi += 1
                z = pow(zeta, brv(zi), q)

                for j in range(offset, offset+layer):
                    t = (z * cs[j + layer]) % q
                    cs[j + layer] = (cs[j] - t) % q
                    cs[j] = (cs[j] + t) % q
            layer //= 2
        return Poly(cs)

    def RefNTT(self):
        # Slower, but simpler, version of the NTT.
        cs = [0]*n
        for i in range(0, n, 2):
            for j in range(n // 2):
                z = pow(zeta, (2*brv(i//2)+1)*j, q)
                cs[i] = (cs[i] + self.cs[2*j] * z) % q
                cs[i+1] = (cs[i+1] + self.cs[2*j+1] * z) % q
        return Poly(cs)

    def InvNTT(self):
        cs = list(self.cs)
        layer = 2
        zi = n//2
        while layer < n:
            for offset in range(0, n-layer, 2*layer):
                zi -= 1
                z = pow(zeta, brv(zi), q)

                for j in range(offset, offset+layer):
                    t = (cs[j+layer] - cs[j]) % q
                    cs[j] = (inv2*(cs[j] + cs[j+layer])) % q
                    cs[j+layer] = (inv2 * z * t) % q
            layer *= 2
        return Poly(cs)

    def MulNTT(self, other):
        """ Computes self o other, the multiplication of self and other
            in the NTT domain. """
        cs = [None]*n
        for i in range(0, n, 2):
            a1 = self.cs[i]
            a2 = self.cs[i+1]
            b1 = other.cs[i]
            b2 = other.cs[i+1]
            z = pow(zeta, 2*brv(i//2)+1, q)
            cs[i] = (a1 * b1 + z * a2 * b2) % q
            cs[i+1] = (a2 * b1 + a1 * b2) % q
        return Poly(cs)

    def Compress(self, d):
        return Poly(Compress(c, d) for c in self.cs)

    def Decompress(self, d):
        return Poly(Decompress(c, d) for c in self.cs)

    def Encode(self, d):
        return Encode(self.cs, d)

def sampleUniform(stream):
    cs = []
    while True:
        b = stream.read(3)
        d1 = b[0] + 256*(b[1] % 16)
        d2 = (b[1] >> 4) + 16*b[2]
        assert d1 + 2**12 * d2 == b[0] + 2**8 * b[1] + 2**16*b[2]
        for d in [d1, d2]:
            if d >= q:
                continue
            cs.append(d)
            if len(cs) == n:
                return Poly(cs)

def CBD(a, eta):
    assert len(a) == 64*eta
    b = WordsToBits(a, 8)
    cs = []
    for i in range(n):
        cs.append((sum(b[:eta]) - sum(b[eta:2*eta])) % q)
        b = b[2*eta:]
    return Poly(cs)

def XOF(seed, j, i):
    h = SHAKE128.new()
    h.update(seed + bytes([j, i]))
    return h

def PRF1(seed, nonce):
    assert len(seed) == 32
    h = SHAKE256.new()
    h.update(seed + bytes([nonce]))
    return h

def PRF2(seed, msg):
    assert len(seed) == 32
    h = SHAKE256.new()
    h.update(seed + msg)
    return h.read(32)

def G(seed):
    h = hashlib.sha3_512(seed).digest()
    return h[:32], h[32:]

def H(msg): return hashlib.sha3_256(msg).digest()

class Vec:
    def __init__(self, ps):
        self.ps = tuple(ps)

    def NTT(self):
        return Vec(p.NTT() for p in self.ps)

    def InvNTT(self):
        return Vec(p.InvNTT() for p in self.ps)

    def DotNTT(self, other):
        """ Computes the dot product <self, other> in NTT domain. """
        return sum((a.MulNTT(b) for a, b in zip(self.ps, other.ps)),
                   Poly())

    def __add__(self, other):
        return Vec(a+b for a,b in zip(self.ps, other.ps))

    def Compress(self, d):
        return Vec(p.Compress(d) for p in self.ps)

    def Decompress(self, d):
        return Vec(p.Decompress(d) for p in self.ps)

    def Encode(self, d):
        return Encode(sum((p.cs for p in self.ps), ()), d)

    def __eq__(self, other):
        return self.ps == other.ps

def EncodeVec(vec, w):
    return Encode(sum([p.cs for p in vec.ps], ()), w)
def DecodeVec(bs, k, w):
    cs = Decode(bs, w)
    return Vec(Poly(cs[n*i:n*(i+1)]) for i in range(k))
def DecodePoly(bs, w):
    return Poly(Decode(bs, w))

class Matrix:
    def __init__(self, cs):
        """ Samples the matrix uniformly from seed rho """
        self.cs = tuple(tuple(row) for row in cs)

    def MulNTT(self, vec):
        """ Computes matrix multiplication A*vec in the NTT domain. """
        return Vec(Vec(row).DotNTT(vec) for row in self.cs)

    def T(self):
        """ Returns transpose of matrix """
        k = len(self.cs)
        return Matrix((self.cs[j][i] for j in range(k))
                      for i in range(k))

def sampleMatrix(rho, k):
    return Matrix([[sampleUniform(XOF(rho, j, i))
            for j in range(k)] for i in range(k)])

def sampleNoise(sigma, eta, offset, k):
    return Vec(CBD(PRF1(sigma, i+offset).read(64*eta), eta)
               for i in range(k))

def constantTimeSelectOnEquality(a, b, ifEq, ifNeq):
    # WARNING! In production code this must be done in a
    # data-independent constant-time manner, which this implementation
    # is not. In fact, many more lines of code in this
    # file are not constant-time.
    return ifEq if a == b else ifNeq

def InnerKeyGen(seed, params):
    assert len(seed) == 32
    rho, sigma = G(seed + bytes([params.k]))
    A = sampleMatrix(rho, params.k)
    s = sampleNoise(sigma, params.eta1, 0, params.k)
    e = sampleNoise(sigma, params.eta1, params.k, params.k)
    sHat = s.NTT()
    eHat = e.NTT()
    tHat = A.MulNTT(sHat) + eHat
    pk = EncodeVec(tHat, 12) + rho
    sk = EncodeVec(sHat, 12)
    return (pk, sk)

def InnerEnc(pk, msg, seed, params):
    assert len(msg) == 32
    tHat = DecodeVec(pk[:-32], params.k, 12)
    if EncodeVec(tHat, 12) != pk[:-32]:
        raise Exception("ML-KEM public key not normalized")
    rho = pk[-32:]
    A = sampleMatrix(rho, params.k)
    r = sampleNoise(seed, params.eta1, 0, params.k)
    e1 = sampleNoise(seed, eta2, params.k, params.k)
    e2 = sampleNoise(seed, eta2, 2*params.k, 1).ps[0]
    rHat = r.NTT()
    u = A.T().MulNTT(rHat).InvNTT() + e1
    m = Poly(Decode(msg, 1)).Decompress(1)
    v = tHat.DotNTT(rHat).InvNTT() + e2 + m
    c1 = u.Compress(params.du).Encode(params.du)
    c2 = v.Compress(params.dv).Encode(params.dv)
    return c1 + c2

def InnerDec(sk, ct, params):
    split = params.du * params.k * n // 8
    c1, c2 = ct[:split], ct[split:]
    u = DecodeVec(c1, params.k, params.du).Decompress(params.du)
    v = DecodePoly(c2, params.dv).Decompress(params.dv)
    sHat = DecodeVec(sk, params.k, 12)
    return (v - sHat.DotNTT(u.NTT()).InvNTT()).Compress(1).Encode(1)

def KeyGen(seed, params):
    assert len(seed) == 64
    z = seed[32:]
    pk, sk2 = InnerKeyGen(seed[:32], params)
    h = H(pk)
    return (pk, sk2 + pk + h + z)

def Enc(pk, seed, params):
    assert len(seed) == 32

    K, r = G(seed + H(pk))
    ct = InnerEnc(pk, seed, r, params)
    return (ct, K)

def Dec(sk, ct, params):
    sk2 = sk[:12 * params.k * n//8]
    pk = sk[12 * params.k * n//8 : 24 * params.k * n//8 + 32]
    h = sk[24 * params.k * n//8 + 32 : 24 * params.k * n//8 + 64]
    z = sk[24 * params.k * n//8 + 64 : 24 * params.k * n//8 + 96]
    m2 = InnerDec(sk, ct, params)
    K2, r2 = G(m2 + h)
    ct2 = InnerEnc(pk, m2, r2, params)
    return constantTimeSelectOnEquality(
        ct2, ct,
        K2,                 # if ct == ct2
        PRF2(z, ct),        # if ct != ct2
    )
]]></artwork>
      </section>
    </section>
    <section anchor="test-vectors-todo-replace-with-test-vectors-that-re-use-ml-kem-x25519-values">
      <name>Test vectors # TODO: replace with test vectors that re-use ML-KEM, X25519 values</name>
      <artwork><![CDATA[
seed     7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26
sk     7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26
pk
  e2236b35a8c24b39b10aa1323a96a919a2ced88400633a7b07131713fc14b2b5b19cfc3d
  a5fa1a92c49f25513e0fd30d6b1611c9ab9635d7086727a4b7d21d34244e66969cf15b3b
  2a785329f61b096b277ea037383479a6b556de7231fe4b7fa9c9ac24c0699a0018a52534
  01bacfa905ca816573e56a2d2e067e9b7287533ba13a937dedb31fa44baced4076992361
  0034ae31e619a170245199b3c5c39864859fe1b4c9717a07c30495bdfb98a0a002ccf56c
  1286cef5041dede3c44cf16bf562c7448518026b3d8b9940680abd38a1575fd27b58da06
  3bfac32c39c30869374c05c1aeb1898b6b303cc68be455346ee0af699636224a148ca2ae
  a10463111c709f69b69c70ce8538746698c4c60a9aef0030c7924ceec42a5d36816f545e
  ae13293460b3acb37ea0e13d70e4aa78686da398a8397c08eaf96882113fe4f7bad4da40
  b0501e1c753efe73053c87014e8661c33099afe8bede414a5b1aa27d8392b3e131e9a70c
  1055878240cad0f40d5fe3cdf85236ead97e2a97448363b2808caafd516cd25052c5c362
  543c2517e4acd0e60ec07163009b6425fc32277acee71c24bab53ed9f29e74c66a0a3564
  955998d76b96a9a8b50d1635a4d7a67eb42df5644d330457293a8042f53cc7a69288f17e
  d55827e82b28e82665a86a14fbd96645eca8172c044f83bc0d8c0b4c8626985631ca87af
  829068f1358963cb333664ca482763ba3b3bb208577f9ba6ac62c25f76592743b64be519
  317714cb4102cb7b2f9a25b2b4f0615de31decd9ca55026d6da0b65111b16fe52feed8a4
  87e144462a6dba93728f500b6ffc49e515569ef25fed17aff520507368253525860f58be
  3be61c964604a6ac814e6935596402a520a4670b3d284318866593d15a4bb01c35e3e587
  ee0c67d2880d6f2407fb7a70712b838deb96c5d7bf2b44bcf6038ccbe33fbcf51a54a584
  fe90083c91c7a6d43d4fb15f48c60c2fd66e0a8aad4ad64e5c42bb8877c0ebec2b5e387c
  8a988fdc23beb9e16c8757781e0a1499c61e138c21f216c29d076979871caa6942bafc09
  0544bee99b54b16cb9a9a364d6246d9f42cce53c66b59c45c8f9ae9299a75d15180c3c95
  2151a91b7a10772429dc4cbae6fcc622fa8018c63439f890630b9928db6bb7f9438ae406
  5ed34d73d486f3f52f90f0807dc88dfdd8c728e954f1ac35c06c000ce41a0582580e3bb5
  7b672972890ac5e7988e7850657116f1b57d0809aaedec0bede1ae148148311c6f7e3173
  46e5189fb8cd635b986f8c0bdd27641c584b778b3a911a80be1c9692ab8e1bbb12839573
  cce19df183b45835bbb55052f9fc66a1678ef2a36dea78411e6c8d60501b4e60592d1369
  8a943b509185db912e2ea10be06171236b327c71716094c964a68b03377f513a05bcd99c
  1f346583bb052977a10a12adfc758034e5617da4c1276585e5774e1f3b9978b09d0e9c44
  d3bc86151c43aad185712717340223ac381d21150a04294e97bb13bbda21b5a182b6da96
  9e19a7fd072737fa8e880a53c2428e3d049b7d2197405296ddb361912a7bcf4827ced611
  d0c7a7da104dde4322095339f64a61d5bb108ff0bf4d780cae509fb22c256914193ff734
  9042581237d522828824ee3bdfd07fb03f1f942d2ea179fe722f06cc03de5b69859edb06
  eff389b27dce59844570216223593d4ba32d9abac8cd049040ef6534
eseed
  3cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e235b8cc87
  3c23dc62b8d260169afa2f75ab916a58d974918835d25e6a435085b2
ct
  b83aa828d4d62b9a83ceffe1d3d3bb1ef31264643c070c5798927e41fb07914a273f8f96
  e7826cd5375a283d7da885304c5de0516a0f0654243dc5b97f8bfeb831f68251219aabdd
  723bc6512041acbaef8af44265524942b902e68ffd23221cda70b1b55d776a92d1143ea3
  a0c475f63ee6890157c7116dae3f62bf72f60acd2bb8cc31ce2ba0de364f52b8ed38c79d
  719715963a5dd3842d8e8b43ab704e4759b5327bf027c63c8fa857c4908d5a8a7b88ac7f
  2be394d93c3706ddd4e698cc6ce370101f4d0213254238b4a2e8821b6e414a1cf20f6c12
  44b699046f5a01caa0a1a55516300b40d2048c77cc73afba79afeea9d2c0118bdf2adb88
  70dc328c5516cc45b1a2058141039e2c90a110a9e16b318dfb53bd49a126d6b73f215787
  517b8917cc01cabd107d06859854ee8b4f9861c226d3764c87339ab16c3667d2f49384e5
  5456dd40414b70a6af841585f4c90c68725d57704ee8ee7ce6e2f9be582dbee985e038ff
  c346ebfb4e22158b6c84374a9ab4a44e1f91de5aac5197f89bc5e5442f51f9a5937b102b
  a3beaebf6e1c58380a4a5fedce4a4e5026f88f528f59ffd2db41752b3a3d90efabe46389
  9b7d40870c530c8841e8712b733668ed033adbfafb2d49d37a44d4064e5863eb0af0a08d
  47b3cc888373bc05f7a33b841bc2587c57eb69554e8a3767b7506917b6b70498727f16ea
  c1a36ec8d8cfaf751549f2277db277e8a55a9a5106b23a0206b4721fa9b3048552c5bd5b
  594d6e247f38c18c591aea7f56249c72ce7b117afcc3a8621582f9cf71787e183dee0936
  7976e98409ad9217a497df888042384d7707a6b78f5f7fb8409e3b535175373461b77600
  2d799cbad62860be70573ecbe13b246e0da7e93a52168e0fb6a9756b895ef7f0147a0dc8
  1bfa644b088a9228160c0f9acf1379a2941cd28c06ebc80e44e17aa2f8177010afd78a97
  ce0868d1629ebb294c5151812c583daeb88685220f4da9118112e07041fcc24d5564a99f
  dbde28869fe0722387d7a9a4d16e1cc8555917e09944aa5ebaaaec2cf62693afad42a3f5
  18fce67d273cc6c9fb5472b380e8573ec7de06a3ba2fd5f931d725b493026cb0acbd3fe6
  2d00e4c790d965d7a03a3c0b4222ba8c2a9a16e2ac658f572ae0e746eafc4feba023576f
  08942278a041fb82a70a595d5bacbf297ce2029898a71e5c3b0d1c6228b485b1ade509b3
  5fbca7eca97b2132e7cb6bc465375146b7dceac969308ac0c2ac89e7863eb8943015b243
  14cafb9c7c0e85fe543d56658c213632599efabfc1ec49dd8c88547bb2cc40c9d38cbd30
  99b4547840560531d0188cd1e9c23a0ebee0a03d5577d66b1d2bcb4baaf21cc7fef1e038
  06ca96299df0dfbc56e1b2b43e4fc20c37f834c4af62127e7dae86c3c25a2f696ac8b589
  dec71d595bfbe94b5ed4bc07d800b330796fda89edb77be0294136139354eb8cd3759157
  8f9c600dd9be8ec6219fdd507adf3397ed4d68707b8d13b24ce4cd8fb22851bfe9d63240
  7f31ed6f7cb1600de56f17576740ce2a32fc5145030145cfb97e63e0e41d354274a079d3
  e6fb2e15
ss     d2df0522128f09dd8e2c92b1e905c793d8f57a54c3da25861f10bf4ca613e384

seed     badfd6dfaac359a5efbb7bcc4b59d538df9a04302e10c8bc1cbf1a0b3a5120ea
sk     badfd6dfaac359a5efbb7bcc4b59d538df9a04302e10c8bc1cbf1a0b3a5120ea
pk
  0333285fa253661508c9fb444852caa4061636cb060e69943b431400134ae1fbc0228724
  7cb38068bbb89e6714af10a3fcda6613acc4b5e4b0d6eb960c302a0253b1f507b596f088
  4d351da89b01c35543214c8e542390b2bc497967961ef10286879c34316e6483b644fc27
  e8019d73024ba1d1cc83650bb068a5431b33d1221b3d122dc1239010a55cb13782140893
  f30aca7c09380255a0c621602ffbb6a9db064c1406d12723ab3bbe2950a21fe521b160b3
  0b16724cc359754b4c88342651333ea9412d5137791cf75558ebc5c54c520dd6c622a059
  f6b332ccebb9f24103e59a297cd69e4a48a3bfe53a5958559e840db5c023f66c10ce2308
  1c2c8261d744799ba078285cfa71ac51f44708d0a6212c3993340724b3ac38f63e82a889
  a4fc581f6b8353cc6233ac8f5394b6cca292f892360570a3031c90c4da3f02a895677390
  e60c24684a405f69ccf1a7b95312a47c844a4f9c2c4a37696dc10072a87bf41a2717d45b
  2a99ce09a4898d5a3f6b67085f9a626646bcf369982d483972b9cd7d244c4f49970f766a
  22507925eca7df99a491d80c27723e84c7b49b633a46b46785a16a41e02c538251622117
  364615d9c2cdaa1687a860c18bfc9ce8690efb2a524cb97cdfd1a4ea661fa7d08817998a
  f838679b07c9db8455e2167a67c14d6a347522e89e8971270bec858364b1c1023b82c483
  cf8a8b76f040fe41c24dec2d49f6376170660605b80383391c4abad1136d874a77ef73b4
  40758b6e7059add20873192e6e372e069c22c5425188e5c240cb3a6e29197ad17e87ec41
  a813af68531f262a6db25bbdb8a15d2ed9c9f35b9f2063890bd26ef09426f225aa1e6008
  d31600a29bcdf3b10d0bc72788d35e25f4976b3ca6ac7cbf0b442ae399b225d9714d0638
  a864bda7018d3b7c793bd2ace6ac68f4284d10977cc029cf203c5698f15a06b162d6c8b4
  fd40c6af40824f9c6101bb94e9327869ab7efd835dfc805367160d6c8571e3643ac70cba
  d5b96a1ad99352793f5af71705f95126cb4787392e94d808491a2245064ba5a7a30c0663
  01392a6c315336e10dbc9c2177c7af382765b6c88eeab51588d01d6a95747f3652dc5b5c
  401a23863c7a0343737c737c99287a40a90896d4594730b552b910d23244684206f0eb84
  2fb9aa316ab182282a75fb72b6806cea4774b822169c386a58773c3edc8229d85905abb8
  7ac228f0f7a2ce9a497bb5325e17a6a82777a997c036c3b862d29c14682ad325a9600872
  f3913029a1588648ba590a7157809ff740b5138380015c40e9fb90f0311107946f28e596
  2e21666ad65092a3a60480cd16e61ff7fb5b44b70cf12201878428ef8067fceb1e1dcb49
  d66c773d312c7e53238cb620e126187009472d41036b702032411dc96cb750631df9d994
  52e495deb4300df660c8d35f32b424e98c7ed14b12d8ab11a289ac63c50a24d52925950e
  49ba6bf4c2c38953c92d60b6cd034e575c711ac41bfa66951f62b9392828d7b45aed377a
  c69c35f1c6b80f388f34e0bb9ce8167eb2bc630382825c396a407e905108081b444ac8a0
  7c2507376a750d18248ee0a81c4318d9a38fc44c3b41e8681f87c34138442659512c4127
  6e1cc8fc4eb66e12727bcb5a9e0e405cdea21538d6ea885ab169050e6b91e1b69f7ed34b
  cbb48fd4c562a576549f85b528c953926d96ea8a160b8843f1c89c62
eseed
  17cda7cfad765f5623474d368ccca8af0007cd9f5e4c849f167a580b14aabdefaee7eef4
  7cb0fca9767be1fda69419dfb927e9df07348b196691abaeb580b32d
ct
  c93beb22326705699bbc3d1d0aa6339be7a405debe61a7c337e1a91453c097a6f77c1306
  39d1aaeb193175f1a987aa1fd789a63c9cd487ebd6965f5d8389c8d7c8cfacbba4b44d2f
  be0ae84de9e96fb11215d9b76acd51887b752329c1a3e0468ccc49392c1e0f1aad61a73c
  10831e60a9798cb2e7ec07596b5803db3e243ecbb94166feade0c9197378700f8eb65a43
  502bbac4605992e2de2b906ab30ba401d7e1ff3c98f42cfc4b30b974d3316f331461ac05
  f43e0db7b41d3da702a4f567b6ee7295199c7be92f6b4a47e7307d34278e03c872fb4864
  7c446a64a3937dccd7c6d8de4d34b9dea45a0b065ef15b9e94d1b6df6dca7174d9bc9d14
  c6225e3a78a58785c3fe4e2fe6a0706f3365389e4258fbb61ecf1a1957715982b3f18444
  24e03acd83da7eee50573f6cd3ff396841e9a00ad679da92274129da277833d0524674fe
  ea09a98d25b888616f338412d8e65e151e65736c8c6fb448c9260fa20e7b2712148bcd3a
  0853865f50c1fc9e4f201aee3757120e034fd509d954b7a749ff776561382c4cb64cebcb
  b6aa82d04cd5c2b40395ecaf231bde8334ecfd955d09efa8c6e7935b1cb0298fb8b6740b
  e4593360eed5f129d59d98822a6cea37c57674e919e84d6b90f695fca58e7d29092bd70f
  7c97c6dfb021b9f87216a6271d8b144a364d03b6bf084f972dc59800b14a2c008bbd0992
  b5b82801020978f2bdddb3ca3367d876cffb3548dab695a29882cae2eb5ba7c847c3c71b
  d0150fa9c33aac8e6240e0c269b8e295ddb7b77e9c17bd310be65e28c0802136d086777b
  e5652d6f1ac879d3263e9c712d1af736eac048fe848a577d6afaea1428dc71db8c430edd
  7b584ae6e6aeaf7257aff0fd8fe25c30840e30ccfa1d95118ef0f6657367e9070f3d97a2
  e9a7bae19957bd707b00e31b6b0ebb9d7df4bd22e44c060830a194b5b8288353255b5295
  4ff5905ab2b126d9aa049e44599368c27d6cb033eae5182c2e1504ee4e3745f51488997b
  8f958f0209064f6f44a7e4de5226d5594d1ad9b42ac59a2d100a2f190df873a2e141552f
  33c923b4c927e8747c6f830c441a8bd3c5b371f6b3ab8103ebcfb18543aefc1beb6f776b
  bfd5344779f4aa23daaf395f69ec31dc046b491f0e5cc9c651dfc306bd8f2105be7bc7a4
  f4e21957f87278c771528a8740a92e2daefa76a3525f1fae17ec4362a2700988001d8600
  11d6ca3a95f79a0205bcf634cef373a8ea273ff0f4250eb8617d0fb92102a6aa09cf0c3e
  e2cad1ad96438c8e4dfd6ee0fcc85833c3103dd6c1600cd305bc2df4cda89b55ca237a3f
  9c3f82390074ff30825fc750130ebaf13d0cf7556d2c52a98a4bad39ca5d44aaadeaef77
  5c695e64d06e966acfcd552a14e2df6c63ae541f0fa88fc48263089685704506a21a0385
  6ce65d4f06d54f3157eeabd62491cb4ac7bf029e79f9fbd4c77e2a3588790c710e611da8
  b2040c76a61507a8020758dcc30894ad018fef98e401cc54106e20d94bd544a8f0e1fd05
  00342d123f618aa8c91bdf6e0e03200693c9651e469aee6f91c98bea4127ae66312f4ae3
  ea155b67
ss     f2e86241c64d60f6649fbc6c5b7d17180b780a3f34355e64a85749949c45f150

seed     ef58538b8d23f87732ea63b02b4fa0f4873360e2841928cd60dd4cee8cc0d4c9
sk     ef58538b8d23f87732ea63b02b4fa0f4873360e2841928cd60dd4cee8cc0d4c9
pk
  36244278824f77c621c660892c1c3886a9560caa52a97c461fd3958a598e749bbc8c7798
  ac8870bac7318ac2b863000ca3b0bdcbbc1ccfcb1a30875df9a76976763247083e646ccb
  2499a4e4f0c9f4125378ba3da1999538b86f99f2328332c177d1192b849413e655101289
  73f679d23253850bb6c347ba7ca81b5e6ac4c574565c731740b3cd8c9756caac39fba7ac
  422acc60c6c1a645b94e3b6d21485ebad9c4fe5bb4ea0853670c5246652bff65ce8381cb
  473c40c1a0cd06b54dcec11872b351397c0eaf995bebdb6573000cbe2496600ba76c8cb0
  23ec260f0571e3ec12a9c82d9db3c57b3a99e8701f78db4fabc1cc58b1bae02745073a81
  fc8045439ba3b885581a283a1ba64e103610aabb4ddfe9959e7241011b2638b56ba6a982
  ef610c514a57212555db9a98fb6bcf0e91660ec15dfa66a67408596e9ccb97489a09a073
  ffd1a0a7ebbe71aa5ff793cb91964160703b4b6c9c5390842c2c905d4a9f88111fed5787
  4ba9b03cf611e70486edf539767c7485189d5f1b08e32a274dc24a39c918fd2a4dfa946a
  8c897486f2c974031b2804aabc81749db430b85311372a3b8478868200b40e043f7bf4a1
  c3a08b0771b431e342ee277410bca034a0c77086c8f702b3aed2b4108bbd3af471633373
  a1ac74b128b148d1b9412aa66948cac6dc6614681fda02ca86675d2a756003c49c50f06e
  13c63ce4bc9f321c860b202ee931834930011f485c9af86b9f642f0c353ad305c66996b9
  a136b753973929495f0d8048db75529edcb4935904797ac66605490f66329c3bb36b8573
  a3e00f817b3082162ff106674d11b261baae0506cde7e69fdce93c6c7b59b9d4c759758a
  cf287c2e4c4bfab5170a9236daf21bdb6005e92464ee8863f845cf37978ef19969264a51
  6fe992c93b5f7ae7cb6718ac69257d630379e4aac6029cb906f98d91c92d118c36a6d161
  15d4c8f16066078badd161a65ba51e0252bc358c67cd2c4beab2537e42956e08a39cfccf
  0cd875b5499ee952c83a162c68084f6d35cf92f71ec66baec74ab87e2243160b64df54af
  b5a07f78ec0f5c5759e5a4322bca2643425748a1a97c62108510c44fd9089c5a7c14e57b
  1b77532800013027cff91922d7c935b4202bb507aa47598a6a5a030117210d4c49c17470
  0550ad6f82ad40e965598b86bc575448eb19d70380d465c1f870824c026d74a2522a799b
  7b122d06c83aa64c0974635897261433914fdfb14106c230425a83dc8467ad8234f086c7
  2a47418be9cfb582b1dcfa3d9aa45299b79fff265356d8286a1ca2f3c2184b2a70d15289
  e5b202d03b64c735a867b1154c55533ff61d6c296277011848143bc85a4b823040ae025a
  29293ab77747d85310078682e0ba0ac236548d905a79494324574d417c7a3457bd5fb525
  3c4876679034ae844d0d05010fec722db5621e3a67a2d58e2ff33b432269169b51f9dcc0
  95b8406dc1864cf0aeb6a2132661a38d641877594b3c51892b9364d25c63d637140a2018
  d10931b0daa5a2f2a405017688c991e586b522f94b1132bc7e87a63246475816c8be9c62
  b731691ab912eb656ce2619225663364701a014b7d0337212caa2ecc731f34438289e0ca
  4590a276802d980056b5d0d316cae2ecfea6d86696a9f161aa90ad47eaad8cadd31ae3cb
  c1c013747dfee80fb35b5299f555dcc2b787ea4f6f16ffdf66952461
eseed
  22a96188d032675c8ac850933c7aff1533b94c834adbb69c6115bad4692d8619f90b0cdf
  8a7b9c264029ac185b70b83f2801f2f4b3f70c593ea3aeeb613a7f1b
ct
  0d2e38cbf17a2e2e4e0c87a94ca1e7701ae1552e02509b3b00f9c82c39e3fd435b05b912
  75f47abc9f1021429a26a346598cd6cd9efdc8adc1dbc35036d0290bf89733c835309202
  232f9bf652ea82f3d49280d6e8a3bd3135fb883445ab5b074d949c5350c7c7d6ac59905b
  dbfce6639da8a9d4b390ecc1dd05522d2956f2d37a05593996e5cb3fd8d5a9eb52417732
  e1ebf545588713b4760227115aab7ada178dadbca583b26cfedba2888a0c95b950bf07f7
  50d7aa8103798aa3470a042c0105c6a037de2f9ebc396021b2ba2c16aba696fbac3454dc
  8e053b8fa55edd45215eeb57a1eab9106fb426b375a9b9e5c3419efc7610977e72640f9f
  d1b2ec337de33c35e5a7581b2aae4d8ee86d2e0ebf82a1350714de50d2d788687878a196
  44ae4e3175e8d59dc90171b3badeff65aeaf600e5e5483a3595fdeb40cbafcbd040c29a2
  f6900533ae999d24f54dfcef748c30313ca447cdddfa57ad78eaa890e90f3f7bf8d11696
  8a5713cc75fd0408f36364fa265c5617039304eaeac4cbee6fc49b9fe2276768cdbec2d7
  3a507b543cc028dc1b154b7c2b0412254c466a94a8d6ea3a47e1743469bd45c08f54cf96
  5884be3696e961741ede16e3b1bc4feb93faaef31d911dc0cb3fa90bcda991959a9d2cbc
  817a5564c5c01177a59e9577589ea344d60cf5b0aa39f31863febd54603ca87ad2363c76
  6642a3f52557bcd9e4c05a87665842ba336b83156a677030f0bad531a8387a1486a599ca
  a748fcea7bdc1eb63f3cdb97173551ab7c1c36b69acbbdb2ff7a1e7bc70439632ddc67b9
  7f3da1f59b3c1588515957cb8a2f86ab635ce0a78b7cdf24eac3445e8fc8b79ba04da9e9
  03f49a7d912c197a84b4cfabc779b97d24788419bcf58035db99717edb9fd1c1df8c4005
  f700eabba528ddfcbaeda6dd30754f795948a34c9319ab653524b19931c7900c4167988a
  f52292fe902e746b524d20ceffb4339e8f5535f41cf35f0f8ea8b4a7b949c5d2381116b1
  46e9b913a83a3fa1c65ff9468c835fe4114554a6c66a80e1c9a6bb064b380be3c95e5595
  ec979bf1c85aa938938e3f10e72b0c87811969e8ab0d83de0b0604c4016ac3a015e19514
  089271bdc6ebf2ec56fab6018e44de749b4c36cc235e370da8466dbdc253542a2d704eb3
  316fd70d5d238cb7eaaf05966d973f62c7ef43b9a806f4ed213ac8099ea15d61a9024441
  60883f6bf441a3e1469945c9b79489ea18390f1ebc83caca10bdb8f2429877b52bd44c94
  a228ef91c392ef5398c5c83982701318ccedab92f7a279c4fddebaa7fe5e986c48b7d813
  5b3fe4cd15be2004ce73ff86b1e55f8ecd6ba5b8114315f8e716ef3ab0a64564a4644651
  166ebd68b1f783e2e443dbccadfe189368647629f1a12215840b7f1d026de2f665c2eb02
  3ff51a6df160912811ee03444ae4227fb941dc9ec4f31b445006fd384de5e60e0a5061b5
  0cb1202f863090fc05eb814e2d42a03586c0b56f533847ac7b8184ce9690bc8dece32a88
  ca934f541d4cc520fa64de6b6e1c3c8e03db5971a445992227c825590688d203523f5271
  61137334
ss     953f7f4e8c5b5049bdc771d1dffada0dd961477d1a2ae0988baa7ea6898d893f

]]></artwork>
    </section>
    <section anchor="example-of-use-in-x509">
      <name>Example of use in X.509</name>
      <t>The following are the encodings of the X-Wing keypair with private key  <tt>0001…1f</tt>.</t>
      <artwork><![CDATA[
-----BEGIN X-WING PRIVATE KEY-----
MDQCAQAwDQYLKwYBBAGD5i2ByHoEIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
GhscHR4f
-----END X-WING PRIVATE KEY-----
]]></artwork>
      <artwork><![CDATA[
-----BEGIN PUBLIC KEY-----
MIIE1DANBgsrBgEEAYPmLYHIegOCBMEAb1QJigoOZBFGYUtpYLpg2GA9YvRH+atJ
m0e9aQbMQLBh2GNKPoiQbyhJWOdEHKbHJcu5cJW3ZxpGK2aByeZYC7yNYLFJ+mAm
EEOvu6UvIFpgKDhIUVlq3zcavqmNM0c4PSu2c0OPZ4NhK/hwFPe5Gol0AmU0XfZ5
NARz0cTBdohuXim48Fi7fHNTFmhs/1w764wmHLAJcKacGvzFS5TLhuHOY7pjbjlc
pFEB4hx70EwxPqGa8kFB79KtREFqJbpPZZEO99iAnDCT8EqvAOPNluNcSqPIAsGK
1vOdpLS42YyL15Atg6B7pFOWZ0pgJDyrk+gP2bHId3N2qcwNb6EV4mOTgLnGvnhI
vRNYjGRwOgU10ZoPgWM6l2oKEFtm7ihdD9JV6CwDMZJfQ4O278dh72CZI1oLmHJj
WKqdAbi4llGfkhR0u3wUuyIlK1wvENQSRsmyPnZEhJNn9UGhX2O8koo5u3vHPwe2
ZcSWu2VYyPRUiacuxLrNNOnFlMM4cbcj8DSV6ItDkasm5DBD3rYRezkZ5FxMGxar
KOR93XI2Y4VHZhkvwYBspwq7eGy9swky5oyKNwvPsHmDoBLDJmuT76YmV/S4ODdM
sLuV4OwGVBsHZdmc8VO8a5YTXKeApVs2R3ieMZFeRig8+ce7boRT+2aCEFFB8dwN
ANhe7XA7bGyWH3nIRSdrQkiUnAZ4LlE+spkbldlgQuOMvto1JEmytQhOvaUiamIG
QAeJEwowlkSYSLYp/upKLCp0PEoN3Jyz89Z2/FY3MbJsShpm3IRZFwBW1XaX8UQ7
gamjRBK7e/BfMydXWlkR3TAdYFOGfzwwgHEfG/EVh7C7KYQnayaF53ViEOSz+JVT
hCMeVYxvUQyR4PxWtdGIX/KUnpWka8G+4fpx9QJ+EMRDsOkdD9dED0Z6JyISEuiP
XGumQpbK4NIHv8YPiMfPtcRaoYOdGMs3xFhD5UJqSpDIArZCj5U8NZxKwGA0UvrA
tzYeL9NdzIhakhRdT8oBWPG31wtLzRGOSipBVEON8xDESpobmepBWQcmeoiwYkJB
V5wXIvRu1hwuPspUXJlwUXF1OZuADbJdo5WT0GSQ1xQsAOiNLbBH6YmL23rLftkH
9uMEFswN5UokLAohJjAvXVTIW8Zqwvg8eXlFtQZ8qkK9LgwZypdQblB6sKXJ9WM3
CEmcGfJK7FE705A6XXO27EmR98cuuZHBw3iJgFyx6jigzAIXayfFjWOM5aMmaEV8
+bm+AnygIUBXlxcl1UEC6JlnFusq2CNFO2BbhVNwsbIbOTLN7UFgqplzx+uuWsR2
TZTPfMlQbwd7rXMBLbtKyBQKOHRkEuszyVFFliBfcHY1hiIX2bYJGMYmjZNEkVuE
eiR2waJw8VSlyEI0FlrPyGk5hwLOqemgfnsOmeqb3LeEH+nA+iXIM4CSVho+3dxw
AfR4rWV4GmAkqtFl2baXmtrESKRGL1ZGhVJ/diQ0/ppCWoRDe0VzkuyoDJE1BhUe
OhMjnzQvynZVtuquhFoiHOs+Z/VjnGGT9v3u9X45m4CLfzqitXQKre2QFj3F13XJ
+vfx+9B12rNE6dfRRmRygfu6ezxWyv1YM7epMOxCBufDptd2T+gdeg==
-----END PUBLIC KEY-----
]]></artwork>
    </section>
    <section anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO acknowledge.</t>
    </section>
    <section anchor="change-log">
      <name>Change log</name>
      <ul empty="true">
        <li>
          <t><strong>RFC Editor's Note:</strong> Please remove this section prior to publication of a
final version of this document.</t>
        </li>
      </ul>
      <section anchor="since-draft-connolly-cfrg-xwing-kem-05">
        <name>Since draft-connolly-cfrg-xwing-kem-05</name>
        <ul spacing="normal">
          <li>
            <t>Fix several typos.</t>
          </li>
          <li>
            <t>Change HPKE/TLS codepoint requests to the memorable 25519 + 203.</t>
          </li>
          <li>
            <t>Add instruction for use in X.509. #21</t>
          </li>
        </ul>
      </section>
      <section anchor="since-draft-connolly-cfrg-xwing-kem-04">
        <name>Since draft-connolly-cfrg-xwing-kem-04</name>
        <ul spacing="normal">
          <li>
            <t>Note that ML-KEM decapsulation key check is not required.</t>
          </li>
          <li>
            <t>Properly refer to FIPS 203 dependencies. #20</t>
          </li>
          <li>
            <t>Move label at the end. As everything fits within a single block of SHA3-256,
this does not make any difference.</t>
          </li>
          <li>
            <t>Use SHAKE-256 to stretch seed. This does not have any security or performance
effects: as we only squeeze 96 bytes, we perform a single Keccak permutation
whether SHAKE-128 or SHAKE-256 is used. The effective capacity of the sponge
in both cases is 832, which gives a security of 416 bits. It does require
less thought from anyone analysing X-Wing in a rush.</t>
          </li>
          <li>
            <t>Add HPKE codepoint.</t>
          </li>
          <li>
            <t>Don't mark TLS entry as recommended before it has been through the
IETF consensus process. (Obviously the authors recommend X-Wing.)</t>
          </li>
        </ul>
      </section>
      <section anchor="since-draft-connolly-cfrg-xwing-kem-03">
        <name>Since draft-connolly-cfrg-xwing-kem-03</name>
        <ul spacing="normal">
          <li>
            <t>Mandate ML-KEM encapsulation key check, and stipulate effect
on TLS and HPKE integration.</t>
          </li>
          <li>
            <t>Add provisional TLS codepoint. (Not assigned, yet.)</t>
          </li>
        </ul>
      </section>
      <section anchor="since-draft-connolly-cfrg-xwing-kem-02">
        <name>Since draft-connolly-cfrg-xwing-kem-02</name>
        <ul spacing="normal">
          <li>
            <t>Use seed as private key.</t>
          </li>
          <li>
            <t>Expand on caching decapsulation key values.</t>
          </li>
          <li>
            <t>Expand on binding properties.</t>
          </li>
        </ul>
      </section>
      <section anchor="since-draft-connolly-cfrg-xwing-kem-01">
        <name>Since draft-connolly-cfrg-xwing-kem-01</name>
        <ul spacing="normal">
          <li>
            <t>Add list of implementations.</t>
          </li>
          <li>
            <t>Miscellaneous editorial improvements.</t>
          </li>
          <li>
            <t>Add Python reference specification.</t>
          </li>
          <li>
            <t>Correct definition of <tt>ML-KEM-768.KeyGenDerand(seed)</tt>.</t>
          </li>
        </ul>
      </section>
      <section anchor="since-draft-connolly-cfrg-xwing-kem-00">
        <name>Since draft-connolly-cfrg-xwing-kem-00</name>
        <ul spacing="normal">
          <li>
            <t>A copy of the X25519 public key is now included in the X-Wing
decapsulation (private) key, so that decapsulation does not
require separate access to the X-Wing public key. See #2.</t>
          </li>
        </ul>
      </section>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA9S92XbcSJame+9PgVKuriAlksI8qDKykjMpcRJJzaUOGQAD
6aJP8oGD4kStfo1zd65Ov0c9Sj/J+bYBcIc7SUVkVlb3OloREh0w2LDH/99m
cK6urrbG7XFHv7CevF991+5dvLAudE8PVWd1MBkO+iNtXd6lw3Zu8fN49dtE
9caTrvVq+/BJS6XpUF+/sG5veK6VqbG+6A/vXljtXtFvtfJ+1lNdOs6Hqhiv
Zv1er9/p3K1mxfBi1TyyeqW7q3bYGk3Sbns0avd747sBD+yfnu9Y1p8s1Rn1
mVe7l+uB5q/e+MmK9UTn7XF/2FYd+bC/vsE//SE/8dCTVm/STfXwRStnMi8s
13b9VTtedZIWw490bzQZvbDGw4luMW2vpYZavagfvekPry6G/cmAK5vDu8G4
b+30h5Puk9aVvuNm/qJlrRopWJUU5DNLkH9OXj8/rwTVuta9iaax9XBvllWu
8smpHmk1zC6tXWknN7qq3eGGSOivbT0u1vrDC7kurbh+OR4PRi+eP5dmcql9
rdfqZs/lwvOyw+f/qqXJL532aPyzdCZ9XLTHl5OUXvJaE89/qBh5poMUR+PG
yNNn18ru1tr9H/fy47trl+Nu50mrpSbjy/5Q5MugllVMOp3SdLZ0e5gPtbVZ
PW9us1rVa39XYwzmhXWmennav11/be7pUoT5BFFnw8loPOlMun+9kKtrWb/b
uj/EiR7roXWWXd6oVD/Q/+HJ/urZifXP1qlinEluvekh9+GoPb5rjjiQbv6a
GU1/xURFJ9PR2j3MbmNte816hzz1MFWqtzCNDTVavDk/j80OgxfoXTeHTdXo
r9n0TrnEXn/Y5aFrY4OnO5uu4yQvWi3xysaN/dWttXzYHmXIdXXwbbxaWu8q
M+i2EXb/4q5u1p/0RjjA+LJUn3gtA6VtwsRI2uzsn5zhai/MxMZqeKGxmdpk
etedwSQdrfUwxrWL/vVz+UGuPJfHnh/tn52vyU9r9LA2yIuykzIk/SQ3xItR
8976qmedjdG2whVR27A7GRvZrCI7nVt7anRpcbu1fTsmWqi0o1ePJww1tnYm
vUxajn4yvU/NzfxZrf6t1HRk+lQda783YhqTsbb6xXTgkYxgnevsshQRzx4e
EAz/1rUX7cHIfFqTn1i799jaPUywn09YzIEaj9uZrpb7St+tbvcyNRhNOmbK
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
+Y8o5YN7O6aGi1TMvMsaW2OmBM2xHEYrq6aPmhljo7Avi1FEEw2+VPXKOVVW
g/6wQ58OT1R29VCImXb6oz7qWnY+508DunxkRI8R3/QGvzfmo108XDr9wSKl
fllawUg3DngaGzMHA00n5QZv6Szm/MVcyn9A4dWe8g+iQmlNpbdrQdfmpEl5
2NK0WmmVxreg+K6CFNxa67Nzm+IzcuxaWv9gwPoogVmMHN/ptsdjswc3vsFd
W/OxqDyeYMRQzjQdanVVSmHxSO5MbmuLB9cM6mu+SmL0M/+6SVq+7dECXA0w
zrZudFgfzr3sMwVz0n069bpOPdQXMlYljNZDVkWcfjMy5wNl+31azhzRZlS0
qzhgzr6Z92KkQlaoTM/zFtHnlzMtL3Si9Sm2EIY8u1rWKM1lUxTCH0cP3CwP
nchpR3lZVGQ5jSE8N2pUFkezU92rD9RK6xPT01qtFHoZVKo4jfDTIH5NwNFs
1b7qNrnvwyWLacGR1ivkxXleO5ViVaqdBrcGi68X/lCybtXtH4R4zdpVCQaq
lS3yD5PkjUgEYP22Up1PJjM8xD8am4KylWRO+ypzBFGV5lL1vy1E5stajRTq
sRdgQzV2Be5EGXNHNx889flCaMuUBY0mg0F/CHRcp129zNKW5Eo9eK14c15U
xjmqyyxHLI+/hWLIU0ejqyq3N/a62rhufVC48gw51eeseRWhmmbnn0Yl7Fmp
N/p/me6emYw5TU+thlbvCXht1i3uAPn6u7qdOzF53HuQTt5X50pjWBMEWyoV
AZenhwAPnY6+UJ1fCFuEd3PSrcMoc8J5vxbYiVX6vCma7veKoSr3UBjCHOiW
E9My0vH+lghyLVxz1nz+D1038NbcIHJdQSmlxxd3TR8Xl5+dNisPRUhiWj87
WnPM2WXzam3puu181ZR0rOONl9uEz/2t7aPz/Z397VPrxYufrV8xtf6Ss1wP
1CZwNF/QXfKWp29X5f18KVwuA15Pj+WpynWX/GXkao7DQeTlhlmGVS7jt9Lr
Bf9uSsQujDGbipOqZJXNrlcKmBhMM42b5hQhsyPDXlY57uyhJvIO+kr1+kLd
cAa9SgmN7jCW24pxP9iLEY11tv36zfbR5rZl/VrJYHZ+of4z3aLfr+U3XKka
Ly7Bsjb2z62z89P9o12awOUeePjX9YPd49P9873D1fMPJ9sr1vznF9NHzvT4
N5lmqzHPcprNSc4/vfbkn5+086Vf5zpZrkqRtT2P7j01NYDZHzo6kQdGC539
+tfp6L8tW/VxPrNaYwPrP6gJ1lS7fOcITNIeIr7OXWt6VqTSn+i4rFNOZbvW
qHrOBC5aPN48355K3czh/AeRx5zhFdZh3u1R93W4pFplxJENGJnHTKfLDQBQ
7plXJ98vesa0e2N5jUWO6hq/b8yrCmKpBs9V8OKRR809hmw1Hywj90hes/mX
6lUt9fjTZuD6+eaQP3xqtswK20zjyjRwDKcaNOcgK+ebWaPxXjlo+bjzNuLd
D6rH1Qwk5pudqmqKDQuebmNNp6RS2YuoWPjJDHC0WhsSP2XPTF7QKF/kEkg6
3WGbHi+VK8c9vT6qjwMw7VaVweVgb5AE5ZEBsbLFhsYW5xy1Pl5378/b8oa4
5WCKAdfnI89cT/ejUvXn5M3Gwf4mWe/D2j+L30+lPfX7ptc/+mjt6XOPPxAU
Gn9+/esDU19rxIYfP86fOnb8NieGxUZNJ1raPD46X98/KsPrD/7MrW3a9d+0
vj+wQiNfNUb/6UROwc7+fLI/W+uzG/VKpb0c7eWfT5/cFxUMni36k/O54YZ/
53L/dlX+A5S5sMJWlQzemVeR5UtvzFGSxytychT+nuuttMq3TaamMWcMc2WQ
obqx+tlYj+vTSzX/aT3GLRph5j8Z6O4FgoeD3GOjz4zgRzFt9t7rZvWeacnK
rV//ZF6OFaxlXknpyGbojGNU567bhdm8nF0pM0r1bQ/V3mp71Kpvzh8fmD7F
TA7N+y/kbWCgDFX1bN4ULn8KHLfs3ZBD8/6p7ACl8sJmrs2LS6ZkUp0F75u3
cA0mLCsvUgfY3FyflRWa74G3Uqmdzt4OfKhx8+3Vuhp/oQarm1t703atuVNr
NXky39QwfQHggQlUJ84zcH7bvCVZVS7r9y/rVNXamXxtj9RVe/X4SnX78maY
lCmq77Hhofp1rNlcXzRocGv6/hNZuno5q3wDK69eTakVZUogpjNDX6avibXk
vX7DGWbVl2o3TPq76slrJlVXqjAvvIAOrnWrfKth/nsRmmVCkw6bLxPX51aq
L1YwhbOSK9Xf2jGr47TOwCKNl0oRpxFhUb6+bM1XfKRXU856sDyT3uv99wpL
raXz461jecehetOw+lKBfrFcF87lTW856/arfGPJb7/Vajdne6fDy9sas45X
Ns8Zbf7SiRlu1TrYXn81m9HChcUW046a1+qe9o6P5jpqfF64P+2mcansReiY
RE0hqis1We6X79yLOTTe+jKF9dacPFfmhbmy8K0w5RhrctSy/Kaa334zX3Sx
frR+P2SZcsPiuzxybluPxqPnQ30hL/QMzUvv+kZ459BEVVH7k2lZbkapRk9a
5TNDc2bzrUBmc2CvZKc/W2V8eyZfSmTegQn9SFlLA8HDepknyu9BelF7X8s6
mjv1Jxewl+kRQfk8uJqeJjTtr2ZtpSxjPvX6fDqtrc1cmltyqzX33v747xDH
+cFZ60hJXDDfxWYtoZSzsmJUX1u2auGsyPt8/WFevV9eZtd+pnNCyag1d+g5
rN7/FP2ZgPh3SHVLl8fRTKmiKd0tOl49fmUufjAiIph05XWf3Fw7+j2xyZai
/GTuNb7BzkTq6RewNIJr+f0rqcqujFHOV7bFn3f75WHfT5v7p5sHn5fqL+ip
vi2O+T2ffVvZ86w9zDrPB5NO57kfOcvVozvtThvJP/gw9/pn/fG43dHPu50r
3WVSy63pGzYvZjt/ZXTrd+RtmS+rtv+l+ZrOePrNNuV3IFjjdrf6eg3LuiFZ
lWfwV63TyWhcTWv2pXXD0YNzG04u+s+brf7QxOy/Z2II/1CiS0+vyhd0lO+h
1t9dUG2En63Kld8ahcf6+EZ5KnI6ofrNi9n3wswi+1ynYtond+NLOc5Rb5Cq
+Sb/Up44mX0pT/n9IVKneNFqjxdelM4hkv07A2RW26PqHWlJoFf1G9KzejdA
RQLscNITkZSZ0Qh7bVDW3v8dobxbPxWY/9jsZgiknKdqzNQI8o4+5vdr1qqX
vkbCfc0bYtPvvJjIt0CUrxxLDaCeVv3SbrmE8m28LcnXshVrsFwJpwZ35t2X
YnbOZk3ekzF7pJ3OivTf+hPdwerag/oyT5VH63ODAEwXLdliksorqVyNsna7
/iwH2zvtdHrfOEz94db4d2v+/Fs6fPLkyT2S8m9rz+9de/7f/23hGk+uVV/d
sJT+9G+9n1as9KeflhvXrOpSS16DB2vIIfWl2fjL1s8/W2F9r17M2qW+lS/9
WWyY/tQ8aPdT64cnvOsTQXOnvCvxrI0u1ZX+xRz3lnZrefsCqS6Vu0I/l8e/
5eCQOa0hBzqMHKtz383j3qH/eaW6acoFIxOc5OHR1cPnvaVbuVMqY+39Eg1X
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
/s1OaXBwbfHtz/P33OY9fGHubipP1klk8dHUnbu5+Oy8lc15+D33nrq2EmbN
qM+M6pToMHXvK7Dh02UbeaJ81v2DjjxF2aVm80cwwLRZJm3KrxqZgwPTDhu4
+8ddNhr+bqcVDH20w8Z9g3RqEjAy3939pteWczVLgA2tutXTpSGVuioDz/mw
/N1mlVrFIMwDa0LM5w7BizmkUrB7ZsF1ny6lci7vv1lO2GhjKKe5Ae72l2nq
hE/TT+7MOirwl4vS4AKOaFAem/X99GksuvzkVJ8WexCJmUNCn3JhfO7neYMH
guaCRL7dD01yyqPdm+gFc1ozb1vmS/nyYkemzF2h0/vd3TMvY1obW4Ljsfv7
FElV+w9PuduqxX2PANxT1IKf9+ZyTz35JUOzPr2ga8Lsalmv/cSnF+5Tc824
xvKcphGr3HvxufXoct4f7yyV20Lk5XY18qX187T6sdbTN0tlt5drk4H8nj7z
gFSWDVv6JA9+Xp6rrl+WnZ+c7jhV771+L9P3Jba4vTUdGQv8/ZFNp48O7VZD
d0cX/7CBpa+50So3qgsRu81tvMv5TUvvl8Bx5/cs5/v6VG74XMo2U8WC95bM
7B/dgpO7jV2zkuS91dmjHG8wWqR3A7HEksQNmtHpASRUzYL+lwZrcr8Mb4Np
eBv8Ppqa66Nq8sNutvrjP5ijy++Nmh5nsP7ceOYv0vlj6bdRU1hSaxUoSJcr
ymnNc87BlHMyzeWVe1GDP8bF5vnoH+C7IhLY7oNEd37QvyXRlYKetst/LOs/
kObKDhstf9zlH01yIvuBMNt7fUEhpIiRL/8dTHnQYMqDUbP6I8u41tm92k1j
Pp/m50Nr+vhcTedmuVEDks6kSHU1684E+K16F8u0XxBiFYg/9Z62X/SeLoF5
lj8vLyaDq+XmOOaRB6phU+gxHWwaDA7Ne9I/qPkseNOZARfVuzrlO9aTEml0
qu+mNaFweNmfc6FZpagMJeXfw/5NuSJ+MFX9R8E3wn3MratZLODt9ac88nu4
uiFt+V+ms1bFExmwObX78Oxe6CprdNX7+3Ku2fwmNYB/NcPmyFK4bhbAFqdU
qmWpvg8bEpC8wMiulu8T5fLPA1bSgIZV5+gIk5y3lOrWp0/zIFJggGluUMD9
au3cpD7fH/7z3PhHfXlZctS+6JZIqeaU92YjShFAVQKFsn37Wdl4uUytJZpa
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
ppDhYwwkUXl1CQCGXsIwp728G4VJ4n64qDktJDs5fMrNsrNUMjXcG1qeJ1Jr
kA3dAhCWsLqw8KFqctgqtsHgciiCDI+Qfd+cnwht8kkhW66+bGNBzJIENxWE
6IvvwLMIJ44cUsVTMnkpJSfoyptBoCK0hFejX1mgcmWrGUYhJwiE0sZ4I4/H
LukUn8syjCMVtA8akTpFnssB06ggGCYAVx9DzWPHbHKlsumTAUJTDV31My11
T+ATICpA9eRVbC6N5VC/IxfgnwQKtCBFESgRiIoEbMhMGMpuH2QU7uBJpvc9
chW4ptCgOS8E9UWhm8gekjkC7tspMCEXgE4qwuvhZ6nJzkwBrw1zYUY4D6Nr
2awxIZ9AWQjTJeDrTOqRKd5nI355LYBcIe8g2oRO6KGpE2aAfVtcl9xvF0QY
ncamCoqm8TnEYYNhkSKPR1LMjIHWEMlQ4l+c60yqA+ZsXIZdSm5wICZyGkzO
HeeaqIJhgy607C9COB1lyvcuEwXHYN42sBQPwyUl2EXGGKRS4Hl+XXJMAvII
BhTLWQ15RSeX8nZOBChI+3JGE2IihS95RVVq2aJO0KQcpkK0RWv63vb2rfm+
Dfl+G3kXu92z3q8BrMrfR1v+5nnz+0iH2nzdU/1bjqe/LrX6faVX+m6g2tU3
9Td/GZ31Rbjc//of/69TfFmrhl2VPxvbu/tH8rj8douT0/236+fyWzY/mJut
w63Xm+uv12+2Xn84eHXzYWNjfXcraLsbd3v97f319Y31i8Ptjdcf9jbXr15t
3twcbV3Er7dP9893Nt6827m9+NjavRxle6d+UQ62fbT16FBmSovzKn/BdWM+
+/vbztb60cbFaLhxsb29/uGke/Bhb19fHG9uHG6vp87rl+2L/vHHjZ3dD2/G
gw8Hgwt3dz35cH2690yNX7a6ZH/1Oj18fbBx6e4evTrpt1+nd5cv3x3n23uv
0r2X2STIXr7zPt4Odl+5auNOf/ywGd0dfTjYefmsu95tbW8fX0/CN9f7O4OL
V1uX+2/edr553zN1/a17dEjAPjmbgNaOTz76R5evnl/e7JzoYLffsde7b+z3
xcegdbR++t3Ozjfy/uXkfbvrxzvtqNg7Ot/pXo6eOzdR6N909w7WX2avVLZ7
/X3nLDg/uJzsHX+IBl/Tr52sNdjZ3vAvbyN7++b25Nuuiq92NqLk1fh0e+fb
y3Rw8vHj9nGStNd7W5vn8fa36/Xjk6PO5Cg7+3ayvz7afdVyro/zwcGZ7364
O3CC9fFFuBENdo7ffbQHFy+37oZXzy5O3HRvP/eO3G/ZzVEabr/1u8fnFwe9
3eve5X7r+vTow9fd05vjizeO/bF/cvHuMOy4/VfbO+Nu1L7Mt5KXb8PNm63D
jy+L1/6xC/y9jNzNj/tO/6C79/Jr692rb/l62vY7nd3i6vLUnng3byZ3+51X
zs319tHrs9NR9+6k93H78uVRL3mze/nePY6v+v1g4l3vndxot/UxO3s3cd9+
uDs5fdNW2eT2YHh0dNzb6Rwegs+yr/HW2dtwf7x1pUbdYGtjyxt+ONXfrz4G
O7eHu7dq2Hp1fJp47/fdD/7bvY+XV9fY9mhw8y3Su3fJ6ObqLujfvTq6uT4Z
7XW3+hsHWy+7k/Mo/NB9+/zMP97KD1ujg8lb//hm9+3GaO9j3s3it8eAyA/n
71/p9cHbkXvqtfXhxx192r6In8nbGv3T82eu2tze2dmI85uj1vrRpY7er0fp
7t27Pa+3f3qWD19ftd/01j/6B53tZ6PBVdrJOxevJ8eH1+O+83K7ezd+fXl8
rVhxd3+39Xpdv9y+6d90rs4+nB18GDyfDF4dbA7sk+3+kffy7nucfHSf73zw
DtOXo7PLQdfbP/24c7Pxznmv3sdvXketC9X9errxKtLPN4rDu/z9u87VqXe+
nn/YOd4tvt/cXOxtF7vPt99eRpvRqw+ve+pO7QTe2/b28dn3Zy/fnrcuNw/1
2w+3129e3536J7fvxvnu/vvnr970Bu+uVLz7zC8Gt8nrl8+2D0+3RsdX2EW+
vWV/DF/e7Z9tT9onrfe7k+7rQfrKP9rfu44/nLQPi5Nxdqr6H47z3cORd7tz
uRW8efntbLC1vz78uPk1eBMffbx9dbO7br+5Hq63xt8/6IPkKP++f6kwpPw8
7m+8O9n1nJvxwffT3eOz9mDj7fbxUXy7tX026KddPdh49zrr6n775sPVy43W
2+Dm/f716cS5vJmcjAZv3r/s3Lx5v+Mcf5ysb6Uv837w7tzePXvt3L4erR+3
jw7SjT3M4MD1hgfF+GqvlUwOt3dGN0fBm/7VwXr/8uXX9ev3b8/338Ufv91c
X8T6fWdn/Ppj/O3qVXJwcfPxbpC/Tjsb4ejV+5fJu0OvtbndzXaLl6+ine3I
DtbD9+9xmO3uKehgMvm4t3HjtV9e7Nzdhl/bF9/X99+ru2Ln67vjw0AddtX2
27j1LO0+W+/dXey/2Xjfuc06zpvtzfBlp7czGX1zN492jt2N9PLt0c0o3U+P
zw+Oojc7F98Gne+3zyaTd6NTt3X+8fykOOy8Tm/yaPj+cOMgHb+623j96njv
9Gp7Mvp+93Znp9PeKLK9D85le/+9m354uXv4ofv149H21dvJdku3T90b9fIm
fnvWudvet3c6w5O73avg8ubg+JvuXhS90XFXf0u9A72996y3/qz9fv/Q3zx7
e9l/5uW3N6314tQfvnvr73bXr76NdzqwiPfd8XD77NXp7oHzcffy7cvnefu1
/Xww2HzXP93S9tvvV5O7/tbLbWfj8o1uHV8efu19f3191/v4djz5Nrnc6bf3
jkfPPj5/+7W3u3ueXHuT5L0fdP3Ng+L7t/b4/etXQ+2+3vnq7Tje+5etZ9fF
7bNkw3GHR9sAmNPT7undRTEJ9ffbd3fXzofDSA8Oj283NybF1mCc/3+VnV1P
2zAUhu/zKyxxAXRLN8rG2CQmVUA1tA/Qyu5xEyexGuLKTsqyX7/zHtshMCbB
JSFx3vNhxxbofWbXr8pclScn99+1x5+q+GWfZ2Cu1yovmaVLX/TLs0shh6ue
7XRawb9P1KZMks9iMvm5OBXnuW6N3XWexzuZiCsmLAurbs02+PG5gG2mbz2Y
ayaYjw2O7JJGK3Qj63+YvRGq7MG0Sw14bm5l0aaZaRracfRpVtgyHfjAKZ1o
klQs9G9665aR722/MY6xw0E/GN1vrr8t2aRvY/QIZx3B02AFW+b/jjDSPMY8
zxlTZYPrILwNx5uhqdiZHTxf7TuMidR5l5tgzpaPEYu8Ncoqla2D8yCr1Vbl
LOiKCfN17/HCCGBxcbVk7HU0Osy0ctD1ltnwKEvNZNoAQ6Z7pmLuBPLVU9pp
i1YAcIX9GdwThaNLlIpVbUgDlWb5ZX6Yzt4fwS0olClgwW7lWgm4Iea6CLBj
FvmLMsS+zXgMGuFu3mYVm0VNI0A7DFLJrR+E+qazuu0FvF2VhQWmpBH5r4IF
9ZT7BLbxHW1IG4rfUQnVHyU+HnlTQ09f9o/dB/FV0alhjeu33eDqeFcpeM8G
iXQoEJFWxnpJHJWYdarwak0SqUYyY3l+e+s2htorYYzAytDeNpPABNHTx4ez
aCtZ0pNMZhtiKwQdoMWKMs64NU5DqDCNVSsHByTTlVXrjV0pM/C1lDRfegQV
t9VcKtu5auhThtEPTc6Xz0yzizLZNfjpgdYu8cIBci5WqoCXpWZsGv2kYGNp
oQBhkqaL8+sF+0qpxnXOU9odqd+7XG216RwVA/mQHem2o7GD0un+8+fHIbes
bODuHWeHap6cHZ7/7Fq9YWBqKBTJpZsQK37LGWFSmPWAu5gqpnRj6aEF48HS
QFH9ACzPOV02MDbrVfuSAGax/fn/NqQbH3j47ecMVYXIjNnj5ROz39tcPbp9
pRucriCduhnEsxeskgcxcBBTHnDLPXWe3/Vdu0zVtWwUFVUoXuk1JYjupXR5
7PqQQY8w/x/k3K+/xlIvtLDthbtxWOhvfFnTD0fHgf48Ri3fvCAoXt/mVLvN
MCeDT9jI7ZLXUHgJZ3WHbg/exL41E/Eo+3uhXPt49rVwxq/TD2+KK1ci4sSl
asOKjcoss4xnsBmfgO/lTBmaujObJn8BzwRqBDPQAAA=

-->

</rfc>
