[CFRG] Nailing down non-contributory behaviour in the hybrid-kems drafts
Jack Grigg <ietf@jackgrigg.com> Wed, 15 July 2026 13:43 UTC
Return-Path: <me@jackgrigg.com>
X-Original-To: cfrg@mail2.ietf.org
Delivered-To: cfrg@mail2.ietf.org
Received: from localhost (localhost [127.0.0.1]) by mail2.ietf.org (Postfix) with ESMTP id 6FBE51173423A for <cfrg@mail2.ietf.org>; Wed, 15 Jul 2026 06:43:35 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ietf.org; s=ietf1; t=1784123015; bh=kYzYz1acjllA7bmc8qwVBEQLy6KhnGIyR8R+F+XcyoQ=; h=Reply-To:From:Date:Subject:To; b=Jh0pctTNVhvZHNdjh99HdL5pOLp/IgEqoN4NQ1PsrswGwo7w2pRWQkuE/4xN+/8ID G36HgpoYAeM36OMtnIg3D5j712pxBJzG2wWmTROdU+kvRVG9evdpvobpyklQ8uM/Je toBHhoL/TbwbpLZaF44sZ1UmTvqh+i+qhnDsYjfM=
X-Virus-Scanned: amavisd-new at ietf.org
X-Spam-Flag: NO
X-Spam-Score: -1.895
X-Spam-Level:
X-Spam-Status: No, score=-1.895 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Received: from mail2.ietf.org ([166.84.6.31]) by localhost (mail2.ietf.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UyvBfFNCzIuN for <cfrg@mail2.ietf.org>; Wed, 15 Jul 2026 06:43:34 -0700 (PDT)
Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mail2.ietf.org (Postfix) with ESMTPS id A576011734233 for <cfrg@irtf.org>; Wed, 15 Jul 2026 06:43:34 -0700 (PDT)
Received: by mail-ej1-f54.google.com with SMTP id a640c23a62f3a-c15b509c323so711063766b.0 for <cfrg@irtf.org>; Wed, 15 Jul 2026 06:43:34 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1784123008; cv=none; d=google.com; s=arc-20260327; b=A0oyornJpAoInJ/51u6BzQJpyTudN/QQbq8PHp9VYYPk95+EgjlsudTbdqnCvjWaK5 YdpbNhwZQgQwFrqesdg2TxOOIi07rjrXItwvoArgL/gR2NsUFkOw++jj94eBf+tk7MjR asT8GxGCl5Xfgg0Crh4g+nvyFNAcD70dtGJv0+GDgr3Od1YosLpGx8F58aVA5XrAyAQg tDNjCIViBvpiE+Qdijxj+pSuzN/EZNluP3I/USvIGHMPalLLkH85PowBnxHT3IZd8s8t mcb68OPkicNL2aWenUnCo7l6AtOqvFO2Je58CT8zw+q081VbxSmouhc+82IHKcV0d4Ij rWVA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=to:subject:message-id:date:from:reply-to:mime-version; bh=VJaMLeBvjIMWOT0koD5qsm4JsusnnzlA57HwdcyDhFg=; fh=PtPfqTVe+9RcQClHmar7JeBMB314Y31yhoSfdH8nv9s=; b=Zv2rP3v3hGc58nZ1MhESxbvuy1EDVZtTSjaqYxOdGwiLE8yJgaEuTjvq85h4IAgJ9N qSLBhKrlLq97RoGnkqofvyJrig1FzwIjAOdrvaeM7nUPJef72WrQL+ncqelMhMLKbGIg bewYld1nxkfiBEcbHS7oMxd7lSaVBHuYe5KwTePaSIedf0PhXXquOiWxJ73ogV40luqa GsEn5k/Fb2GIuCyVpz567Qp/L2kkJO6eQmEPGNV+TxQX1hX9KTftQV8f8me9QOOqfWZc zFnKUMe81ks7OaHraguO6zt+Zp9Ii1b7ZbyhSHu52M+M/jBaAJFSaJXjQxG1p5r3wv+D T2Qw==; darn=irtf.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784123008; x=1784727808; h=content-type:to:subject:message-id:date:from:reply-to:mime-version :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to:content-type; bh=VJaMLeBvjIMWOT0koD5qsm4JsusnnzlA57HwdcyDhFg=; b=N/FnfLd4I3nmCvR0mVdgyVqaSLt3Xgg4XJ6xxcXKua8fENevCTWlUc3f43QTG5gAsz 3MqZu2ag4tutxabfmyOomfWZ7zXaE/o1tQ5g+SCKa1s9KxmY+1aUqfjNDaY+VSPAzCy4 wPSv3g+GaoM5aiedbUa6Qv6X3MabDG4zWoySVmBN+nPjoc62lYZqU7kwxhTNrp9JGobd gZVKuB2rc2YMPXTN4qSXArkgGwqO+jWVTj0W3zHvVNYlbSUiR+67H++sZZmsAy7J3kyT 8+xHmbfK1I09LJtpkrVcDfX+QnLRuqrx/sfOqKgj19Cj3laBy/D7+/2YI4DfMnn6psVS 2nGQ==
X-Gm-Message-State: AOJu0Yy6uoS816uda8lC/mk+R87L0ZnMoPdz4568nZDX4cykid+v4J94 9LGGC+Z5LSiOoCdGnJMbIDIoB+yOMyjNsrp0xyEgpyZ2UckYtKopHYS9/xJM0Fc66e5crIQvJdX HMGbBLmavOj0c0xs+CaExXyhWrUhCWxYKYPAxgcq0U+PAyGraupwBRXYpr52UcEo=
X-Gm-Gg: AfdE7cnYY4yxsXr+Xe6ily96xXIFmhANHsjfubDERY3cBdM5XMMGq5YPhKPpC+cMhTx Zl2MhxRNcrqFIi5bR553raQM2mTqYdNNpL4bfJLesXhpSpFsHbUzxo81oufZcfpYS7r/A53nbkY iONCk5DavYBXPEcJv1NIkvhkPvYR+Mr4bHsVk/X+WvJ6gsCFlc9QJkyKhQqiu/83aPm8YoWzshN t+cnpdFVCl9dRQ3yV7g9EV0Q72w6JpZer6/uurVUrB7uQhO547bKZpJbaq7m9iHqX+I3Qt8
X-Received: by 2002:a17:906:730f:b0:c12:8cbe:b897 with SMTP id a640c23a62f3a-c1667935e07mr411151066b.15.1784123007299; Wed, 15 Jul 2026 06:43:27 -0700 (PDT)
MIME-Version: 1.0
From: Jack Grigg <ietf@jackgrigg.com>
Date: Wed, 15 Jul 2026 14:43:15 +0100
X-Gm-Features: AUfX_mw-YWrFGlrab7eBXhbQ5Ai5Re2uCYoWU3bnwQ6y38kSEdk_9PP2tioSNOc
Message-ID: <CAPC=aNXyp1qpsbMiTYjqc=RX8tmWmKCasTS8sKh4Q==UOi+=sQ@mail.gmail.com>
To: IRTF CFRG <cfrg@irtf.org>
Content-Type: multipart/alternative; boundary="000000000000163f270656a682c3"
Message-ID-Hash: 6FGMYA3ZSPUFNZ45XO3VBQY2KJ35FJXP
X-Message-ID-Hash: 6FGMYA3ZSPUFNZ45XO3VBQY2KJ35FJXP
X-MailFrom: me@jackgrigg.com
X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-cfrg.irtf.org-0; header-match-cfrg.irtf.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header
X-Mailman-Version: 3.3.9rc6
Precedence: list
Reply-To: ietf@jackgrigg.com
Subject: [CFRG] Nailing down non-contributory behaviour in the hybrid-kems drafts
List-Id: Crypto Forum Research Group <cfrg.irtf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/cfrg/t2nIVd88lzBpJjw_XF1hrBqiR9A>
List-Archive: <https://mailarchive.ietf.org/arch/browse/cfrg>
List-Help: <mailto:cfrg-request@irtf.org?subject=help>
List-Owner: <mailto:cfrg-owner@irtf.org>
List-Post: <mailto:cfrg@irtf.org>
List-Subscribe: <mailto:cfrg-join@irtf.org>
List-Unsubscribe: <mailto:cfrg-leave@irtf.org>
Hi all, While implementing a protocol using X-Wing (specifically post-quantum support in age encryption [0] using HPKE), I encountered an incompatibility between two different X-Wing implementations that led me down the hybrid-kems rabbit hole, and I uncovered several inconsistencies in the drafts that should be resolved. The core problem stems from Section 6.1 of RFC 7748 [1], which placed a MAY on checking for non-contributory behaviour: > Both now share K = X25519(a, X25519(b, 9)) = X25519(b, X25519(a, 9)) as a shared secret. Both MAY check, without leaking extra > information about the value of K, whether K is the all-zero value and abort if so (see below). > [...] > The check for the all-zero value results from the fact that the X25519 function produces that value if it operates on an input corresponding to a point with small order, where the order divides the cofactor of the curve (see [Section 7](https://www.rfc-editor.org/info/rfc7748/#section-7)) Neither the original X-Wing draft [2], nor the ePrint it is based on [3] mentioned this, and thus inherently embedded the MAY in its specification. This has led to different X-Wing implementations implementing different behaviour, likely based on whatever their existing X25519 implementation made most convenient to do. However, this is seemingly incompatible with the current draft specification for X-Wing (aka MLKEM768-X25519) in draft-irtf-cfrg-concrete-hybrid-kems-04 [4]. Specifically, Section 4.2 of draft-irtf-cfrg-hybrid-kems-12 [5] states: > A scalar value of zero MUST NOT be used as a private key: it does not correspond to a meaningful Diffie-Hellman exchange and, for some curves such as P-256, is explicitly forbidden by the relevant standards and would yield a point-at-infinity encoding that departs from the fixed-size model used here. RandomScalar MUST NOT return a zero scalar; for the groups of interest this occurs only with negligible probability. A strict reading of the above could be interpreted as allowing non-contributory behaviour, because AFAICT there's nothing in the current text that actually does the identity check on the nominal group shared secret. However, I think these MUST NOTs imply it was the authors' intentions to require rejection of non-contributory behaviour. Indeed, if you read the specifications of expandDecapsKeyG and prepareEncapsG [6] with those MUST NOTs enforced, then it is impossible to produce a ciphertext that would have non-contributory behaviour, and thus an implementation could quite justifiably reject those that do. Further supporting evidence for rejecting non-contributory behaviour in IETF KEMs is found in RFC 9180 [7], which makes this a MUST for the X25519 DHKEM (which its update draft [8] preserves). Now, for an honestly-generated key and ciphertext, the chance of encountering this divergence is cryptographically negligible: - The Curve25519 scalar within a decapsulation key is a subslice of the output of PRG(seed) (via GenerateKeyPair [9] and expandDecapsKeyG). - The ephemeral Curve25519 scalar used within encapsulation is the output of RandomScalar(random(32)) (via prepareEncapsG), which is constrained by the MUST NOT on the output of RandomScalar. However, for an adversarial ciphertext, there is nothing preventing the adversary from using zero as the ephemeral Curve25519 scalar, or a point of small order as the ephemeral public key. Indeed, I encountered this issue due to this specific edge case being exercised in age test vectors. So the probability of encountering this divergence is non-negligible, and the specs should handle it. My suggested fix is to alter the definition of ElementToSharedSecret [10] to something like: > ElementToSharedSecret(P) -> ss: Extract a shared secret from an element of the group (e.g., by taking the X coordinate of an elliptic curve point), aborting if a valid shared secret cannot be extracted. and then for the Curve25519 Nominal Group defined in Section 3.1.2 of draft-irtf-cfrg-concrete-hybrid-kems-04 [11], change its ElementToSharedSecret specification to: > ElementToSharedSecret(p) -> ss: Aborts if P is the all-zero value, otherwise outputs P. However, that does then raise the question of whether X-Wing is being assumed as purely an implicitly-rejecting KEM (due to how its ML-KEM component behaves). I don't believe it was ever valid to assume this, due to the MAY in the X25519 component meaning that X25519 implementations can explicitly abort, and thus so might X-Wing. However, if this is a widely-held and relied-upon assumption, then it would imply that a compatible X-Wing spec would instead need to require that expandDecapsKeyG MUST NOT check whether the shared secret is the all-zero value, in order to prevent the abort. I myself would prefer that X-Wing follow the RFC 9180 precedent and reject non-contributory behaviour. --- Regardless of how the above is addressed, at least one other fix is necessary. The Curve25519 Nominal Group specifies its RandomScalar as: > RandomScalar(seed) -> k: Implemented by the identity function, i.e., by returning the seed. This trivially violates the MUST NOT from draft-irtf-cfrg-hybrid-kems-12; the all-zero seed produces the forbidden zero scalar. This should be similarly updated to: > RandomScalar(seed) -> k: Aborts if seed is the all-zero value, otherwise returns the seed. Cheers, Jack [0] https://c2sp.org/age#mlkem768x25519-recipient-stanza [1] https://www.rfc-editor.org/info/rfc7748/#section-6.1 [2] https://datatracker.ietf.org/doc/html/draft-connolly-cfrg-xwing-kem-10 [3] https://eprint.iacr.org/2024/039 [4] https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-concrete-hybrid-kems-04#name-mlkem768-x25519 [5] https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hybrid-kems-12#section-4.2-4 [6] https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hybrid-kems-12#name-using-a-nominal-group [7] https://www.rfc-editor.org/info/rfc9180/#section-7.1.4 [8] https://datatracker.ietf.org/doc/html/draft-ietf-hpke-hpke-04#name-validation-of-inputs-and-ou [9] https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hybrid-kems-12#name-key-generation [10] https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hybrid-kems-12#section-4.2-3.3.1 [11] https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-concrete-hybrid-kems-04#name-curve25519-nominal-group
- [CFRG] Nailing down non-contributory behaviour in… Jack Grigg
- [CFRG] Re: Nailing down non-contributory behaviou… Peter Schwabe
- [CFRG] Re: Nailing down non-contributory behaviou… Jack Grigg