6 points par GN⁺ 3 시간 전 | 1 commentaires | Partager sur WhatsApp
  • 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-sys peut, 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 main est 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 zstd qui utilise libzstd-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-safe utilise des enum, mais il y a un décalage car il faut utiliser des struct pour assurer la sûreté FFI
  • Soutien

1 commentaires

 
GN⁺ 3 시간 전
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

    • Oui, clairement. En cryptographie, les contournements viennent bien plus souvent de défauts d’implémentation que d’algorithmes réellement cassés
      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
    • Si les exigences de performance du projet ne sont pas trop strictes et que tu peux tolérer un peu de FFI, il est aussi possible d’utiliser la pile crypto de Go depuis Rust
      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 -sys et -rs-sys. Mon intuition était que -sys servait aux crates qui encapsulent des bibliothèques système non écrites en Rust
    Mais dans ce cadre, le suffixe -rs-sys n’a plus beaucoup de sens, donc mon intuition doit être fausse. Quelqu’un a une source faisant autorité là-dessus ?

    • Ce nom de package est à peu près aussi mauvais qu’on peut l’imaginer. Trois des quatre parties du nom sont erronées ou peu souhaitables
      *-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 crate
      lib* : 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-sys pourrait laisser penser qu’on va lier liblibzstd. Et d’ailleurs, même hors Rust, j’ai déjà vu des noms avec lib en 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 »
    • Les crates -sys exposent 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 externe
      J’ai vu le nom -rs-sys utilisé 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 crate
    • Il y a quand même une certaine logique
      libzstd est le nom d’origine. Les bibliothèques C ont tendance à inclure lib dans leur nom, et celui-ci a été conservé comme référence au lieu d’être adapté aux conventions Rust/Cargo
      -rs signale 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ées pysomething
      -sys vient 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 C
      Donc ce n’est pas -rs-sys, mais la version -sys de libzstd-rs
  • Pourquoi choisir ça plutôt que ruzstd ? Ne vaudrait-il pas mieux investir dans la crate existante ?

    • ruzstd n’implémente pas encore complètement la compression
      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

    • Tu pourrais expliquer un peu plus ce que cette phrase t’inspire ?
      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 »