6 puntos por GN⁺ 3 시간 전 | 1 comentarios | Compartir por WhatsApp
  • libzstd-rs-sys es el tercer proyecto de compresión de la Fundación Trifecta, después de zlib y bzip2, y es la primera versión de zstd basada en Rust
  • Zstd es un formato de compresión adaptado a CPUs modernas; es más rápido que gzip y también ofrece una mejor tasa de compresión, por lo que se espera que reemplace gradualmente a gzip en el tráfico web
  • El crate zstd existente en Rust compila código C desde el código fuente, por lo que requiere una toolchain de C y soporte para el objetivo, lo que puede dificultar la configuración en Windows y WebAssembly
  • La implementación en Rust puede compilarse como una biblioteca C compatible como reemplazo directo, y se está validando como alternativa a la implementación de referencia en C mediante un suite de pruebas, fuzz testing y Miri
  • La descompresión predeterminada es unos pocos puntos porcentuales más lenta que en C, pero la caída de rendimiento de ~3% es el costo de la seguridad de memoria, y con una bandera experimental puede igualar el rendimiento de C

Primera versión y significado de la implementación en Rust

  • Trifecta Tech Foundation anunció la primera versión de libzstd-rs-sys, que trabaja con zstd como su tercer proyecto de compresión después de zlib y bzip2
  • Zstd es un formato de compresión diseñado pensando en CPUs modernas, y puede ser mucho más rápido que gzip además de lograr una mejor tasa de compresión
  • zstd ya se usa ampliamente y se espera que reemplace gradualmente a gzip en el tráfico web
  • En Rust ya es posible usar zstd mediante el crate zstd, pero el crate existente compila código C desde el código fuente, por lo que requiere una toolchain de C y soporte para el objetivo
  • Configurar una toolchain de C para Windows o WebAssembly puede ser complicado, así que una implementación pura en Rust ofrece una mejor experiencia de dependencias para desarrolladores de Rust
  • libzstd-rs-sys puede compilarse como una biblioteca C compatible como reemplazo directo, igual que el trabajo hecho con zlib y bzip2, y apunta a ser una alternativa a la implementación de referencia en C
  • La implementación de referencia en C es mantenida por Meta, y para contribuir es necesario firmar un acuerdo entre Meta y el contribuidor, por lo que una implementación independiente, compatible y con buen rendimiento puede fortalecer el ecosistema open source

Validación, rendimiento y trabajo pendiente

  • La implementación de referencia inicial fue convertida con c2rust, y después se completó el trabajo de limpieza en la descompresión y el constructor de diccionarios
  • El código Rust se compila como una biblioteca estática de C y luego se valida con el suite de pruebas de la implementación de referencia
  • También se usan fuzz testing y Miri para verificar la corrección de la implementación
  • La pre-release está disponible en libzstd-rs-sys v0.0.1-prerelease.2
  • El costo de la seguridad de memoria

    • El rendimiento de descompresión predeterminado es unos pocos puntos porcentuales más lento que el de la implementación de referencia en C
    • Cada cambio que se integra en main se mide con el suite de benchmarks
    • Si se activa la feature flag unsafe-performance-experimental, se iguala el rendimiento de C
    • Esta bandera desactiva verificaciones de límites en cuatro puntos donde los datos de entrada se usan para indexar estructuras de datos
    • Para la mayoría de usuarios, una caída de rendimiento de alrededor de 3% probablemente sea un costo aceptable a cambio de una mejor seguridad de memoria
    • Si se necesita hasta el último punto de rendimiento, se puede activar esa bandera asumiendo el riesgo, y el comportamiento en esos cuatro puntos coincide con C, que no hace verificaciones de límites
  • Implementación de compresión e integración con el ecosistema

    • La parte de compresión todavía está buscando financiamiento
    • Existe código compartido entre compresión y descompresión, así que ya se revisó parte del código de compresión, pero aún queda la mayor parte del trabajo de limpieza
    • Ya se configuraron benchmarks para evitar regresiones de rendimiento en compresión, y se está verificando con el suite de pruebas de la implementación de referencia que genere resultados correctos
    • El trabajo pendiente está resumido en Milestone 4: Encoder implementation
    • Hay un fork de zstd que usa libzstd-rs-sys en lugar de la biblioteca C, y se espera integrarlo upstream en el futuro
    • En las APIs más usadas, la integración es relativamente simple
    • En la feature experimental, zstd-safe usa enum, pero existe una discrepancia porque para seguridad de FFI se debe usar struct
  • Patrocinio

