nyvo

Nyvo archive format specification

Important links:

0. About this specification

This specification should serve as a detailed description of the Nyvo archive format. It is currently incomplete and should therefore not be your single source of information about the format.

In the following, the Nyvo archive format will be called “Nyvo” for simplicity.

Current specification version: 1

1. General information

1.1. File extensions

It is recommended to use the one of the following file extensions for Nyvo:

1.2. Endianness

Nyvo uses Little-endian (LE) byte order everywhere without exceptions.

1.3. Variable-length integers

Also, Nyvo makes extensive use of variable-length integers (unsigned LEB128 encoding), which are also used in the RAR 5.0 archive format and a wide range of other projects, including WebAssembly, LLVM and Android.

In the following (and the reference implementation), this kind of variable-length unsigned integers is referred to as vu8. The theoretical limit of this encoding is infinite, but the reference implementation cannot handle more bits than the target architecture supports (e.g. 64 bits for amd64/x86_64 or other 64-bit architectures, 32 bits for i386/x86_32 and so on) due to internal memory adressing by the Rust programming language.

[!CAUTION]
Archives with variable integers larger than platform word size may cause unexpected errors.

As this encoding is widely used, it is considered trivial and will not be documented here.

LEB128 on Wikipedia

2. Content structure

Section Notes
Magic value always the first 8 bytes
Archive metadata  
Encryption methods  
Store methods  

After these headers, one of the three headers may follow:

Parsing should end if EOF is reached. This allows append operations.

2.1. Magic value

Always the first 8 bytes of the archive. This should be used to detect the Nyvo format itself when checking the archive type.

Type Name Content Notes
u8[8] magic value a8 28 4e 79 76 6f 28 a8 escaped string:\xa8\x28Nyvo\x28\xa8

2.2. Archive metadata

Type Name Content Notes
vu8 Format version Spec version -1 0 for Nyvo v1
vu8 Encryption method count Number of entries in the encryption methods header  
vu8 Store method count Number of entries in the store methods header  

2.3. Encryption methods

This is an array of encryption methods with the length stored in the archive metadata header.

An entry of this header is structured in this format:

Type Name Content Notes
vu8 Encryption algorithm Encryption algorithm used for content encryption  
vu8 Key derivation memory Memory cost for Argon2id key derivation  
vu8 Key derivation iterations Iteration cost for Argon2id key derivation  
vu8 Key derivation parallelism Parallelism cost for Argon2id key derivation  
u8[32] Salt Key derivation salt  
vu8 KEK count Key encryption key count  
Key[] Keys Key encryption keys  

[!IMPORTANT]
Key derivation fields may not exceed 32 bits.

2.3.1. Encryption algorithm IDs

ID Name
0 AES-256-GCM-SIV

More will be added in the future. For now, only AES-256-GCM-SIV is recommended and supported.

2.3.2. Key

Type Name Content Notes
u8[12] Nonce DEK cipher nonce  
u8[48] DEK Data encryption key cipher 32-byte AES-256 key + 16-byte GCM-SIV tag

The DEK will always be encrypted with AES-256-GCM-SIV, no matter what the “Encryption algorithm” fields says.

Content decryption steps:

  1. Obtain a valid decryption passphrase of any length.
  2. Pass the passphrase into the Argon2id key derivation function with correct parameters. This will return a KEK.
  3. Try decrypting every DEK cipher using the KEK.

2.4. Store methods

This is an array of store methods with the length stored in the archive metadata header.

An entry of this header is structured in this format:

Type Name Content Notes
vu8 Encryption method ID of the encryption method to use + 1 0 for no encryption, 1 for encryption using the first method, …
vu8 Compression algorithm Compression algorithm used for content compression 0 for no compression

2.4.1. Compression algorithm IDs

ID Name
0 None (don’t compress)
1 Zstandard

More will be added in the future.

2.5. Content information header

Type Name Content Notes
bool Is index true if the following content is an index Highest bit of byte 0
Store option reference Store option ID of the store option used for following content Lower 7 bits of byte 0
optional vu8 Store option ID Custom store option ID Only present if Store option = Custom (1)
vu8 Length Length of the following content in bytes  
u8[16] Checksum BLAKE3-256 Checksum of the next Length bytes  

2.5.1. Store option reference

7-bit enum

Value Name Notes
0 Default Store option 0 if defined, else format default
1 Custom References a custom store option ID in a vu8
2 Copy Reuses the store option the content before used. If not used before, Default (0).
3 Increment Increments the store option the content before used by 1. If not used before, Default (0).
4 Decrement Decrements the store option the content before used by 1. If not used before, Default (0).

2.6. Index header

This header can be compressed and encrypted according to its corresponding store option.

Because file directories are structured like trees, the index header is structured like a tree as well. This makes a little harder to parse than other archive formats, because an entry only contains parts of its path to save space.

Type Name Content Notes
bool      

2.7. Content header

This header can be compressed and encrypted according to its corresponding store option.

Type Name Content Notes
u8[] Content raw file contents  

// TODO: complete this spec