Annonce de Zstandard implémenté en Rust
(trifectatech.org)- libzstd-rs-sys est le troisième projet de compression de la fondation Trifecta, après zlib et bzip2, et constitue la première release de zstd basée sur Rust
- Zstd est un format de compression conçu pour les CPU modernes, plus rapide que gzip et offrant un meilleur taux de compression, et devrait progressivement remplacer gzip dans le trafic web
- Le crate Rust zstd existant compile du code C depuis les sources, ce qui nécessite une toolchain C et le support de la cible, ce qui peut compliquer la configuration sous Windows et WebAssembly
- L’implémentation Rust peut être compilée comme une bibliothèque C compatible drop-in et est en cours de validation comme alternative à l’implémentation de référence en C via une suite de tests, du fuzz testing et Miri
- La décompression par défaut est plus lente de quelques pourcents que la version C, mais cette baisse d’environ 3 % des performances est le prix de la sécurité mémoire, et un flag expérimental permet d’atteindre les performances de C
Première release et intérêt de l’implémentation Rust
- La Trifecta Tech Foundation a annoncé la première release de libzstd-rs-sys, consacré à zstd comme troisième projet de compression après zlib et bzip2
- Zstd est un format de compression conçu en tenant compte des CPU modernes, capable d’être bien plus rapide que gzip tout en offrant un meilleur taux de compression
- zstd est déjà largement utilisé et devrait progressivement remplacer gzip dans le trafic web
- En Rust, il est déjà possible d’utiliser zstd via le crate zstd, mais ce crate compile du code C depuis les sources, ce qui impose une toolchain C et le support de la cible
- La configuration d’une toolchain C pour Windows ou WebAssembly peut être difficile, si bien qu’une implémentation pure Rust offre une meilleure expérience de dépendances aux développeurs Rust
libzstd-rs-syspeut, comme les travaux sur zlib et bzip2, être compilé comme une bibliothèque C compatible drop-in et vise à devenir une alternative à l’implémentation de référence en C- L’implémentation de référence en C est maintenue par Meta et nécessite de signer un accord entre Meta et les contributeurs pour toute contribution ; une implémentation indépendante, performante et compatible peut donc renforcer l’écosystème open source
Validation, performances et travail restant
- L’implémentation de référence initiale a été convertie avec
c2rust, puis un travail de nettoyage a été réalisé sur la décompression et le dictionary builder - Le code Rust est compilé en bibliothèque statique C, puis validé à l’aide de la suite de tests de l’implémentation de référence
- Le fuzz testing et Miri sont également utilisés pour valider l’exactitude de l’implémentation
- La prérelease est disponible ici : libzstd-rs-sys v0.0.1-prerelease.2
-
Le coût de la sécurité mémoire
- Les performances de décompression par défaut sont inférieures de quelques pourcents à celles de l’implémentation de référence en C
- Chaque modification fusionnée dans
mainest mesurée dans la suite de benchmarks - En activant le flag de fonctionnalité
unsafe-performance-experimental, on atteint les performances de C - Ce flag désactive les vérifications de limites à 4 endroits où les données d’entrée sont utilisées pour indexer des structures de données
- Pour la plupart des utilisateurs, une baisse de performances d’environ 3 % est probablement un coût acceptable au regard du gain en sécurité mémoire
- Si l’on a besoin des dernières performances possibles, il est possible d’activer ce flag en acceptant le risque ; le comportement à ces 4 endroits est alors aligné sur celui du C, qui n’effectue pas de vérification de limites
-
Implémentation de la compression et intégration à l’écosystème
- La partie compression est encore à la recherche de financements
- Une partie du code est partagée entre compression et décompression, si bien que le code de compression a déjà été examiné en partie, mais l’essentiel du travail de nettoyage reste à faire
- Des benchmarks ont été mis en place pour éviter les régressions de performances de la compression, et la suite de tests de l’implémentation de référence sert à vérifier que les résultats produits sont corrects
- Le travail restant est récapitulé dans Milestone 4: Encoder implementation
- Il existe un fork de
zstdqui utiliselibzstd-rs-sysà la place de la bibliothèque C, avec l’objectif d’une intégration upstream à l’avenir - Pour les API les plus utilisées, l’intégration est relativement simple
- Dans la fonctionnalité
experimental,zstd-safeutilise des enum, mais il y a un décalage car il faut utiliser desstructpour assurer la sûreté FFI
-
Soutien
- Le travail sur la décompression est financé par Chainguard, Astral, NLnet Foundation
- Le dictionary builder a bénéficié d’un investissement de la part de Sovereign Tech Agency
1 commentaires
Avis sur Lobste.rs
Excellente nouvelle. Il y a quelques jours, j’ai dû récupérer libc-dev juste pour compiler zstd à cause d’une dépendance, et je me demandais si quelqu’un avait déjà tenté une réimplémentation sérieuse en Rust
J’espère que ça sera largement adopté par la communauté
Je développe un projet basé sur WireGuard en Rust, donc je pioche dans plusieurs bibliothèques crypto Rust. La sûreté mémoire est un avantage évident, mais contrairement aux anciennes bibliothèques C, elles n’ont pas toutes fait l’objet d’un audit de sécurité
Au final, la vraie question est de savoir si réécrire ces algorithmes en Rust vaut le coût que cela implique
Il faut que tout le code « ennuyeux » non cryptographique — parsing, état du protocole, gestion des buffers — fonctionne correctement pour que le système soit sûr. Si un attaquant peut envoyer un paquet magique menant à une exécution de code arbitraire, il ne va pas s’embarrasser de cryptanalyse avancée ou de canaux auxiliaires temporels pour ramener un cassage qui prendrait des millénaires à quelques décennies
Les deux côtés sont sûrs en mémoire, avec l’avantage de ne garder qu’une frontière FFI unsafe très étroite. Les bibliothèques crypto Go sont aujourd’hui plus matures que ce que propose Rust, ou plus précisément l’écosystème crates.io
Je me demande si quelqu’un connaît une explication documentée sur quand utiliser les suffixes
-syset-rs-sys. Mon intuition était que-sysservait aux crates qui encapsulent des bibliothèques système non écrites en RustMais dans ce cadre, le suffixe
-rs-sysn’a plus beaucoup de sens, donc mon intuition doit être fausse. Quelqu’un a une source faisant autorité là-dessus ?*-sys: convention ancienne et très répandue, documentée ici : https://doc.rust-lang.org/cargo/reference/… . Mais elle ne correspond pas du tout à cette cratelib*: on sait déjà que c’est une bibliothèque, ce préfixe n’est pas d’usage en Rust, et le lien ci-dessus indique même à moitié explicitement de l’éviter avec*-sys.libzstd-syspourrait laisser penser qu’on va lierliblibzstd. Et d’ailleurs, même hors Rust, j’ai déjà vu des noms avecliben double*-rs: comme l’indique https://rust-lang.github.io/api-guidelines/naming.html , « toutes les crates sont en Rust ! inutile de le rappeler sans cesse aux utilisateurs »-sysexposent généralement une interface de type C très brute, contiennent beaucoup de code unsafe et construisent ou lient en général une bibliothèque externeJ’ai vu le nom
-rs-sysutilisé de manière moins cohérente. Il semble servir pour des bibliothèques qui compilent du code externe reconditionné dans une crate Rust, par exemple une implémentation Rust incomplète où il reste encore des parties en C, ou du code de support Rust pour une sys cratelibzstdest le nom d’origine. Les bibliothèques C ont tendance à inclurelibdans leur nom, et celui-ci a été conservé comme référence au lieu d’être adapté aux conventions Rust/Cargo-rssignale une réécriture en Rust pour la distinguer de l’implémentation C de Facebook. C’est un suffixe générique assez courant dans plusieurs projets Rust, un peu comme les bibliothèques Python nomméespysomething-sysvient du fait que cette implémentation expose une API C unsafe en remplacement direct. Du point de vue d’un utilisateur Cargo, ce n’est pas une bibliothèque Rust. Elle n’a pas d’interface Rust et s’utilise comme du code C avec des fonctions CDonc ce n’est pas
-rs-sys, mais la version-sysdelibzstd-rsPourquoi choisir ça plutôt que ruzstd ? Ne vaudrait-il pas mieux investir dans la crate existante ?
Un portage 1:1 permet d’obtenir assez directement des performances similaires et une parité fonctionnelle, au lieu de devoir redécouvrir comment produire un compresseur tout aussi rapide et complet à partir d’une autre base de code
« L’implémentation C de référence est maintenue par Meta, et il faut signer un accord de contribution avec Meta pour y contribuer »
J’ai appris récemment un détail amusant : l’implémentation zstd de référence maintenue par Facebook est elle aussi codée avec des LLM, et comme c’est aussi une dépendance d’openssl, je suis entièrement pour le fait d’avoir davantage d’alternatives
« Avec les réglages par défaut, les performances de décompression de notre implémentation sont de quelques pourcents inférieures à celles de l’implémentation C de référence »
C’est tout ce que j’ai besoin de savoir sur ce projet
Pour référence, juste après la phrase citée, il est écrit ceci
« Cela dit, en activant le flag de fonctionnalité
unsafe-performance-experimental, on retrouve les performances du C, donc nous estimons que cette perte de performance est justifiable. Ce flag désactive 4 vérifications de limites à quatre endroits où les données d’entrée servent à indexer des structures de données. Pour la plupart des utilisateurs, une perte d’environ 3 % est probablement un coût acceptable en échange d’un gain en sûreté mémoire. Si vous avez vraiment besoin de gratter la toute dernière parcelle de performance, vous pouvez activer ce flag à vos risques et périls. Le comportement à ces quatre emplacements est alors identique à celui du C sans vérification de limites, et cela semble fonctionner sans problème dans de nombreux systèmes en production »