1 comentarios

 
GN⁺ 3 시간 전
Opiniones en Lobste.rs
  • De verdad es una noticia muy bienvenida. Hace unos días, por una dependencia tuve que traer libc-dev para intentar hacer un build de zstd, y me preguntaba si alguien ya había intentado una reimplementación seria en Rust
    Ojalá la comunidad la adopte ampliamente

  • Estoy haciendo un proyecto basado en WireGuard en Rust, así que he estado trayendo varias librerías criptográficas de Rust. La seguridad de memoria es una ventaja clara, pero a diferencia de las viejas librerías en C, no todas han pasado por una auditoría de seguridad
    Al final, lo que me pregunto es si reescribir estos algoritmos en Rust realmente vale el costo

    • Sí, vale totalmente la pena. La criptografía se elude mucho más a menudo por fallas de implementación que porque el algoritmo mismo esté roto
      El código “aburrido” no criptográfico, como parsing, estado del protocolo y manejo de buffers, tiene que funcionar bien para que el sistema sea seguro. Si un atacante puede mandar un paquete mágico que permita ejecución arbitraria de código, no va a perder tiempo con criptoanálisis avanzado ni canales laterales de timing para reducir un descifrado de miles de años a unas décadas
    • Si los requisitos de rendimiento del proyecto no son demasiado estrictos y puedes tolerar un poco de FFI, también es posible usar el stack criptográfico de Go desde Rust
      Ambos lados tienen seguridad de memoria, y la ventaja es que solo hace falta una frontera FFI unsafe y estrecha. Las librerías criptográficas de Go hoy están más maduras que las de Rust, o más precisamente que lo que ofrece el ecosistema de crates.io
  • Me pregunto si alguien conoce una explicación documentada de cuándo se debe usar el sufijo -sys y cuándo -rs-sys. Por intuición, pensaba que -sys era para crates que envuelven librerías del sistema no escritas en Rust
    Pero bajo ese criterio, el sufijo -rs-sys no se entiende muy bien, así que supongo que mi intuición estaba equivocada. ¿Alguien conoce una fuente autorizada?

    • Este nombre de paquete está, de una manera imaginable, casi al nivel de lo peor posible. Tres de las cuatro partes del nombre son incorrectas o poco deseables
      *-sys: es una convención vieja y muy usada, explicada en https://doc.rust-lang.org/cargo/reference/…. Pero no encaja en absoluto con este crate
      lib*: ya sabemos que es una librería, en Rust este prefijo no es una convención, y en el enlace de arriba incluso se señala medio explícitamente que conviene evitarlo junto con *-sys. libzstd-sys podría hacer pensar que enlaza con liblibzstd. Además, incluso fuera de Rust sí he visto nombres reales con doble lib
      *-rs: como dice https://rust-lang.github.io/api-guidelines/naming.html, “¡todos los crates son Rust! No hace falta recordárselo constantemente al usuario”
    • Los crates -sys normalmente exponen una interfaz estilo C muy cruda, contienen mucho código unsafe y por lo general compilan o enlazan una librería externa
      He visto que el nombre -rs-sys se usa de manera menos consistente. Parece usarse para librerías que compilan código externo reempaquetado dentro de un crate de Rust, por ejemplo una implementación incompleta en Rust que todavía conserva partes en C, o código de soporte en Rust para un sys crate
    • Sí tiene cierta lógica
      libzstd es el nombre original. Las librerías de C tienden a incluir lib en el nombre, y aquí lo dejaron igual como referencia en vez de adaptarlo a las convenciones de Rust/Cargo
      -rs marca que es una reescritura en Rust, para distinguirla de la implementación en C de Facebook. Es un sufijo bastante común en varios proyectos de Rust, parecido a cómo algunas librerías de Python se nombran como pysomething
      -sys está porque esta implementación expone una API unsafe de C como reemplazo drop-in. Desde la perspectiva del usuario de Cargo, no es una librería de Rust. No tiene interfaz Rust; se llama como código C con funciones C
      Así que no es -rs-sys, sino la versión -sys de libzstd-rs
  • ¿Por qué elegir esto en vez de ruzstd? ¿No sería mejor invertir en el crate existente?

    • ruzstd todavía no implementa completamente la compresión
      Un port 1:1 permite lograr velocidad similar y paridad de funciones mediante una transformación de código relativamente directa, en vez de tener que redescubrir cómo construir un compresor igual de rápido y completo sobre otra base de código
  • “La implementación de referencia en C la mantiene Meta, y para contribuir hay que firmar un acuerdo de contribuyente con Meta”
    Hace poco me enteré de un dato curioso: la implementación de referencia de zstd mantenida por Facebook también está siendo programada con LLM, y además es una dependencia de openssl, así que estoy totalmente a favor de que haya más alternativas

  • “Con la configuración por defecto, el rendimiento de descompresión de nuestra implementación es unos cuantos puntos porcentuales más lento que la implementación de referencia en C”
    Eso es todo lo que necesito saber sobre este proyecto

    • ¿Podrías explicar un poco más cómo te cayó esa frase?
      Como referencia, justo después de la frase citada sigue esto
      “Sin embargo, al activar el feature flag unsafe-performance-experimental, se iguala el rendimiento de C, por lo que creemos que esta pérdida de rendimiento es justificable. Este flag desactiva 4 verificaciones de límites en cuatro lugares donde los datos de entrada se usan para indexar estructuras de datos. Para la mayoría de los usuarios, una pérdida de rendimiento de alrededor de 3% probablemente sea un costo aceptable a cambio de una mejor seguridad de memoria. Si realmente necesitas hasta la última gota de rendimiento, puedes activar este flag bajo tu propia responsabilidad. El comportamiento en estos cuatro puntos es el mismo que en C sin verificaciones de límites, y parece funcionar sin problemas en muchos sistemas de producción”