Skip to contents

Shrinks an HQC key pair for storage by replacing its secret half with the seed it was generated from (32 bytes for v5, instead of several kilobytes). The full key is derived again from the seed whenever hqc_decapsulate() needs it, so a compressed key works everywhere a full one does in this package.

Usage

hqc_compress_key(key)

Arguments

key

A key from hqc_keygen().

Value

The key (class bricklayer_hqc_key) with secret replaced by the hex of its seed: 32 bytes for v5, 96, 104 or 112 for round 4. The other elements are unchanged.

Details

The HQC specification of 2025-08-22 allows the decapsulation key to be stored as its 32-byte seed_KEM alone (the compressed format dk_KEM = (seed_KEM)), from which the whole key pair is derived again. hqc_compress_key() keeps only that seed; hqc_decapsulate() takes such a key and expands it, and refuses one whose seed does not derive the key's public half.

The round-4 revision (64-byte shared secret) defines no compressed format, but its key pair is derived from the randomness its key generation draws, sk_seed || sigma || pk_seed (96, 104 or 112 bytes: the seed of hqc_keygen() and hqc_sizes()), all of which its secret key sk_seed || sigma || pk_seed || s carries. For a round-4 key the compressed form is that seed: this package's convention, not a format of the submission, so software built on round 4 (liboqs, PQClean) expects the full secret key.

A key that is already compressed is returned unchanged. Errors: key not from hqc_keygen(); a secret of neither the full nor the seed length. The public half is kept, and anyone with the seed can rebuild the whole secret key, so the compressed key must be protected exactly like the full one.

References

Gaborit, P. et al. (2025). Hamming Quasi-Cyclic (HQC), specification of 2025-08-22, section 3 (HQC-KEM key pair formats). https://pqc-hqc.org/

Examples

key <- hqc_keygen(1)
small <- hqc_compress_key(key)
nchar(small$secret) / 2
#> [1] 32
sent <- hqc_encapsulate(hqc_public_key(key))
identical(hqc_decapsulate(small, sent$ciphertext), sent$shared)
#> [1] TRUE

# compressing twice changes nothing
identical(hqc_compress_key(small), small)
#> [1] TRUE

# a seed paired with someone else's public key is refused on use
spliced <- small
spliced$public <- hqc_keygen(1)$public
try(hqc_decapsulate(spliced, sent$ciphertext))
#> Error : the compressed secret key does not derive this key's public key