ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
sntrup761.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_SNTRUP761_H
5#define PROTOCORE_SNTRUP761_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file sntrup761.h
13 * @brief Streamlined NTRU Prime sntrup761 KEM - keygen, encapsulation, decapsulation.
14 *
15 * The second post-quantum KEM OpenSSH ships (alongside ML-KEM-768), used by the
16 * sntrup761x25519-sha512@openssh.com hybrid key exchange. Both KEM roles are provided:
17 * - Encapsulation (SSH server / responder): given the peer's public key, produce a ciphertext
18 * and a shared secret.
19 * - KeyGen + Decapsulation (the reverse-SSH client / initiator): generate a keypair, send the
20 * public key, then recover the shared secret from the server's ciphertext.
21 *
22 * Streamlined NTRU Prime, parameter set sntrup761 (p=761, q=4591, w=286): a lattice KEM over
23 * the ring Z_q[x]/(x^761 - x - 1). The algorithm and the byte encodings match OpenSSH's embedded
24 * sntrup761 reference (public domain; D. J. Bernstein et al.) so the ciphertext this produces
25 * decapsulates byte-for-byte on a real OpenSSH peer. Zero heap; SHA-512 through @ref Sha512Ns,
26 * randomness through protocore_rand_fill() (crypto/rng).
27 *
28 * @ref Sntrup761Ns::dec is implicit-rejection (FO): a ciphertext that fails the re-encrypt check
29 * yields a deterministic pseudo-random secret rather than an error, so @ref Sntrup761Ns::ok is true
30 * for any well-formed call.
31 *
32 * @c work is PROTOCORE_SNTRUP761_BORROW secure bytes the CALLER took, at an address it knows. It
33 * is not held past the call, so nothing here aliases it. The caller releases
34 * it, and the pool wipes on release; this module neither takes it, holds it, releases it, nor wipes
35 * it. That is what keeps the hashed key material in it from outliving the caller.
36 *
37 * @author Douglas Quigg (dstroy0)
38 * @date 2026
39 */
40
41#define PROTOCORE_SNTRUP761_PK_BYTES 1158 ///< public key (Rq-encoded h)
42#define PROTOCORE_SNTRUP761_SK_BYTES 1763 ///< secret key (f, 1/g, pk, rho, cache)
43#define PROTOCORE_SNTRUP761_CT_BYTES 1039 ///< ciphertext (Rounded-encoded c || 32-byte Confirm)
44#define PROTOCORE_SNTRUP761_SS_BYTES 32 ///< shared secret (session key)
45#define PROTOCORE_SNTRUP761_SK_PK_OFFSET \
46 382 ///< the public key is embedded in sk at this offset (2*Small_bytes); the KEM initiator reconstructs
47
48/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
49typedef struct
50{
51 proto_bool (*keypair)(uint8_t *, uint8_t *, uint8_t *);
52 proto_bool (*enc)(uint8_t *, const uint8_t *, uint8_t *, uint8_t *);
53 proto_bool (*dec)(uint8_t *, const uint8_t *, const uint8_t *, uint8_t *);
55PROTOCORE_NS_LAYOUT(Sntrup761Ns, keypair, enc, dec);
56
57/**
58 * @brief Generate a keypair: send pk, hold sk until the peer's ciphertext arrives.
59 * @param work PROTOCORE_SNTRUP761_BORROW bytes the caller took. Not held past the call.
60 * @param pk PROTOCORE_SNTRUP761_PK_BYTES bytes
61 * @param sk PROTOCORE_SNTRUP761_SK_BYTES bytes
62 * @return PROTO_TRUE on success.
63 */
64proto_bool protocore_sntrup761_keypair(uint8_t *work, uint8_t *pk, uint8_t *sk);
65/**
66 * @brief Draw a short polynomial, encrypt it under pk, derive the session key.
67 * @param work PROTOCORE_SNTRUP761_BORROW bytes the caller took. Not held past the call.
68 * @param pk the peer's public key, PROTOCORE_SNTRUP761_PK_BYTES bytes
69 * @param ct PROTOCORE_SNTRUP761_CT_BYTES bytes
70 * @param ss PROTOCORE_SNTRUP761_SS_BYTES bytes
71 * @return PROTO_TRUE on success.
72 */
73proto_bool protocore_sntrup761_enc(uint8_t *work, const uint8_t *pk, uint8_t *ct, uint8_t *ss);
74/**
75 * @brief Recover the session key from the peer's ciphertext under sk.
76 * @param work PROTOCORE_SNTRUP761_BORROW bytes the caller took. Not held past the call.
77 * @param sk this side's secret key, PROTOCORE_SNTRUP761_SK_BYTES bytes
78 * @param ct the peer's ciphertext, PROTOCORE_SNTRUP761_CT_BYTES bytes
79 * @param ss PROTOCORE_SNTRUP761_SS_BYTES bytes
80 * @return PROTO_TRUE on success.
81 */
82proto_bool protocore_sntrup761_dec(uint8_t *work, const uint8_t *sk, const uint8_t *ct, uint8_t *ss);
83
84/** @brief Module namespace. */
87
89
90#endif // PROTOCORE_SNTRUP761_H
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
proto_bool protocore_sntrup761_enc(uint8_t *work, const uint8_t *pk, uint8_t *ct, uint8_t *ss)
Draw a short polynomial, encrypt it under pk, derive the session key.
PROTOCORE_NS Sntrup761Ns Sntrup761 PROTOCORE_UNUSED
Module namespace.
Definition sntrup761.h:85
proto_bool protocore_sntrup761_dec(uint8_t *work, const uint8_t *sk, const uint8_t *ct, uint8_t *ss)
Recover the session key from the peer's ciphertext under sk.
proto_bool protocore_sntrup761_keypair(uint8_t *work, uint8_t *pk, uint8_t *sk)
Generate a keypair: send pk, hold sk until the peer's ciphertext arrives.
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition sntrup761.h:50
proto_bool(* keypair)(uint8_t *, uint8_t *, uint8_t *)
Definition sntrup761.h:51
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97