create-sia-app 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +179 -0
- package/package.json +29 -0
- package/template/CLAUDE.md +160 -0
- package/template/README.md +102 -0
- package/template/_gitignore +5 -0
- package/template/biome.json +40 -0
- package/template/index.html +13 -0
- package/template/package.json +30 -0
- package/template/rust/README.md +16 -0
- package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +6 -0
- package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +16 -0
- package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +5 -0
- package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +13 -0
- package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +5 -0
- package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +5 -0
- package/template/rust/sia-sdk-rs/.github/dependabot.yml +10 -0
- package/template/rust/sia-sdk-rs/.github/workflows/main.yml +36 -0
- package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +34 -0
- package/template/rust/sia-sdk-rs/.github/workflows/release.yml +30 -0
- package/template/rust/sia-sdk-rs/.rustfmt.toml +4 -0
- package/template/rust/sia-sdk-rs/Cargo.lock +4127 -0
- package/template/rust/sia-sdk-rs/Cargo.toml +3 -0
- package/template/rust/sia-sdk-rs/LICENSE +21 -0
- package/template/rust/sia-sdk-rs/README.md +30 -0
- package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +79 -0
- package/template/rust/sia-sdk-rs/indexd/Cargo.toml +79 -0
- package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +258 -0
- package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +1710 -0
- package/template/rust/sia-sdk-rs/indexd/src/builder.rs +354 -0
- package/template/rust/sia-sdk-rs/indexd/src/download.rs +379 -0
- package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +659 -0
- package/template/rust/sia-sdk-rs/indexd/src/lib.rs +827 -0
- package/template/rust/sia-sdk-rs/indexd/src/mock.rs +162 -0
- package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +125 -0
- package/template/rust/sia-sdk-rs/indexd/src/quic.rs +575 -0
- package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +52 -0
- package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +497 -0
- package/template/rust/sia-sdk-rs/indexd/src/upload.rs +629 -0
- package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +41 -0
- package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +398 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +76 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +47 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +10 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +130 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +3 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +377 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +155 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +1039 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +58 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +23 -0
- package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +33 -0
- package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +818 -0
- package/template/rust/sia-sdk-rs/knope.toml +54 -0
- package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +38 -0
- package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +19 -0
- package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +278 -0
- package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +91 -0
- package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +59 -0
- package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +12 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +22 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +767 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +257 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +291 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +26 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +367 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +6 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +303 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +347 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +15 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +435 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +112 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +357 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +1507 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +146 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +7 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +278 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +236 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +677 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +450 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +110 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +778 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +117 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +1737 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +1726 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +59 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +16 -0
- package/template/scripts/setup-rust.js +29 -0
- package/template/src/App.tsx +13 -0
- package/template/src/components/DevNote.tsx +21 -0
- package/template/src/components/auth/ApproveScreen.tsx +84 -0
- package/template/src/components/auth/AuthFlow.tsx +77 -0
- package/template/src/components/auth/ConnectScreen.tsx +214 -0
- package/template/src/components/auth/LoadingScreen.tsx +8 -0
- package/template/src/components/auth/RecoveryScreen.tsx +182 -0
- package/template/src/components/upload/UploadZone.tsx +314 -0
- package/template/src/index.css +9 -0
- package/template/src/lib/constants.ts +8 -0
- package/template/src/lib/format.ts +35 -0
- package/template/src/lib/hex.ts +13 -0
- package/template/src/lib/sdk.ts +25 -0
- package/template/src/lib/wasm-env.ts +5 -0
- package/template/src/main.tsx +12 -0
- package/template/src/stores/auth.ts +86 -0
- package/template/tsconfig.app.json +31 -0
- package/template/tsconfig.json +7 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vite.config.ts +18 -0
- package/template/wasm/indexd_wasm/indexd_wasm.d.ts +309 -0
- package/template/wasm/indexd_wasm/indexd_wasm.js +1507 -0
- package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
- package/template/wasm/indexd_wasm/package.json +31 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
use std::collections::{HashMap, HashSet};
|
|
2
|
+
use std::sync::{Arc, RwLock};
|
|
3
|
+
use std::time::Duration;
|
|
4
|
+
|
|
5
|
+
use bytes::Bytes;
|
|
6
|
+
use chrono::Utc;
|
|
7
|
+
use sia::rhp::{self, HostPrices};
|
|
8
|
+
use sia::signing::{PrivateKey, PublicKey, Signature};
|
|
9
|
+
use sia::types::{Currency, Hash256};
|
|
10
|
+
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
11
|
+
use tokio::time::sleep;
|
|
12
|
+
|
|
13
|
+
use crate::rhp4::{self, RHP4Client};
|
|
14
|
+
use crate::{
|
|
15
|
+
DownloadError, DownloadOptions, Downloader, Hosts, Object, PackedUpload, UploadError,
|
|
16
|
+
UploadOptions, Uploader,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
pub struct MockRHP4Client {
|
|
20
|
+
sectors: RwLock<HashMap<PublicKey, HashMap<Hash256, Bytes>>>,
|
|
21
|
+
slow_hosts: RwLock<HashSet<PublicKey>>,
|
|
22
|
+
slow_delay: RwLock<Duration>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl MockRHP4Client {
|
|
26
|
+
pub fn new() -> Self {
|
|
27
|
+
Self {
|
|
28
|
+
sectors: RwLock::new(HashMap::new()),
|
|
29
|
+
slow_hosts: RwLock::new(HashSet::new()),
|
|
30
|
+
slow_delay: RwLock::new(Duration::ZERO),
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub fn clear(&self) {
|
|
35
|
+
self.sectors.write().unwrap().clear();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Sets the given hosts as "slow" - they will sleep for the specified duration
|
|
39
|
+
/// before completing any write_sector or read_sector operation.
|
|
40
|
+
pub fn set_slow_hosts(&self, hosts: impl IntoIterator<Item = PublicKey>, delay: Duration) {
|
|
41
|
+
let mut slow = self.slow_hosts.write().unwrap();
|
|
42
|
+
slow.clear();
|
|
43
|
+
slow.extend(hosts);
|
|
44
|
+
*self.slow_delay.write().unwrap() = delay;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Clears all slow host settings.
|
|
48
|
+
pub fn reset_slow_hosts(&self) {
|
|
49
|
+
self.slow_hosts.write().unwrap().clear();
|
|
50
|
+
*self.slow_delay.write().unwrap() = Duration::ZERO;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl RHP4Client for Arc<MockRHP4Client> {
|
|
55
|
+
async fn host_prices(&self, _: PublicKey, _: bool) -> Result<HostPrices, rhp4::Error> {
|
|
56
|
+
Ok(HostPrices {
|
|
57
|
+
contract_price: Currency::zero(),
|
|
58
|
+
collateral: Currency::zero(),
|
|
59
|
+
ingress_price: Currency::zero(),
|
|
60
|
+
egress_price: Currency::zero(),
|
|
61
|
+
storage_price: Currency::zero(),
|
|
62
|
+
free_sector_price: Currency::zero(),
|
|
63
|
+
tip_height: 0,
|
|
64
|
+
signature: Signature::default(),
|
|
65
|
+
valid_until: Utc::now() + chrono::Duration::days(1),
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async fn write_sector(
|
|
70
|
+
&self,
|
|
71
|
+
host_key: PublicKey,
|
|
72
|
+
_: &PrivateKey,
|
|
73
|
+
sector: Bytes,
|
|
74
|
+
) -> Result<Hash256, rhp4::Error> {
|
|
75
|
+
// Check if this host is configured as slow
|
|
76
|
+
let slow_delay = {
|
|
77
|
+
let slow_hosts = self.slow_hosts.read().unwrap();
|
|
78
|
+
if slow_hosts.contains(&host_key) {
|
|
79
|
+
Some(*self.slow_delay.read().unwrap())
|
|
80
|
+
} else {
|
|
81
|
+
None
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
if let Some(delay) = slow_delay {
|
|
85
|
+
sleep(delay).await;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
sleep(Duration::from_millis(3)).await; // simulate network latency ~ 10Gbps
|
|
89
|
+
let sector_root = rhp::sector_root(§or);
|
|
90
|
+
let mut sectors = self.sectors.write().unwrap();
|
|
91
|
+
let host_sectors = sectors.entry(host_key).or_default();
|
|
92
|
+
host_sectors.insert(sector_root, sector);
|
|
93
|
+
Ok(sector_root)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async fn read_sector(
|
|
97
|
+
&self,
|
|
98
|
+
host_key: PublicKey,
|
|
99
|
+
_: &PrivateKey,
|
|
100
|
+
root: Hash256,
|
|
101
|
+
offset: usize,
|
|
102
|
+
length: usize,
|
|
103
|
+
) -> Result<Bytes, rhp4::Error> {
|
|
104
|
+
let sector = {
|
|
105
|
+
let sectors = self.sectors.read().unwrap();
|
|
106
|
+
let host_sectors = sectors
|
|
107
|
+
.get(&host_key)
|
|
108
|
+
.ok_or_else(|| rhp4::Error::Transport("host not found".to_string()))?;
|
|
109
|
+
let sector = host_sectors
|
|
110
|
+
.get(&root)
|
|
111
|
+
.ok_or_else(|| rhp4::Error::Transport("sector not found".to_string()))?;
|
|
112
|
+
sector.slice(offset..offset + length)
|
|
113
|
+
};
|
|
114
|
+
sleep(Duration::from_nanos(sector.len() as u64 * 8 / 10)).await; // simulate network latency ~ 10Gbps
|
|
115
|
+
Ok(sector)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
pub struct MockUploader {
|
|
120
|
+
uploader: Uploader<Arc<MockRHP4Client>>,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
impl MockUploader {
|
|
124
|
+
pub fn new(hosts: Hosts, client: Arc<MockRHP4Client>, app_key: Arc<PrivateKey>) -> Self {
|
|
125
|
+
Self {
|
|
126
|
+
uploader: Uploader::new(hosts, client.clone(), app_key),
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
pub async fn upload<R: AsyncReadExt + Send + Sync + Unpin + 'static>(
|
|
131
|
+
&self,
|
|
132
|
+
r: R,
|
|
133
|
+
options: UploadOptions,
|
|
134
|
+
) -> Result<Object, UploadError> {
|
|
135
|
+
self.uploader.upload(r, options).await
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
pub fn upload_packed(&self, options: UploadOptions) -> PackedUpload {
|
|
139
|
+
self.uploader.upload_packed(options)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
pub struct MockDownloader {
|
|
144
|
+
downloader: Downloader<Arc<MockRHP4Client>>,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
impl MockDownloader {
|
|
148
|
+
pub fn new(hosts: Hosts, client: Arc<MockRHP4Client>, app_key: Arc<PrivateKey>) -> Self {
|
|
149
|
+
Self {
|
|
150
|
+
downloader: Downloader::new(hosts, client.clone(), app_key),
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
pub async fn download<W: AsyncWriteExt + Send + Sync + Unpin>(
|
|
155
|
+
&self,
|
|
156
|
+
w: &mut W,
|
|
157
|
+
object: &Object,
|
|
158
|
+
options: DownloadOptions,
|
|
159
|
+
) -> Result<(), DownloadError> {
|
|
160
|
+
self.downloader.download(w, object, options).await
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
use chacha20poly1305::aead::{Aead, OsRng};
|
|
2
|
+
use chacha20poly1305::{AeadCore, KeyInit, XChaCha20Poly1305};
|
|
3
|
+
use sia::blake2::Blake2b256;
|
|
4
|
+
use sia::encryption::EncryptionKey;
|
|
5
|
+
use sia::signing::PrivateKey;
|
|
6
|
+
use sia::types::Hash256;
|
|
7
|
+
use thiserror::Error;
|
|
8
|
+
|
|
9
|
+
const NONCE_SIZE: usize = 24;
|
|
10
|
+
|
|
11
|
+
#[derive(Error, Debug)]
|
|
12
|
+
pub enum DecryptError {
|
|
13
|
+
#[error("decryption error")]
|
|
14
|
+
Decryption,
|
|
15
|
+
#[error("invalid encryption key length")]
|
|
16
|
+
KeyLength,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pub(crate) fn derive(key: &[u8], salt: &[u8], domain: &[u8], okm: &mut [u8]) {
|
|
20
|
+
let hkdf = hkdf::SimpleHkdf::<Blake2b256>::new(Some(salt), key);
|
|
21
|
+
hkdf.expand(domain, okm).unwrap();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub(crate) fn derive_encryption_key(key: &[u8], salt: &[u8], domain: &[u8]) -> EncryptionKey {
|
|
25
|
+
let hkdf = hkdf::SimpleHkdf::<Blake2b256>::new(Some(salt), key);
|
|
26
|
+
let mut okm = [0u8; 32];
|
|
27
|
+
hkdf.expand(domain, &mut okm).unwrap();
|
|
28
|
+
okm.into()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub(crate) fn seal_data_key(
|
|
32
|
+
app_key: &PrivateKey,
|
|
33
|
+
object_id: &Hash256,
|
|
34
|
+
encryption_key: &EncryptionKey,
|
|
35
|
+
) -> Vec<u8> {
|
|
36
|
+
let data_encryption_key =
|
|
37
|
+
derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"dataKey");
|
|
38
|
+
let encryption_key_cipher = XChaCha20Poly1305::new(data_encryption_key.as_ref().into());
|
|
39
|
+
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
|
|
40
|
+
let encrypted_data_key = encryption_key_cipher
|
|
41
|
+
.encrypt(&nonce, encryption_key.as_ref().as_ref())
|
|
42
|
+
.expect("encryption failed");
|
|
43
|
+
[nonce.to_vec(), encrypted_data_key].concat()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub(crate) fn seal_metadata_key(
|
|
47
|
+
app_key: &PrivateKey,
|
|
48
|
+
object_id: &Hash256,
|
|
49
|
+
encryption_key: &EncryptionKey,
|
|
50
|
+
) -> Vec<u8> {
|
|
51
|
+
let meta_encryption_key =
|
|
52
|
+
derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"metadataKey");
|
|
53
|
+
let encryption_key_cipher = XChaCha20Poly1305::new(meta_encryption_key.as_ref().into());
|
|
54
|
+
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
|
|
55
|
+
let encrypted_meta_key = encryption_key_cipher
|
|
56
|
+
.encrypt(&nonce, encryption_key.as_ref().as_ref())
|
|
57
|
+
.expect("encryption failed");
|
|
58
|
+
[nonce.to_vec(), encrypted_meta_key].concat()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub(crate) fn open_data_key(
|
|
62
|
+
app_key: &PrivateKey,
|
|
63
|
+
object_id: &Hash256,
|
|
64
|
+
encrypted_data_key: &[u8],
|
|
65
|
+
) -> Result<EncryptionKey, DecryptError> {
|
|
66
|
+
if encrypted_data_key.len() < NONCE_SIZE {
|
|
67
|
+
return Err(DecryptError::Decryption);
|
|
68
|
+
}
|
|
69
|
+
let data_encryption_key =
|
|
70
|
+
derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"dataKey");
|
|
71
|
+
let encryption_key_cipher = XChaCha20Poly1305::new(data_encryption_key.as_ref().into());
|
|
72
|
+
let (nonce_bytes, ciphertext) = encrypted_data_key.split_at(NONCE_SIZE);
|
|
73
|
+
let nonce_bytes: [u8; 24] = nonce_bytes.try_into().unwrap(); // safe due to length check above
|
|
74
|
+
let nonce = chacha20poly1305::XNonce::from(nonce_bytes);
|
|
75
|
+
let decrypted_data_key = encryption_key_cipher
|
|
76
|
+
.decrypt(&nonce, ciphertext)
|
|
77
|
+
.map_err(|_| DecryptError::Decryption)?;
|
|
78
|
+
EncryptionKey::try_from(decrypted_data_key.as_ref()).map_err(|_| DecryptError::KeyLength)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pub(crate) fn open_metadata_key(
|
|
82
|
+
app_key: &PrivateKey,
|
|
83
|
+
object_id: &Hash256,
|
|
84
|
+
encrypted_meta_key: &[u8],
|
|
85
|
+
) -> Result<EncryptionKey, DecryptError> {
|
|
86
|
+
if encrypted_meta_key.len() < NONCE_SIZE {
|
|
87
|
+
return Err(DecryptError::Decryption);
|
|
88
|
+
}
|
|
89
|
+
let meta_encryption_key =
|
|
90
|
+
derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"metadataKey");
|
|
91
|
+
let encryption_key_cipher = XChaCha20Poly1305::new(meta_encryption_key.as_ref().into());
|
|
92
|
+
let (nonce_bytes, ciphertext) = encrypted_meta_key.split_at(NONCE_SIZE);
|
|
93
|
+
let nonce_bytes: [u8; 24] = nonce_bytes.try_into().unwrap(); // safe due to length check above
|
|
94
|
+
let nonce = chacha20poly1305::XNonce::from(nonce_bytes);
|
|
95
|
+
let decrypted_meta_key = encryption_key_cipher
|
|
96
|
+
.decrypt(&nonce, ciphertext)
|
|
97
|
+
.map_err(|_| DecryptError::Decryption)?;
|
|
98
|
+
EncryptionKey::try_from(decrypted_meta_key.as_ref()).map_err(|_| DecryptError::KeyLength)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub(crate) fn seal_metadata(meta_key: &EncryptionKey, metadata: &[u8]) -> Vec<u8> {
|
|
102
|
+
let metadata_cipher = XChaCha20Poly1305::new(meta_key.as_ref().into());
|
|
103
|
+
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
|
|
104
|
+
let encrypted_metadata = metadata_cipher
|
|
105
|
+
.encrypt(&nonce, metadata)
|
|
106
|
+
.expect("encryption failed");
|
|
107
|
+
[nonce.to_vec(), encrypted_metadata].concat()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
pub(crate) fn open_metadata(
|
|
111
|
+
meta_key: &EncryptionKey,
|
|
112
|
+
encrypted_metadata: &[u8],
|
|
113
|
+
) -> Result<Vec<u8>, DecryptError> {
|
|
114
|
+
if encrypted_metadata.len() < NONCE_SIZE {
|
|
115
|
+
return Err(DecryptError::Decryption);
|
|
116
|
+
}
|
|
117
|
+
let metadata_cipher = XChaCha20Poly1305::new(meta_key.as_ref().into());
|
|
118
|
+
let (nonce_bytes, ciphertext) = encrypted_metadata.split_at(NONCE_SIZE);
|
|
119
|
+
let nonce_bytes: [u8; 24] = nonce_bytes.try_into().unwrap(); // safe due to length check above
|
|
120
|
+
let nonce = chacha20poly1305::XNonce::from(nonce_bytes);
|
|
121
|
+
let decrypted_metadata = metadata_cipher
|
|
122
|
+
.decrypt(&nonce, ciphertext)
|
|
123
|
+
.map_err(|_| DecryptError::Decryption)?;
|
|
124
|
+
Ok(decrypted_metadata)
|
|
125
|
+
}
|