1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*!

#### A simple archiving format, designed for storing assets in compact secure containers
`vach` is an archiving and resource transmission format.
It was built to be secure, contained and protected. A big benefit of `vach` is the fine grained control it grants it's users, as it allows for per-entry independent configuration.
`vach` also has in-built support for multiple compression schemes (LZ4, Snappy and Brolti), [data signing](https://github.com/dalek-cryptography/ed25519-dalek), leaf [bitflags](https://docs.rs/vach/latest/vach/archive/struct.Flags.html), [encryption](https://docs.rs/aes-gcm/latest/aes_gcm/) and some degree of archive customization.
> Check out the `vach` spec at **[spec.txt](https://github.com/zeskeertwee/vach/blob/main/spec/main.txt)**.
### 👄 Terminologies
- **Archive:** Any source of data, for example a file or TCP stream, that is a valid `vach` data source.
- **Leaf:** Any actual data endpoint within an archive, what `tar` calls archive members, for example `footstep1.wav` in `sounds.vach`.
- **Entry:** Some data in the registry section of a `vach` source on an corresponding [leaf](crate::builder::Leaf). For example, `{ id: footstep.wav, location: 45, offset: 2345, flags: 0b0000_0000_0000_0000u16 }`.
### 🔫 Cargo Features
- `archive` and `builder` (default): Turning them off turns off their respective modules. For example a game only needs the `archive` feature but a tool for packing assets would only need the `builder` feature.
- `multithreaded`: Pulls [rayon](https://crates.io/crates/rayon) as a dependency and adds [`Send`] as a trait bound to many generic types. This allows for the auto-parallelization of the `Builder::dump(---)` function.
- `compression`: Pulls `snap`, `lz4_flex` and `brotli` as dependencies and allows for compression in `vach` archives.
- `crypto`: Enables encryption and authentication functionality by pulling the `ed25519_dalek` and `aes_gcm` crates
### 🀄 Show me some code _dang it!_
##### > Building a basic unsigned `.vach` file
```ignore
use std::{io::Cursor, fs::File};
use vach::prelude::{Builder, BuilderConfig};
let config = BuilderConfig::default();
let mut builder = Builder::default();
// Use `Builder::add( reader, ID )` to add data to the write queue
// Adds any data that implements `io::Read`
builder.add(File::open("test_data/background.wav")?, "ambient").unwrap();
builder.add(&[12, 23, 34, 45, 56, 67, 78, 90, 69], "ftstep").unwrap();
builder.add(b"Hello, Cassandra!", "hello").unwrap();
// let mut target = File::create("sounds.vach")?;
let mut target = Cursor::new(Vec::new());
// The number of bytes written to the file
let size = builder.dump(&mut target, &config).unwrap();
```
##### > Loading resources from an unsigned `.vach` file
```ignore
use std::fs::File;
use vach::prelude::{Archive, Resource, Flags};
let target = File::open("sounds.vach")?;
let mut archive = Archive::new(target)?;
let resource: Resource = archive.fetch_mut("ambient")?;
// By default all resources are flagged as NOT authenticated
println!("{}", Sound::new(&resource.data)?);
assert!(!resource.authenticated);
let resource = archive.fetch_mut("ftstep")?;
```
##### > Build a signed `.vach` file
```ignore
use std::{io::Cursor, fs::File};
use vach::prelude::{Builder, BuilderConfig, Keypair};
use vach::crypto_utils::gen_keypair;
let keypair: Keypair = gen_keypair();
let config: BuilderConfig = BuilderConfig::default().keypair(keypair);
let mut builder = Builder::default();
// Use `Builder::add( reader, ID )` to add data to the write queue
builder.add(File::open("test_data/background.wav")?, "ambient").unwrap();
builder.add(vec![12, 23, 34, 45, 56, 67, 78], "ftstep").unwrap();
builder.add(b"Hello, Cassandra!" as &[u8], "hello").unwrap();
let mut target = File::create("sounds.vach")?;
builder.dump(&mut target, &config).unwrap();
let mut target = Cursor::new(Vec::new());
builder.dump(&mut target, &config).unwrap();
```
##### > Load resources from a signed `.vach` source
```ignore
// Load public_key
let mut public_key = File::open(PUBLIC_KEY)?;
let mut public_key_bytes: [u8; crate::PUBLIC_KEY_LENGTH];
public_key.read_exact(&mut public_key_bytes)?;
// Build the Loader config
let mut config = ArchiveConfig::default().key(PublicKey::from_bytes(&public_key_bytes)?);
let target = File::open("sounds.vach")?;
let archive = Archive::with_config(target, &config)?;
// Resources are marked as secure (=true) if the signatures match the data
let mut resource = archive.fetch_mut("ambient")?;
println!("{}", Sound::new(&resource.data)?);
assert!(resource.authenticated);
```
##### > Serialize and de-serialize a `Keypair`, `SecretKey` and `PublicKey`
As `Keypair`, `SecretKey` and `PublicKey` are reflected from [ed25519_dalek](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/), you could refer to their docs to read further about them. These are needed for any cryptography related procedures,
```ignore
use vach::prelude::{Keypair, SecretKey, PublicKey};
use vach::crypto_utils::gen_keypair;
// Generate keys
let keypair : Keypair = gen_keypair();
let secret : SecretKey = keypair.secret;
let public : PublicKey = keypair.public;
// Serialize
let public_key_bytes : [u8; vach::PUBLIC_KEY_LENGTH] = public.to_bytes();
let secret_key_bytes : [u8; vach::SECRET_KEY_LENGTH] = secret.to_bytes();
let keypair_bytes : [u8; vach::KEYPAIR_LENGTH] = keypair.to_bytes();
// Deserialize
let public_key : PublicKey = PublicKey::from_bytes(&public_key_bytes).unwrap();
let secret_key : SecretKey = SecretKey::from_bytes(&secret_key_bytes).unwrap();
let keypair : Keypair = Keypair::from_bytes(&keypair_bytes).unwrap();
```
*/
/// All tests are included in this module.
pub
pub
pub
// Re-export
pub use rand;
pub use rayon;
/// Current [`vach`](crate) spec version. increments by ten with every spec change
pub const VERSION: u16 = 30;
/// Size of a keypair: (secret + public)
pub const KEYPAIR_LENGTH: usize = 64;
/// Size of a secret key
pub const SECRET_KEY_LENGTH: usize = 32;
/// Size of a public key
pub const PUBLIC_KEY_LENGTH: usize = 32;
/// Size of a signature
pub const SIGNATURE_LENGTH: usize = 64;
/// Maximum size for any ID
pub const MAX_ID_LENGTH: usize = 65535; // u16::MAX
/// The standard size of any MAGIC entry in bytes
pub const MAGIC_LENGTH: usize = 5;
/// The default MAGIC used by `vach`
pub const DEFAULT_MAGIC: & = b"VfACH";
/// Consolidated import for crate logic; This module stores all `structs` associated with this crate. Constants can be accesses [directly](#constants) with `crate::<CONSTANT>`
/// Import keypairs and signatures from here, mirrors from `ed25519_dalek`
/// [`Builder`](crate::builder::Builder) related data structures and logic
/// Loader-based logic and data-structures
/// Some utility functions to keep you happy