diff --git a/Cargo.toml b/Cargo.toml index a84435b1..040e75fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,11 @@ categories = ["cryptography", "database"] keywords = ["hyperledger", "aries", "ssi", "verifiable", "credentials"] rust-version = "1.65" +[[bin]] +name = "uniffi-bindgen" +path = "uniffi/uniffi-bindgen.rs" +required-features = ["uffi"] + [lib] name = "aries_askar" path = "src/lib.rs" @@ -28,6 +33,7 @@ rustdoc-args = ["--cfg", "docsrs"] default = ["all_backends", "ffi", "logger", "migration"] all_backends = ["postgres", "sqlite"] ffi = ["ffi-support", "logger"] +uffi = ["uniffi", "all_backends", "logger", "tokio", "ffi"] jemalloc = ["jemallocator"] logger = ["env_logger", "log", "askar-storage/log"] postgres = ["askar-storage/postgres"] @@ -35,6 +41,9 @@ sqlite = ["askar-storage/sqlite"] pg_test = ["askar-storage/pg_test"] migration = ["askar-storage/migration"] +[build-dependencies] +uniffi = { version = "0.24.3", features = ["build", "cli", "tokio"] } + [dependencies] async-lock = "2.5" env_logger = { version = "0.9", optional = true } @@ -45,6 +54,8 @@ once_cell = "1.5" serde = { version = "1.0", features = ["derive"] } serde_cbor = "0.11" serde_json = "1.0" +tokio = { version = "1.5", optional = true } +uniffi = { version = "0.24.3", optional = true, features = ["cli", "tokio"] } zeroize = "1.5" [dependencies.askar-crypto] diff --git a/build-swift-framework.sh b/build-swift-framework.sh new file mode 100755 index 00000000..5b742148 --- /dev/null +++ b/build-swift-framework.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +set -eo pipefail + +NAME="aries_askar" +VERSION=$(cargo generate-lockfile && cargo pkgid | sed -e "s/^.*#//") +BUNDLE_IDENTIFIER="org.hyperledger.$NAME" +LIBRARY_NAME="lib$NAME.a" +FRAMEWORK_LIBRARY_NAME=${NAME}FFI +FRAMEWORK_NAME="$FRAMEWORK_LIBRARY_NAME.framework" +XC_FRAMEWORK_NAME="$FRAMEWORK_LIBRARY_NAME.xcframework" +HEADER_NAME="${NAME}FFI.h" +OUT_PATH="out" +MIN_IOS_VERSION="15.0" +WRAPPER_PATH="wrappers/swift/Askar/Sources/Askar" + +AARCH64_APPLE_IOS_PATH="./target/aarch64-apple-ios/release" +AARCH64_APPLE_IOS_SIM_PATH="./target/aarch64-apple-ios-sim/release" +X86_64_APPLE_IOS_PATH="./target/x86_64-apple-ios/release" +AARCH64_APPLE_DARWIN_PATH="./target/aarch64-apple-darwin/release" +X86_64_APPLE_DARWIN_PATH="./target/x86_64-apple-darwin/release" + +targets=("aarch64-apple-ios" "aarch64-apple-ios-sim" "x86_64-apple-ios" "aarch64-apple-darwin" "x86_64-apple-darwin") + +# Build for all targets +for target in "${targets[@]}"; do + echo "Building for $target..." + rustup target add $target + cargo build --release --no-default-features --features uffi --target $target +done + +# Generate swift wrapper +echo "Generating swift wrapper..." +mkdir -p $OUT_PATH +CURRENT_ARCH=$(rustc --version --verbose | grep host | cut -f2 -d' ') +cargo run --features uffi --bin uniffi-bindgen generate uniffi/askar.udl --language swift -o $OUT_PATH --lib-file ./target/$CURRENT_ARCH/release/$LIBRARY_NAME + +# Merge libraries with lipo +echo "Merging libraries with lipo..." +lipo -create $AARCH64_APPLE_IOS_SIM_PATH/$LIBRARY_NAME \ + $X86_64_APPLE_IOS_PATH/$LIBRARY_NAME \ + -output $OUT_PATH/sim-$LIBRARY_NAME +lipo -create $AARCH64_APPLE_DARWIN_PATH/$LIBRARY_NAME \ + $X86_64_APPLE_DARWIN_PATH/$LIBRARY_NAME \ + -output $OUT_PATH/macos-$LIBRARY_NAME + +# Create framework template +rm -rf $OUT_PATH/$FRAMEWORK_NAME +mkdir -p $OUT_PATH/$FRAMEWORK_NAME/Headers +mkdir -p $OUT_PATH/$FRAMEWORK_NAME/Modules +cp $OUT_PATH/$HEADER_NAME $OUT_PATH/$FRAMEWORK_NAME/Headers +cat < $OUT_PATH/$FRAMEWORK_NAME/Modules/module.modulemap +framework module $FRAMEWORK_LIBRARY_NAME { + umbrella header "$HEADER_NAME" + + export * + module * { export * } +} +EOT + +cat < $OUT_PATH/$FRAMEWORK_NAME/Info.plist + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $FRAMEWORK_LIBRARY_NAME + CFBundleIdentifier + $BUNDLE_IDENTIFIER + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $FRAMEWORK_LIBRARY_NAME + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $VERSION + NSPrincipalClass + + MinimumOSVersion + $MIN_IOS_VERSION + + +EOT + +# Prepare frameworks for each platform +rm -rf $OUT_PATH/frameworks +mkdir -p $OUT_PATH/frameworks/sim +mkdir -p $OUT_PATH/frameworks/ios +mkdir -p $OUT_PATH/frameworks/macos +cp -r $OUT_PATH/$FRAMEWORK_NAME $OUT_PATH/frameworks/sim/ +cp -r $OUT_PATH/$FRAMEWORK_NAME $OUT_PATH/frameworks/ios/ +cp -r $OUT_PATH/$FRAMEWORK_NAME $OUT_PATH/frameworks/macos/ +mv $OUT_PATH/sim-$LIBRARY_NAME $OUT_PATH/frameworks/sim/$FRAMEWORK_NAME/$FRAMEWORK_LIBRARY_NAME +mv $OUT_PATH/macos-$LIBRARY_NAME $OUT_PATH/frameworks/macos/$FRAMEWORK_NAME/$FRAMEWORK_LIBRARY_NAME +cp $AARCH64_APPLE_IOS_PATH/$LIBRARY_NAME $OUT_PATH/frameworks/ios/$FRAMEWORK_NAME/$FRAMEWORK_LIBRARY_NAME + +# Create xcframework +echo "Creating xcframework..." +rm -rf $OUT_PATH/$XC_FRAMEWORK_NAME +xcodebuild -create-xcframework \ + -framework $OUT_PATH/frameworks/sim/$FRAMEWORK_NAME \ + -framework $OUT_PATH/frameworks/ios/$FRAMEWORK_NAME \ + -framework $OUT_PATH/frameworks/macos/$FRAMEWORK_NAME \ + -output $OUT_PATH/$XC_FRAMEWORK_NAME + +# Copy swift wrapper +# Need some temporary workarounds to compile swift wrapper +# https://github.com/rust-lang/cargo/issues/11953 +cat < $OUT_PATH/import.txt +#if os(macOS) +import SystemConfiguration +#endif +EOT +cat $OUT_PATH/import.txt $OUT_PATH/$NAME.swift > $WRAPPER_PATH/$NAME.swift diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..bcab9a13 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::generate_scaffolding("./uniffi/askar.udl").unwrap(); +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index baa78d32..d52fc47c 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -23,7 +23,7 @@ mod log; mod result_list; mod secret; mod store; -mod tags; +pub(crate) mod tags; #[cfg(all(feature = "migration", feature = "sqlite"))] mod migration; diff --git a/src/lib.rs b/src/lib.rs index b15b6160..d7cb8fe6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ //! Secure storage designed for Hyperledger Aries agents #![cfg_attr(docsrs, feature(doc_cfg))] -#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] +#![deny(missing_docs, rust_2018_idioms)] #[macro_use] mod error; @@ -24,7 +24,27 @@ pub use askar_storage::future; #[cfg(feature = "ffi")] mod ffi; +#[cfg(feature = "uffi")] +mod uffi; + pub mod kms; mod store; pub use store::{entry, PassKey, Session, Store, StoreKeyMethod}; + +#[cfg(feature = "uffi")] +pub use storage::entry::{Entry, EntryOperation, EntryTag, Scan, TagFilter}; + +#[cfg(feature = "uffi")] +pub use uffi::{ + crypto::{AskarCrypto, AskarEcdhEs, AskarEcdh1PU}, + error::ErrorCode, + entry::{AskarEntry, AskarKeyEntry}, + key::{AskarLocalKey, AskarKeyAlg, SeedMethod, LocalKeyFactory, EncryptedBuffer}, + scan::AskarScan, + session::{AskarSession, AskarEntryOperation}, + store::{AskarStore, AskarStoreManager}, +}; + +#[cfg(feature = "uffi")] +uniffi::include_scaffolding!("askar"); diff --git a/src/uffi/crypto.rs b/src/uffi/crypto.rs new file mode 100644 index 00000000..821485a3 --- /dev/null +++ b/src/uffi/crypto.rs @@ -0,0 +1,340 @@ +use std::sync::Arc; +use crate::{ + kms::{ + crypto_box, crypto_box_open, crypto_box_random_nonce, crypto_box_seal, crypto_box_seal_open, + derive_key_ecdh_1pu, derive_key_ecdh_es, + }, + uffi::{ + error::ErrorCode, + key::{AskarLocalKey, AskarKeyAlg, EncryptedBuffer}, + }, +}; + +pub struct AskarCrypto {} + +impl AskarCrypto { + pub fn new() -> Self { + Self {} + } +} + +#[uniffi::export] +impl AskarCrypto { + pub fn random_nonce(&self) -> Result, ErrorCode> { + Ok(crypto_box_random_nonce()?.to_vec()) + } + + pub fn crypto_box( + &self, + receiver_key: Arc, + sender_key: Arc, + message: Vec, + nonce: Vec, + ) -> Result, ErrorCode> { + Ok(crypto_box(&receiver_key.key, &sender_key.key, &message, &nonce)?) + } + + pub fn box_open( + &self, + receiver_key: Arc, + sender_key: Arc, + message: Vec, + nonce: Vec, + ) -> Result, ErrorCode> { + Ok(crypto_box_open(&receiver_key.key, &sender_key.key, &message, &nonce)?.to_vec()) + } + + pub fn box_seal( + &self, + receiver_key: Arc, + message: Vec, + ) -> Result, ErrorCode> { + Ok(crypto_box_seal(&receiver_key.key, &message)?) + } + + pub fn box_seal_open( + &self, + receiver_key: Arc, + ciphertext: Vec, + ) -> Result, ErrorCode> { + Ok(crypto_box_seal_open(&receiver_key.key, &ciphertext)?.to_vec()) + } +} + +pub struct AskarEcdhEs { + alg_id: Vec, + apu: Vec, + apv: Vec, +} + +impl AskarEcdhEs { + pub fn new( + alg_id: String, + apu: String, + apv: String, + ) -> Self { + Self { + alg_id: alg_id.into_bytes(), + apu: apu.into_bytes(), + apv: apv.into_bytes(), + } + } +} + +#[uniffi::export] +impl AskarEcdhEs { + pub fn derive_key( + &self, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + receiver_key: Arc, + receive: bool, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_es( + enc_alg.into(), + &ephemeral_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + receive, + )?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn encrypt_direct( + &self, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + receiver_key: Arc, + message: Vec, + nonce: Option>, + aad: Option>, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_es( + enc_alg.into(), + &ephemeral_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + false, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.aead_encrypt(message, nonce, aad)?) + } + + pub fn decrypt_direct( + &self, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + receiver_key: Arc, + ciphertext: Vec, + tag: Option>, + nonce: Vec, + aad: Option>, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_es( + enc_alg.into(), + &ephemeral_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + true, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.aead_decrypt(ciphertext, tag, nonce, aad)?) + } + + pub fn sender_wrap_key( + &self, + wrap_alg: AskarKeyAlg, + ephemeral_key: Arc, + receiver_key: Arc, + cek: Arc, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_es( + wrap_alg.into(), + &ephemeral_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + false, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.wrap_key(cek, None)?) + } + + pub fn receiver_unwrap_key( + &self, + wrap_alg: AskarKeyAlg, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + receiver_key: Arc, + ciphertext: Vec, + nonce: Option>, + tag: Option>, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_es( + wrap_alg.into(), + &ephemeral_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + true, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.unwrap_key(enc_alg, ciphertext, tag, nonce)?) + } +} + +pub struct AskarEcdh1PU { + alg_id: Vec, + apu: Vec, + apv: Vec, +} + +impl AskarEcdh1PU { + pub fn new( + alg_id: String, + apu: String, + apv: String, + ) -> Self { + Self { + alg_id: alg_id.into_bytes(), + apu: apu.into_bytes(), + apv: apv.into_bytes(), + } + } +} + +#[uniffi::export] +impl AskarEcdh1PU { + pub fn derive_key( + &self, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + sender_key: Arc, + receiver_key: Arc, + cc_tag: Vec, + receive: bool, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_1pu( + enc_alg.into(), + &ephemeral_key.key, + &sender_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + &cc_tag, + receive, + )?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn encrypt_direct( + &self, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + sender_key: Arc, + receiver_key: Arc, + message: Vec, + nonce: Option>, + aad: Option>, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_1pu( + enc_alg.into(), + &ephemeral_key.key, + &sender_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + &[], + false, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.aead_encrypt(message, nonce, aad)?) + } + + pub fn decrypt_direct( + &self, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + sender_key: Arc, + receiver_key: Arc, + ciphertext: Vec, + tag: Option>, + nonce: Vec, + aad: Option>, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_1pu( + enc_alg.into(), + &ephemeral_key.key, + &sender_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + &[], + true, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.aead_decrypt(ciphertext, tag, nonce, aad)?) + } + + pub fn sender_wrap_key( + &self, + wrap_alg: AskarKeyAlg, + ephemeral_key: Arc, + sender_key: Arc, + receiver_key: Arc, + cek: Arc, + cc_tag: Vec, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_1pu( + wrap_alg.into(), + &ephemeral_key.key, + &sender_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + &cc_tag, + false, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.wrap_key(cek, None)?) + } + + pub fn receiver_unwrap_key( + &self, + wrap_alg: AskarKeyAlg, + enc_alg: AskarKeyAlg, + ephemeral_key: Arc, + sender_key: Arc, + receiver_key: Arc, + ciphertext: Vec, + cc_tag: Vec, + nonce: Option>, + tag: Option>, + ) -> Result, ErrorCode> { + let key = derive_key_ecdh_1pu( + enc_alg.into(), + &ephemeral_key.key, + &sender_key.key, + &receiver_key.key, + &self.alg_id, + &self.apu, + &self.apv, + &cc_tag, + true, + )?; + let derived = AskarLocalKey { key }; + Ok(derived.unwrap_key(wrap_alg, ciphertext, tag, nonce)?) + } +} diff --git a/src/uffi/entry.rs b/src/uffi/entry.rs new file mode 100644 index 00000000..abd70500 --- /dev/null +++ b/src/uffi/entry.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; +use std::sync::Arc; +use crate::{ + kms::KeyEntry, + storage::entry::Entry, + uffi::{error::ErrorCode, key::AskarLocalKey}, +}; + +pub struct AskarEntry { + entry: Entry, +} + +impl AskarEntry { + pub fn new(entry: Entry) -> Self { + Self { entry } + } +} + +#[uniffi::export] +impl AskarEntry { + pub fn category(&self) -> String { + self.entry.category.clone() + } + + pub fn name(&self) -> String { + self.entry.name.clone() + } + + pub fn tags(&self) -> HashMap { + let mut map = HashMap::new(); + for tag in &self.entry.tags { + map.insert(tag.name().to_string(), tag.value().to_string()); + } + map + } + + pub fn value(&self) -> Vec { + self.entry.value.to_vec() + } +} + +pub struct AskarKeyEntry { + entry: KeyEntry, +} + +impl AskarKeyEntry { + pub fn new(entry: KeyEntry) -> Self { + Self { entry } + } +} + +#[uniffi::export] +impl AskarKeyEntry { + pub fn algorithm(&self) -> Option { + self.entry.algorithm().map(String::from) + } + + pub fn metadata(&self) -> Option { + self.entry.metadata().map(String::from) + } + + pub fn name(&self) -> String { + self.entry.name().to_string() + } + + pub fn is_local(&self) -> bool { + self.entry.is_local() + } + + pub fn tags(&self) -> HashMap { + let mut map = HashMap::new(); + for tag in &self.entry.tags { + map.insert(tag.name().to_string(), tag.value().to_string()); + } + map + } + + pub fn load_local_key(&self) -> Result, ErrorCode> { + let key = self.entry.load_local_key()?; + Ok(Arc::new(AskarLocalKey { key })) + } +} diff --git a/src/uffi/error.rs b/src/uffi/error.rs new file mode 100644 index 00000000..75b5d8e4 --- /dev/null +++ b/src/uffi/error.rs @@ -0,0 +1,56 @@ +use std::fmt::{self, Display, Formatter}; + +use crate::error::{Error, ErrorKind}; +use crate::storage::{Error as StorageError, ErrorKind as StorageErrorKind}; + +#[derive(Debug, PartialEq, Clone, Serialize, uniffi::Error)] +pub enum ErrorCode { + Success { message: String }, + Backend { message: String }, + Busy { message: String }, + Duplicate { message: String }, + Encryption { message: String }, + Input { message: String }, + NotFound { message: String }, + Unexpected { message: String }, + Unsupported { message: String }, + Custom { message: String }, +} + +impl From for ErrorCode { + fn from(err: Error) -> ErrorCode { + match err.kind() { + ErrorKind::Backend => ErrorCode::Backend { message: err.to_string() }, + ErrorKind::Busy => ErrorCode::Busy { message: err.to_string() }, + ErrorKind::Duplicate => ErrorCode::Duplicate { message: err.to_string() }, + ErrorKind::Encryption => ErrorCode::Encryption { message: err.to_string() }, + ErrorKind::Input => ErrorCode::Input { message: err.to_string() }, + ErrorKind::NotFound => ErrorCode::NotFound { message: err.to_string() }, + ErrorKind::Unexpected => ErrorCode::Unexpected { message: err.to_string() }, + ErrorKind::Unsupported => ErrorCode::Unsupported { message: err.to_string() }, + ErrorKind::Custom => ErrorCode::Custom { message: err.to_string() }, + } + } +} + +impl From for ErrorCode { + fn from(err: StorageError) -> ErrorCode { + match err.kind() { + StorageErrorKind::Backend => ErrorCode::Backend { message: err.to_string() }, + StorageErrorKind::Busy => ErrorCode::Busy { message: err.to_string() }, + StorageErrorKind::Duplicate => ErrorCode::Duplicate { message: err.to_string() }, + StorageErrorKind::Encryption => ErrorCode::Encryption { message: err.to_string() }, + StorageErrorKind::Input => ErrorCode::Input { message: err.to_string() }, + StorageErrorKind::NotFound => ErrorCode::NotFound { message: err.to_string() }, + StorageErrorKind::Unexpected => ErrorCode::Unexpected { message: err.to_string() }, + StorageErrorKind::Unsupported => ErrorCode::Unsupported { message: err.to_string() }, + StorageErrorKind::Custom => ErrorCode::Custom { message: err.to_string() }, + } + } +} + +impl Display for ErrorCode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} diff --git a/src/uffi/key.rs b/src/uffi/key.rs new file mode 100644 index 00000000..14ce1444 --- /dev/null +++ b/src/uffi/key.rs @@ -0,0 +1,250 @@ +use std::sync::Arc; +use crate::{ + crypto::alg::{KeyAlg, AesTypes, BlsCurves, Chacha20Types, EcCurves}, + kms::{LocalKey, Encrypted}, + uffi::error::ErrorCode, +}; + +#[derive(uniffi::Enum)] +pub enum AskarKeyAlg { + A128Gcm, + A256Gcm, + A128CbcHs256, + A256CbcHs512, + A128Kw, + A256Kw, + Bls12_381G1, + Bls12_381G2, + Bls12_381G1g2, + C20P, + XC20P, + Ed25519, + X25519, + K256, + P256, + P384, +} + +impl Into for AskarKeyAlg { + fn into(self) -> KeyAlg { + match self { + AskarKeyAlg::A128Gcm => KeyAlg::Aes(AesTypes::A128Gcm), + AskarKeyAlg::A256Gcm => KeyAlg::Aes(AesTypes::A256Gcm), + AskarKeyAlg::A128CbcHs256 => KeyAlg::Aes(AesTypes::A128CbcHs256), + AskarKeyAlg::A256CbcHs512 => KeyAlg::Aes(AesTypes::A256CbcHs512), + AskarKeyAlg::A128Kw => KeyAlg::Aes(AesTypes::A128Kw), + AskarKeyAlg::A256Kw => KeyAlg::Aes(AesTypes::A256Kw), + AskarKeyAlg::Bls12_381G1 => KeyAlg::Bls12_381(BlsCurves::G1), + AskarKeyAlg::Bls12_381G2 => KeyAlg::Bls12_381(BlsCurves::G2), + AskarKeyAlg::Bls12_381G1g2 => KeyAlg::Bls12_381(BlsCurves::G1G2), + AskarKeyAlg::C20P => KeyAlg::Chacha20(Chacha20Types::C20P), + AskarKeyAlg::XC20P => KeyAlg::Chacha20(Chacha20Types::XC20P), + AskarKeyAlg::Ed25519 => KeyAlg::Ed25519, + AskarKeyAlg::X25519 => KeyAlg::X25519, + AskarKeyAlg::K256 => KeyAlg::EcCurve(EcCurves::Secp256k1), + AskarKeyAlg::P256 => KeyAlg::EcCurve(EcCurves::Secp256r1), + AskarKeyAlg::P384 => KeyAlg::EcCurve(EcCurves::Secp384r1), + } + } +} + +impl From for AskarKeyAlg { + fn from(key_alg: KeyAlg) -> Self { + match key_alg { + KeyAlg::Aes(AesTypes::A128Gcm) => AskarKeyAlg::A128Gcm, + KeyAlg::Aes(AesTypes::A256Gcm) => AskarKeyAlg::A256Gcm, + KeyAlg::Aes(AesTypes::A128CbcHs256) => AskarKeyAlg::A128CbcHs256, + KeyAlg::Aes(AesTypes::A256CbcHs512) => AskarKeyAlg::A256CbcHs512, + KeyAlg::Aes(AesTypes::A128Kw) => AskarKeyAlg::A128Kw, + KeyAlg::Aes(AesTypes::A256Kw) => AskarKeyAlg::A256Kw, + KeyAlg::Bls12_381(BlsCurves::G1) => AskarKeyAlg::Bls12_381G1, + KeyAlg::Bls12_381(BlsCurves::G2) => AskarKeyAlg::Bls12_381G2, + KeyAlg::Bls12_381(BlsCurves::G1G2) => AskarKeyAlg::Bls12_381G1g2, + KeyAlg::Chacha20(Chacha20Types::C20P) => AskarKeyAlg::C20P, + KeyAlg::Chacha20(Chacha20Types::XC20P) => AskarKeyAlg::XC20P, + KeyAlg::Ed25519 => AskarKeyAlg::Ed25519, + KeyAlg::X25519 => AskarKeyAlg::X25519, + KeyAlg::EcCurve(EcCurves::Secp256k1) => AskarKeyAlg::K256, + KeyAlg::EcCurve(EcCurves::Secp256r1) => AskarKeyAlg::P256, + KeyAlg::EcCurve(EcCurves::Secp384r1) => AskarKeyAlg::P384, + } + } +} + +#[derive(uniffi::Enum)] +pub enum SeedMethod { + BlsKeyGen, +} + +impl Into<&str> for SeedMethod { + fn into(self) -> &'static str { + match self { + SeedMethod::BlsKeyGen => "bls_keygen", + } + } +} + +#[derive(uniffi::Record)] +pub struct AeadParams { + nonce_length: i32, + tag_length: i32, +} + +pub struct EncryptedBuffer { + enc: Encrypted, +} + +#[uniffi::export] +impl EncryptedBuffer { + pub fn ciphertext(&self) -> Vec { + self.enc.ciphertext().to_vec() + } + + pub fn nonce(&self) -> Vec { + self.enc.nonce().to_vec() + } + + pub fn tag(&self) -> Vec { + self.enc.tag().to_vec() + } + + pub fn ciphertext_tag(&self) -> Vec { + self.enc.buffer[0..(self.enc.nonce_pos)].to_vec() + } +} + +pub struct AskarLocalKey { + pub key: LocalKey, +} + +pub struct LocalKeyFactory { +} + +impl LocalKeyFactory { + pub fn new() -> Self { + Self {} + } +} + +#[uniffi::export] +impl LocalKeyFactory { + pub fn generate(&self, alg: AskarKeyAlg, ephemeral: bool) -> Result, ErrorCode> { + let key = LocalKey::generate(alg.into(), ephemeral)?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn from_seed(&self, alg: AskarKeyAlg, seed: Vec, method: Option) -> Result, ErrorCode> { + let key = LocalKey::from_seed(alg.into(), &seed, method.map(|m| m.into()))?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn from_jwk_slice(&self, jwk: Vec) -> Result, ErrorCode> { + let key = LocalKey::from_jwk_slice(&jwk)?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn from_jwk(&self, jwk: String) -> Result, ErrorCode> { + let key = LocalKey::from_jwk(&jwk)?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn from_public_bytes(&self, alg: AskarKeyAlg, bytes: Vec) -> Result, ErrorCode> { + let key = LocalKey::from_public_bytes(alg.into(), &bytes)?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn from_secret_bytes(&self, alg: AskarKeyAlg, bytes: Vec) -> Result, ErrorCode> { + let key = LocalKey::from_secret_bytes(alg.into(), &bytes)?; + Ok(Arc::new(AskarLocalKey { key })) + } +} + +#[uniffi::export] +impl AskarLocalKey { + pub fn to_public_bytes(&self) -> Result, ErrorCode> { + Ok(self.key.to_public_bytes()?.into_vec()) + } + + pub fn to_secret_bytes(&self) -> Result, ErrorCode> { + Ok(self.key.to_secret_bytes()?.into_vec()) + } + + pub fn to_key_exchange(&self, alg: AskarKeyAlg, pk: Arc) -> Result, ErrorCode> { + let key = self.key.to_key_exchange(alg.into(), &pk.key)?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn algorithm(&self) -> AskarKeyAlg { + self.key.algorithm().into() + } + + pub fn to_jwk_public(&self, alg: Option) -> Result { + Ok(self.key.to_jwk_public(alg.map(|a| a.into()))?) + } + + pub fn to_jwk_secret(&self) -> Result, ErrorCode> { + Ok(self.key.to_jwk_secret()?.into_vec()) + } + + pub fn to_jwk_thumbprint(&self, alg: Option) -> Result { + Ok(self.key.to_jwk_thumbprint(alg.map(|a| a.into()))?) + } + + pub fn to_jwk_thumbprints(&self) -> Result, ErrorCode> { + Ok(self.key.to_jwk_thumbprints()?) + } + + pub fn convert_key(&self, alg: AskarKeyAlg) -> Result, ErrorCode> { + let key = self.key.convert_key(alg.into())?; + Ok(Arc::new(AskarLocalKey { key })) + } + + pub fn aead_params(&self) -> Result { + let params = self.key.aead_params()?; + Ok(AeadParams { + nonce_length: params.nonce_length as i32, + tag_length: params.tag_length as i32, + }) + } + + pub fn aead_padding(&self, msg_len: i32) -> i32 { + self.key.aead_padding(msg_len as usize) as i32 + } + + pub fn aead_random_nonce(&self) -> Result, ErrorCode> { + Ok(self.key.aead_random_nonce()?) + } + + pub fn aead_encrypt(&self, message: Vec, nonce: Option>, aad: Option>) -> Result, ErrorCode> { + Ok(Arc::new(EncryptedBuffer { + enc: self.key.aead_encrypt(&message, &nonce.unwrap_or_default(), &aad.unwrap_or_default())?, + })) + } + + pub fn aead_decrypt(&self, ciphertext: Vec, tag: Option>, nonce: Vec, aad: Option>) -> Result, ErrorCode> { + Ok(self.key.aead_decrypt((ciphertext.as_slice(), tag.unwrap_or_default().as_slice()), &nonce, &aad.unwrap_or_default())?.to_vec()) + } + + pub fn sign_message(&self, message: Vec, sig_type: Option) -> Result, ErrorCode> { + Ok(self.key.sign_message(&message, sig_type.as_deref())?) + } + + pub fn verify_signature(&self, message: Vec, signature: Vec, sig_type: Option) -> Result { + Ok(self.key.verify_signature(&message, &signature, sig_type.as_deref())?) + } + + pub fn wrap_key(&self, key: Arc, nonce: Option>) -> Result, ErrorCode> { + Ok(Arc::new(EncryptedBuffer { + enc: self.key.wrap_key(&key.key, &nonce.unwrap_or_default())?, + })) + } + + pub fn unwrap_key(&self, alg: AskarKeyAlg, ciphertext: Vec, tag: Option>, nonce: Option>) -> Result, ErrorCode> { + let key = self.key.unwrap_key( + alg.into(), + (ciphertext.as_slice(), tag.unwrap_or_default().as_slice()), + &nonce.unwrap_or_default() + )?; + Ok(Arc::new(AskarLocalKey { key })) + } +} diff --git a/src/uffi/mod.rs b/src/uffi/mod.rs new file mode 100644 index 00000000..6cc4d2ce --- /dev/null +++ b/src/uffi/mod.rs @@ -0,0 +1,8 @@ +#![allow(missing_docs)] +pub mod entry; +pub mod error; +pub mod key; +pub mod scan; +pub mod session; +pub mod store; +pub mod crypto; diff --git a/src/uffi/scan.rs b/src/uffi/scan.rs new file mode 100644 index 00000000..beaf3cc2 --- /dev/null +++ b/src/uffi/scan.rs @@ -0,0 +1,47 @@ +use std::sync::Arc; +use tokio::sync::Mutex; +use crate::{ + uffi::{error::ErrorCode, entry::AskarEntry}, + storage::entry::{Entry, Scan}, +}; + +pub struct AskarScan { + scan: Mutex>, +} + +impl AskarScan { + pub fn new(scan: Scan<'static, Entry>) -> Self { + Self { scan: Mutex::new(scan) } + } +} + +#[uniffi::export(async_runtime = "tokio")] +impl AskarScan { + pub async fn next(&self) -> Result>>, ErrorCode> { + let mut scan = self.scan.lock().await; + let entries = scan.fetch_next().await?; + let entries: Vec> = entries + .unwrap_or(vec![]) + .into_iter() + .map(|entry| Arc::new(AskarEntry::new(entry))) + .collect(); + if entries.is_empty() { + Ok(None) + } else { + Ok(Some(entries)) + } + } + + pub async fn fetch_all(&self) -> Result>, ErrorCode> { + let mut scan = self.scan.lock().await; + let mut entries = vec![]; + while let Some(mut batch) = scan.fetch_next().await? { + entries.append(&mut batch); + } + let entries = entries + .into_iter() + .map(|entry| Arc::new(AskarEntry::new(entry))) + .collect(); + Ok(entries) + } +} diff --git a/src/uffi/session.rs b/src/uffi/session.rs new file mode 100644 index 00000000..055c4acd --- /dev/null +++ b/src/uffi/session.rs @@ -0,0 +1,251 @@ +use std::{ + str::FromStr, + sync::Arc, +}; +use tokio::sync::Mutex; +use crate::{ + ffi::tags::EntryTagSet, + storage::entry::{EntryOperation, TagFilter}, + store::Session, + uffi::{error::ErrorCode, entry::AskarEntry, entry::AskarKeyEntry, key::AskarLocalKey}, +}; + +#[derive(uniffi::Enum)] +pub enum AskarEntryOperation { + Insert, + Replace, + Remove, +} + +impl Into for AskarEntryOperation { + fn into(self) -> EntryOperation { + match self { + AskarEntryOperation::Insert => EntryOperation::Insert, + AskarEntryOperation::Replace => EntryOperation::Replace, + AskarEntryOperation::Remove => EntryOperation::Remove, + } + } +} + +macro_rules! SESSION_CLOSED_ERROR { + () => { + ErrorCode::Unexpected { message: String::from("Session is already closed") } + }; +} + +pub struct AskarSession { + session: Mutex>, +} + +impl AskarSession { + pub fn new(session: Session) -> Self { + Self { session: Mutex::new(Some(session)) } + } +} + +#[uniffi::export(async_runtime = "tokio")] +impl AskarSession { + pub async fn close(&self) -> Result<(), ErrorCode> { + self.session.lock().await.take(); + Ok(()) + } + + pub async fn count( + &self, + category: String, + tag_filter: Option, + ) -> Result { + Ok(self. + session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .count(Some(&category), tag_filter.as_deref().map(TagFilter::from_str).transpose()?) + .await?) + } + + pub async fn fetch( + &self, + category: String, + name: String, + for_update: bool, + ) -> Result>, ErrorCode> { + let entry = self + .session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .fetch(&category, &name, for_update) + .await?; + Ok(entry.map(|entry| Arc::new(AskarEntry::new(entry)))) + } + + pub async fn fetch_all( + &self, + category: String, + tag_filter: Option, + limit: Option, + for_update: bool, + ) -> Result>, ErrorCode> { + let entries = self + .session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .fetch_all(Some(&category), tag_filter.as_deref().map(TagFilter::from_str).transpose()?, limit, for_update) + .await?; + Ok(entries + .into_iter() + .map(|entry| Arc::new(AskarEntry::new(entry))) + .collect()) + } + + pub async fn update( + &self, + operation: AskarEntryOperation, + category: String, + name: String, + value: Vec, + tags: Option, + expiry_ms: Option, + ) -> Result<(), ErrorCode> { + let tags = if let Some(tags) = tags { + Some( + serde_json::from_str::>(&tags) + .map_err(err_map!("Error decoding tags"))? + .into_vec(), + ) + } else { + None + }; + self.session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .update(operation.into(), &category, &name, Some(&value), tags.as_deref(), expiry_ms) + .await?; + Ok(()) + } + + pub async fn remove_all( + &self, + category: String, + tag_filter: Option, + ) -> Result { + Ok(self + .session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .remove_all(Some(&category), tag_filter.as_deref().map(TagFilter::from_str).transpose()?) + .await?) + } + + pub async fn insert_key( + &self, + name: String, + key: Arc, + metadata: Option, + tags: Option, + expiry_ms: Option, + ) -> Result<(), ErrorCode> { + let tags = if let Some(tags) = tags { + Some( + serde_json::from_str::>(&tags) + .map_err(err_map!("Error decoding tags"))? + .into_vec(), + ) + } else { + None + }; + self.session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .insert_key(&name, &key.key, metadata.as_deref(), tags.as_deref(), expiry_ms) + .await?; + Ok(()) + } + + pub async fn fetch_key( + &self, + name: String, + for_update: bool, + ) -> Result>, ErrorCode> { + let key = self + .session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .fetch_key(&name, for_update) + .await?; + Ok(key.map(|entry| Arc::new(AskarKeyEntry::new(entry)))) + } + + pub async fn fetch_all_keys( + &self, + algorithm: Option, + thumbprint: Option, + tag_filter: Option, + limit: Option, + for_update: bool, + ) -> Result>, ErrorCode> { + let tag_filter = tag_filter.as_deref().map(TagFilter::from_str).transpose()?; + let keys = self + .session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .fetch_all_keys(algorithm.as_deref(), thumbprint.as_deref(), tag_filter, limit, for_update) + .await?; + Ok(keys + .into_iter() + .map(|entry| Arc::new(AskarKeyEntry::new(entry))) + .collect()) + } + + pub async fn remove_key(&self, name: String) -> Result<(), ErrorCode> { + self + .session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .remove_key(&name).await?; + Ok(()) + } + + pub async fn update_key( + &self, + name: String, + metadata: Option, + tags: Option, + expiry_ms: Option, + ) -> Result<(), ErrorCode> { + let tags = if let Some(tags) = tags { + Some( + serde_json::from_str::>(&tags) + .map_err(err_map!("Error decoding tags"))? + .into_vec(), + ) + } else { + None + }; + self.session + .lock() + .await + .as_mut() + .ok_or(SESSION_CLOSED_ERROR!())? + .update_key(&name, metadata.as_deref(), tags.as_deref(), expiry_ms) + .await?; + Ok(()) + } +} diff --git a/src/uffi/store.rs b/src/uffi/store.rs new file mode 100644 index 00000000..01237889 --- /dev/null +++ b/src/uffi/store.rs @@ -0,0 +1,195 @@ +use std::{ + sync::Arc, + str::FromStr, +}; +use tokio::sync::RwLock; +use crate::{ + store::{PassKey, Store, StoreKeyMethod}, + uffi::{error::ErrorCode, scan::AskarScan, session::AskarSession}, + storage::{generate_raw_store_key, entry::TagFilter}, +}; + +macro_rules! STORE_CLOSED_ERROR { + () => { + ErrorCode::Unexpected { message: String::from("Store is already closed") } + }; +} + +pub struct AskarStoreManager {} + +impl AskarStoreManager { + pub fn new() -> Self { + Self {} + } +} + +#[uniffi::export] +impl AskarStoreManager { + pub fn generate_raw_store_key(&self, seed: Option) -> Result { + let key = generate_raw_store_key(seed.as_ref().map(|s| s.as_bytes()))?; + Ok(key.to_string()) + } + + pub fn set_default_logger(&self) -> Result<(), ErrorCode> { + env_logger::try_init().map_err( + |e| ErrorCode::Unexpected { message: format!("{}", e) })?; + Ok(()) + } +} + +#[uniffi::export(async_runtime = "tokio")] +impl AskarStoreManager { + pub async fn provision( + &self, + spec_uri: String, + key_method: Option, + pass_key: Option, + profile: Option, + recreate: bool, + ) -> Result, ErrorCode> { + let key_method = match key_method { + Some(method) => StoreKeyMethod::parse_uri(&method)?, + None => StoreKeyMethod::default() + }; + let pass_key = PassKey::from(pass_key.as_deref()).into_owned(); + let store = Store::provision( + spec_uri.as_str(), + key_method, + pass_key, + profile, + recreate, + ).await?; + Ok(Arc::new(AskarStore { store: RwLock::new(Some(store)) })) + } + + pub async fn open( + &self, + spec_uri: String, + key_method: Option, + pass_key: Option, + profile: Option, + ) -> Result, ErrorCode> { + let key_method = match key_method { + Some(method) => Some(StoreKeyMethod::parse_uri(&method)?), + None => None + }; + let pass_key = PassKey::from(pass_key.as_deref()).into_owned(); + let store = Store::open( + spec_uri.as_str(), + key_method, + pass_key, + profile, + ).await?; + Ok(Arc::new(AskarStore { store: RwLock::new(Some(store)) })) + } + + pub async fn remove(&self, spec_uri: String) -> Result { + let removed = Store::remove(spec_uri.as_str()).await?; + Ok(removed) + } +} + +pub struct AskarStore { + store: RwLock>, // Option is used to allow for the store to be closed +} + +#[uniffi::export(async_runtime = "tokio")] +impl AskarStore { + pub async fn get_profile_name(&self) -> Result { + let name = self + .store + .read() + .await + .as_ref() + .ok_or(STORE_CLOSED_ERROR!())? + .get_active_profile().to_string(); + Ok(name) + } + + pub async fn create_profile(&self, profile: Option) -> Result { + let name = self + .store + .read() + .await + .as_ref() + .ok_or(STORE_CLOSED_ERROR!())? + .create_profile(profile) + .await?; + Ok(name) + } + + pub async fn remove_profile(&self, profile: String) -> Result { + let removed = self + .store + .read() + .await + .as_ref() + .ok_or(STORE_CLOSED_ERROR!())? + .remove_profile(profile) + .await?; + Ok(removed) + } + + pub async fn rekey(&self, key_method: Option, pass_key: Option) -> Result<(), ErrorCode> { + let key_method = match key_method { + Some(method) => StoreKeyMethod::parse_uri(&method)?, + None => StoreKeyMethod::default() + }; + let pass_key = PassKey::from(pass_key.as_deref()).into_owned(); + self + .store + .write() + .await + .as_mut() + .ok_or(STORE_CLOSED_ERROR!())? + .rekey(key_method, pass_key) + .await?; + Ok(()) + } + + pub async fn close(&self) -> Result<(), ErrorCode> { + let store = self.store.write().await.take(); + store + .ok_or(STORE_CLOSED_ERROR!())? + .close().await?; + Ok(()) + } + + pub async fn scan( + &self, + profile: Option, + categogy: String, + tag_filter: Option, + offset: Option, + limit: Option, + ) -> Result, ErrorCode> { + let tag_filter = tag_filter.as_deref().map(TagFilter::from_str).transpose()?; + let scan = self + .store + .read() + .await + .as_ref() + .ok_or(STORE_CLOSED_ERROR!())? + .scan( + profile, + Some(categogy), + tag_filter, + offset, + limit, + ) + .await?; + Ok(Arc::new(AskarScan::new(scan))) + } + + pub async fn session(&self, profile: Option) -> Result, ErrorCode> { + let session = self + .store + .read() + .await + .as_ref() + .ok_or(STORE_CLOSED_ERROR!())? + .session(profile) + .await?; + Ok(Arc::new(AskarSession::new(session))) + } +} diff --git a/uniffi/askar.udl b/uniffi/askar.udl new file mode 100644 index 00000000..e2723534 --- /dev/null +++ b/uniffi/askar.udl @@ -0,0 +1,24 @@ +interface AskarEntry {}; +interface AskarKeyEntry {}; +interface AskarScan {}; +interface AskarSession {}; +interface AskarStore {}; +interface AskarLocalKey {}; +interface EncryptedBuffer {}; +interface LocalKeyFactory { + constructor(); +}; +interface AskarStoreManager { + constructor(); +}; +interface AskarCrypto { + constructor(); +}; +interface AskarEcdhEs { + constructor(string alg_id, string apu, string apv); +}; +interface AskarEcdh1PU { + constructor(string alg_id, string apu, string apv); +}; + +namespace aries_askar {}; diff --git a/uniffi/uniffi-bindgen.rs b/uniffi/uniffi-bindgen.rs new file mode 100644 index 00000000..f6cff6cf --- /dev/null +++ b/uniffi/uniffi-bindgen.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/wrappers/swift/Askar/.gitignore b/wrappers/swift/Askar/.gitignore new file mode 100644 index 00000000..62b7e8f0 --- /dev/null +++ b/wrappers/swift/Askar/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm +.netrc diff --git a/wrappers/swift/Askar/Package.swift b/wrappers/swift/Askar/Package.swift new file mode 100644 index 00000000..4bdf8e80 --- /dev/null +++ b/wrappers/swift/Askar/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.7 +import PackageDescription + +let package = Package( + name: "Askar", + platforms: [ + .macOS(.v10_15) + ], + products: [ + .library( + name: "Askar", + targets: ["Askar"]), + ], + dependencies: [ + ], + targets: [ + .target( + name: "Askar", + dependencies: ["aries_askarFFI"]), + .testTarget( + name: "AskarTests", + dependencies: ["Askar"]), + .binaryTarget( + name: "aries_askarFFI", + path: "../../../out/aries_askarFFI.xcframework"), + ] +) diff --git a/wrappers/swift/Askar/Sources/Askar/aries_askar.swift b/wrappers/swift/Askar/Sources/Askar/aries_askar.swift new file mode 100644 index 00000000..d493d952 --- /dev/null +++ b/wrappers/swift/Askar/Sources/Askar/aries_askar.swift @@ -0,0 +1,3819 @@ +#if os(macOS) +import SystemConfiguration +#endif +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(aries_askarFFI) + import aries_askarFFI +#endif + +private extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_aries_askar_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_aries_askar_rustbuffer_free(self, $0) } + } +} + +private extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +private extension Data { + init(rustBuffer: RustBuffer) { + // TODO: This copies the buffer. Can we read directly from a + // Rust buffer? + self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len)) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +private func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset ..< reader.offset + MemoryLayout.size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { + let range = reader.offset ..< (reader.offset + count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer { buffer in + reader.data.copyBytes(to: buffer, from: range) + } + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return try Float(bitPattern: readInt(&reader)) +} + +// Reads a float at the current offset. +private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return try Double(bitPattern: readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +private func createWriter() -> [UInt8] { + return [] +} + +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +private func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +private func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +private func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous go the Rust trait of the same name. +private protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} + +extension FfiConverterPrimitive { + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} + +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +private enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +private let CALL_SUCCESS: Int8 = 0 +private let CALL_ERROR: Int8 = 1 +private let CALL_PANIC: Int8 = 2 + +private extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + try makeRustCall(callback, errorHandler: nil) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> Error, + _ callback: (UnsafeMutablePointer) -> T +) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> Error)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_PANIC: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +// Public interface members begin here. + +private struct FfiConverterUInt8: FfiConverterPrimitive { + typealias FfiType = UInt8 + typealias SwiftType = UInt8 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt8 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: UInt8, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterInt32: FfiConverterPrimitive { + typealias FfiType = Int32 + typealias SwiftType = Int32 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Int32 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Int32, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterInt64: FfiConverterPrimitive { + typealias FfiType = Int64 + typealias SwiftType = Int64 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Int64 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Int64, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterBool: FfiConverter { + typealias FfiType = Int8 + typealias SwiftType = Bool + + public static func lift(_ value: Int8) throws -> Bool { + return value != 0 + } + + public static func lower(_ value: Bool) -> Int8 { + return value ? 1 : 0 + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool { + return try lift(readInt(&buf)) + } + + public static func write(_ value: Bool, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +private struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +public protocol AskarCryptoProtocol { + func boxOpen(receiverKey: AskarLocalKey, senderKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]) throws -> [UInt8] + func boxSeal(receiverKey: AskarLocalKey, message: [UInt8]) throws -> [UInt8] + func boxSealOpen(receiverKey: AskarLocalKey, ciphertext: [UInt8]) throws -> [UInt8] + func cryptoBox(receiverKey: AskarLocalKey, senderKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]) throws -> [UInt8] + func randomNonce() throws -> [UInt8] +} + +public class AskarCrypto: AskarCryptoProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + public convenience init() { + self.init(unsafeFromRawPointer: try! rustCall { + uniffi_aries_askar_fn_constructor_askarcrypto_new($0) + }) + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarcrypto(pointer, $0) } + } + + public func boxOpen(receiverKey: AskarLocalKey, senderKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarcrypto_box_open(self.pointer, + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterSequenceUInt8.lower(message), + FfiConverterSequenceUInt8.lower(nonce), $0) + } + ) + } + + public func boxSeal(receiverKey: AskarLocalKey, message: [UInt8]) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarcrypto_box_seal(self.pointer, + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(message), $0) + } + ) + } + + public func boxSealOpen(receiverKey: AskarLocalKey, ciphertext: [UInt8]) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarcrypto_box_seal_open(self.pointer, + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(ciphertext), $0) + } + ) + } + + public func cryptoBox(receiverKey: AskarLocalKey, senderKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarcrypto_crypto_box(self.pointer, + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterSequenceUInt8.lower(message), + FfiConverterSequenceUInt8.lower(nonce), $0) + } + ) + } + + public func randomNonce() throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarcrypto_random_nonce(self.pointer, $0) + } + ) + } +} + +public struct FfiConverterTypeAskarCrypto: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarCrypto + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarCrypto { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarCrypto, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarCrypto { + return AskarCrypto(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarCrypto) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarCrypto_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarCrypto { + return try FfiConverterTypeAskarCrypto.lift(pointer) +} + +public func FfiConverterTypeAskarCrypto_lower(_ value: AskarCrypto) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarCrypto.lower(value) +} + +public protocol AskarEcdh1PUProtocol { + func decryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8], aad: [UInt8]?) throws -> [UInt8] + func deriveKey(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, ccTag: [UInt8], receive: Bool) throws -> AskarLocalKey + func encryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]?, aad: [UInt8]?) throws -> EncryptedBuffer + func receiverUnwrapKey(wrapAlg: AskarKeyAlg, encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], ccTag: [UInt8], nonce: [UInt8]?, tag: [UInt8]?) throws -> AskarLocalKey + func senderWrapKey(wrapAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, cek: AskarLocalKey, ccTag: [UInt8]) throws -> EncryptedBuffer +} + +public class AskarEcdh1Pu: AskarEcdh1PUProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + public convenience init(algId: String, apu: String, apv: String) { + self.init(unsafeFromRawPointer: try! rustCall { + uniffi_aries_askar_fn_constructor_askarecdh1pu_new( + FfiConverterString.lower(algId), + FfiConverterString.lower(apu), + FfiConverterString.lower(apv), $0 + ) + }) + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarecdh1pu(pointer, $0) } + } + + public func decryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8], aad: [UInt8]?) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdh1pu_decrypt_direct(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(ciphertext), + FfiConverterOptionSequenceUInt8.lower(tag), + FfiConverterSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(aad), $0) + } + ) + } + + public func deriveKey(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, ccTag: [UInt8], receive: Bool) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdh1pu_derive_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(ccTag), + FfiConverterBool.lower(receive), $0) + } + ) + } + + public func encryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]?, aad: [UInt8]?) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdh1pu_encrypt_direct(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(message), + FfiConverterOptionSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(aad), $0) + } + ) + } + + public func receiverUnwrapKey(wrapAlg: AskarKeyAlg, encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], ccTag: [UInt8], nonce: [UInt8]?, tag: [UInt8]?) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdh1pu_receiver_unwrap_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(wrapAlg), + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(ciphertext), + FfiConverterSequenceUInt8.lower(ccTag), + FfiConverterOptionSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(tag), $0) + } + ) + } + + public func senderWrapKey(wrapAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, senderKey: AskarLocalKey, receiverKey: AskarLocalKey, cek: AskarLocalKey, ccTag: [UInt8]) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdh1pu_sender_wrap_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(wrapAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(senderKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterTypeAskarLocalKey.lower(cek), + FfiConverterSequenceUInt8.lower(ccTag), $0) + } + ) + } +} + +public struct FfiConverterTypeAskarEcdh1PU: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarEcdh1Pu + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarEcdh1Pu { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarEcdh1Pu, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarEcdh1Pu { + return AskarEcdh1Pu(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarEcdh1Pu) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarEcdh1PU_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarEcdh1Pu { + return try FfiConverterTypeAskarEcdh1PU.lift(pointer) +} + +public func FfiConverterTypeAskarEcdh1PU_lower(_ value: AskarEcdh1Pu) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarEcdh1PU.lower(value) +} + +public protocol AskarEcdhEsProtocol { + func decryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8], aad: [UInt8]?) throws -> [UInt8] + func deriveKey(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, receive: Bool) throws -> AskarLocalKey + func encryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]?, aad: [UInt8]?) throws -> EncryptedBuffer + func receiverUnwrapKey(wrapAlg: AskarKeyAlg, encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], nonce: [UInt8]?, tag: [UInt8]?) throws -> AskarLocalKey + func senderWrapKey(wrapAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, cek: AskarLocalKey) throws -> EncryptedBuffer +} + +public class AskarEcdhEs: AskarEcdhEsProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + public convenience init(algId: String, apu: String, apv: String) { + self.init(unsafeFromRawPointer: try! rustCall { + uniffi_aries_askar_fn_constructor_askarecdhes_new( + FfiConverterString.lower(algId), + FfiConverterString.lower(apu), + FfiConverterString.lower(apv), $0 + ) + }) + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarecdhes(pointer, $0) } + } + + public func decryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8], aad: [UInt8]?) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdhes_decrypt_direct(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(ciphertext), + FfiConverterOptionSequenceUInt8.lower(tag), + FfiConverterSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(aad), $0) + } + ) + } + + public func deriveKey(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, receive: Bool) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdhes_derive_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterBool.lower(receive), $0) + } + ) + } + + public func encryptDirect(encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, message: [UInt8], nonce: [UInt8]?, aad: [UInt8]?) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdhes_encrypt_direct(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(message), + FfiConverterOptionSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(aad), $0) + } + ) + } + + public func receiverUnwrapKey(wrapAlg: AskarKeyAlg, encAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, ciphertext: [UInt8], nonce: [UInt8]?, tag: [UInt8]?) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdhes_receiver_unwrap_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(wrapAlg), + FfiConverterTypeAskarKeyAlg.lower(encAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterSequenceUInt8.lower(ciphertext), + FfiConverterOptionSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(tag), $0) + } + ) + } + + public func senderWrapKey(wrapAlg: AskarKeyAlg, ephemeralKey: AskarLocalKey, receiverKey: AskarLocalKey, cek: AskarLocalKey) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarecdhes_sender_wrap_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(wrapAlg), + FfiConverterTypeAskarLocalKey.lower(ephemeralKey), + FfiConverterTypeAskarLocalKey.lower(receiverKey), + FfiConverterTypeAskarLocalKey.lower(cek), $0) + } + ) + } +} + +public struct FfiConverterTypeAskarEcdhEs: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarEcdhEs + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarEcdhEs { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarEcdhEs, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarEcdhEs { + return AskarEcdhEs(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarEcdhEs) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarEcdhEs_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarEcdhEs { + return try FfiConverterTypeAskarEcdhEs.lift(pointer) +} + +public func FfiConverterTypeAskarEcdhEs_lower(_ value: AskarEcdhEs) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarEcdhEs.lower(value) +} + +public protocol AskarEntryProtocol { + func category() -> String + func name() -> String + func tags() -> [String: String] + func value() -> [UInt8] +} + +public class AskarEntry: AskarEntryProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarentry(pointer, $0) } + } + + public func category() -> String { + return try! FfiConverterString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarentry_category(self.pointer, $0) + } + ) + } + + public func name() -> String { + return try! FfiConverterString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarentry_name(self.pointer, $0) + } + ) + } + + public func tags() -> [String: String] { + return try! FfiConverterDictionaryStringString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarentry_tags(self.pointer, $0) + } + ) + } + + public func value() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarentry_value(self.pointer, $0) + } + ) + } +} + +public struct FfiConverterTypeAskarEntry: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarEntry + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarEntry { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarEntry, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarEntry { + return AskarEntry(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarEntry) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarEntry_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarEntry { + return try FfiConverterTypeAskarEntry.lift(pointer) +} + +public func FfiConverterTypeAskarEntry_lower(_ value: AskarEntry) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarEntry.lower(value) +} + +public protocol AskarKeyEntryProtocol { + func algorithm() -> String? + func isLocal() -> Bool + func loadLocalKey() throws -> AskarLocalKey + func metadata() -> String? + func name() -> String + func tags() -> [String: String] +} + +public class AskarKeyEntry: AskarKeyEntryProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarkeyentry(pointer, $0) } + } + + public func algorithm() -> String? { + return try! FfiConverterOptionString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarkeyentry_algorithm(self.pointer, $0) + } + ) + } + + public func isLocal() -> Bool { + return try! FfiConverterBool.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarkeyentry_is_local(self.pointer, $0) + } + ) + } + + public func loadLocalKey() throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarkeyentry_load_local_key(self.pointer, $0) + } + ) + } + + public func metadata() -> String? { + return try! FfiConverterOptionString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarkeyentry_metadata(self.pointer, $0) + } + ) + } + + public func name() -> String { + return try! FfiConverterString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarkeyentry_name(self.pointer, $0) + } + ) + } + + public func tags() -> [String: String] { + return try! FfiConverterDictionaryStringString.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarkeyentry_tags(self.pointer, $0) + } + ) + } +} + +public struct FfiConverterTypeAskarKeyEntry: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarKeyEntry + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarKeyEntry { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarKeyEntry, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarKeyEntry { + return AskarKeyEntry(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarKeyEntry) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarKeyEntry_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarKeyEntry { + return try FfiConverterTypeAskarKeyEntry.lift(pointer) +} + +public func FfiConverterTypeAskarKeyEntry_lower(_ value: AskarKeyEntry) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarKeyEntry.lower(value) +} + +public protocol AskarLocalKeyProtocol { + func aeadDecrypt(ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8], aad: [UInt8]?) throws -> [UInt8] + func aeadEncrypt(message: [UInt8], nonce: [UInt8]?, aad: [UInt8]?) throws -> EncryptedBuffer + func aeadPadding(msgLen: Int32) -> Int32 + func aeadParams() throws -> AeadParams + func aeadRandomNonce() throws -> [UInt8] + func algorithm() -> AskarKeyAlg + func convertKey(alg: AskarKeyAlg) throws -> AskarLocalKey + func signMessage(message: [UInt8], sigType: String?) throws -> [UInt8] + func toJwkPublic(alg: AskarKeyAlg?) throws -> String + func toJwkSecret() throws -> [UInt8] + func toJwkThumbprint(alg: AskarKeyAlg?) throws -> String + func toJwkThumbprints() throws -> [String] + func toKeyExchange(alg: AskarKeyAlg, pk: AskarLocalKey) throws -> AskarLocalKey + func toPublicBytes() throws -> [UInt8] + func toSecretBytes() throws -> [UInt8] + func unwrapKey(alg: AskarKeyAlg, ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8]?) throws -> AskarLocalKey + func verifySignature(message: [UInt8], signature: [UInt8], sigType: String?) throws -> Bool + func wrapKey(key: AskarLocalKey, nonce: [UInt8]?) throws -> EncryptedBuffer +} + +public class AskarLocalKey: AskarLocalKeyProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarlocalkey(pointer, $0) } + } + + public func aeadDecrypt(ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8], aad: [UInt8]?) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_aead_decrypt(self.pointer, + FfiConverterSequenceUInt8.lower(ciphertext), + FfiConverterOptionSequenceUInt8.lower(tag), + FfiConverterSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(aad), $0) + } + ) + } + + public func aeadEncrypt(message: [UInt8], nonce: [UInt8]?, aad: [UInt8]?) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_aead_encrypt(self.pointer, + FfiConverterSequenceUInt8.lower(message), + FfiConverterOptionSequenceUInt8.lower(nonce), + FfiConverterOptionSequenceUInt8.lower(aad), $0) + } + ) + } + + public func aeadPadding(msgLen: Int32) -> Int32 { + return try! FfiConverterInt32.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarlocalkey_aead_padding(self.pointer, + FfiConverterInt32.lower(msgLen), $0) + } + ) + } + + public func aeadParams() throws -> AeadParams { + return try FfiConverterTypeAeadParams.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_aead_params(self.pointer, $0) + } + ) + } + + public func aeadRandomNonce() throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_aead_random_nonce(self.pointer, $0) + } + ) + } + + public func algorithm() -> AskarKeyAlg { + return try! FfiConverterTypeAskarKeyAlg.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_askarlocalkey_algorithm(self.pointer, $0) + } + ) + } + + public func convertKey(alg: AskarKeyAlg) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_convert_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), $0) + } + ) + } + + public func signMessage(message: [UInt8], sigType: String?) throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_sign_message(self.pointer, + FfiConverterSequenceUInt8.lower(message), + FfiConverterOptionString.lower(sigType), $0) + } + ) + } + + public func toJwkPublic(alg: AskarKeyAlg?) throws -> String { + return try FfiConverterString.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_jwk_public(self.pointer, + FfiConverterOptionTypeAskarKeyAlg.lower(alg), $0) + } + ) + } + + public func toJwkSecret() throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_jwk_secret(self.pointer, $0) + } + ) + } + + public func toJwkThumbprint(alg: AskarKeyAlg?) throws -> String { + return try FfiConverterString.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_jwk_thumbprint(self.pointer, + FfiConverterOptionTypeAskarKeyAlg.lower(alg), $0) + } + ) + } + + public func toJwkThumbprints() throws -> [String] { + return try FfiConverterSequenceString.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_jwk_thumbprints(self.pointer, $0) + } + ) + } + + public func toKeyExchange(alg: AskarKeyAlg, pk: AskarLocalKey) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_key_exchange(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), + FfiConverterTypeAskarLocalKey.lower(pk), $0) + } + ) + } + + public func toPublicBytes() throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_public_bytes(self.pointer, $0) + } + ) + } + + public func toSecretBytes() throws -> [UInt8] { + return try FfiConverterSequenceUInt8.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_to_secret_bytes(self.pointer, $0) + } + ) + } + + public func unwrapKey(alg: AskarKeyAlg, ciphertext: [UInt8], tag: [UInt8]?, nonce: [UInt8]?) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_unwrap_key(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), + FfiConverterSequenceUInt8.lower(ciphertext), + FfiConverterOptionSequenceUInt8.lower(tag), + FfiConverterOptionSequenceUInt8.lower(nonce), $0) + } + ) + } + + public func verifySignature(message: [UInt8], signature: [UInt8], sigType: String?) throws -> Bool { + return try FfiConverterBool.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_verify_signature(self.pointer, + FfiConverterSequenceUInt8.lower(message), + FfiConverterSequenceUInt8.lower(signature), + FfiConverterOptionString.lower(sigType), $0) + } + ) + } + + public func wrapKey(key: AskarLocalKey, nonce: [UInt8]?) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarlocalkey_wrap_key(self.pointer, + FfiConverterTypeAskarLocalKey.lower(key), + FfiConverterOptionSequenceUInt8.lower(nonce), $0) + } + ) + } +} + +public struct FfiConverterTypeAskarLocalKey: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarLocalKey + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarLocalKey { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarLocalKey, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarLocalKey { + return AskarLocalKey(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarLocalKey) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarLocalKey_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift(pointer) +} + +public func FfiConverterTypeAskarLocalKey_lower(_ value: AskarLocalKey) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarLocalKey.lower(value) +} + +public protocol AskarScanProtocol { + func fetchAll() async throws -> [AskarEntry] + func next() async throws -> [AskarEntry]? +} + +public class AskarScan: AskarScanProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarscan(pointer, $0) } + } + + public func fetchAll() async throws -> [AskarEntry] { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation<[AskarEntry], Error>? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarscan_fetch_all( + self.pointer, + + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerSequenceTypeAskarEntryTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func next() async throws -> [AskarEntry]? { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation<[AskarEntry]?, Error>? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarscan_next( + self.pointer, + + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerOptionSequenceTypeAskarEntryTypeErrorCode, + &continuation, + $0 + ) + } + } + } +} + +public struct FfiConverterTypeAskarScan: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarScan + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarScan { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarScan, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarScan { + return AskarScan(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarScan) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarScan_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarScan { + return try FfiConverterTypeAskarScan.lift(pointer) +} + +public func FfiConverterTypeAskarScan_lower(_ value: AskarScan) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarScan.lower(value) +} + +public protocol AskarSessionProtocol { + func close() async throws + func count(category: String, tagFilter: String?) async throws -> Int64 + func fetch(category: String, name: String, forUpdate: Bool) async throws -> AskarEntry? + func fetchAll(category: String, tagFilter: String?, limit: Int64?, forUpdate: Bool) async throws -> [AskarEntry] + func fetchAllKeys(algorithm: String?, thumbprint: String?, tagFilter: String?, limit: Int64?, forUpdate: Bool) async throws -> [AskarKeyEntry] + func fetchKey(name: String, forUpdate: Bool) async throws -> AskarKeyEntry? + func insertKey(name: String, key: AskarLocalKey, metadata: String?, tags: String?, expiryMs: Int64?) async throws + func removeAll(category: String, tagFilter: String?) async throws -> Int64 + func removeKey(name: String) async throws + func update(operation: AskarEntryOperation, category: String, name: String, value: [UInt8], tags: String?, expiryMs: Int64?) async throws + func updateKey(name: String, metadata: String?, tags: String?, expiryMs: Int64?) async throws +} + +public class AskarSession: AskarSessionProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarsession(pointer, $0) } + } + + public func close() async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_close( + self.pointer, + + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func count(category: String, tagFilter: String?) async throws -> Int64 { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_count( + self.pointer, + + FfiConverterString.lower(category), + FfiConverterOptionString.lower(tagFilter), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerInt64TypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func fetch(category: String, name: String, forUpdate: Bool) async throws -> AskarEntry? { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_fetch( + self.pointer, + + FfiConverterString.lower(category), + FfiConverterString.lower(name), + FfiConverterBool.lower(forUpdate), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerOptionTypeAskarEntryTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func fetchAll(category: String, tagFilter: String?, limit: Int64?, forUpdate: Bool) async throws -> [AskarEntry] { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation<[AskarEntry], Error>? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_fetch_all( + self.pointer, + + FfiConverterString.lower(category), + FfiConverterOptionString.lower(tagFilter), + FfiConverterOptionInt64.lower(limit), + FfiConverterBool.lower(forUpdate), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerSequenceTypeAskarEntryTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func fetchAllKeys(algorithm: String?, thumbprint: String?, tagFilter: String?, limit: Int64?, forUpdate: Bool) async throws -> [AskarKeyEntry] { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation<[AskarKeyEntry], Error>? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_fetch_all_keys( + self.pointer, + + FfiConverterOptionString.lower(algorithm), + FfiConverterOptionString.lower(thumbprint), + FfiConverterOptionString.lower(tagFilter), + FfiConverterOptionInt64.lower(limit), + FfiConverterBool.lower(forUpdate), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerSequenceTypeAskarKeyEntryTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func fetchKey(name: String, forUpdate: Bool) async throws -> AskarKeyEntry? { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_fetch_key( + self.pointer, + + FfiConverterString.lower(name), + FfiConverterBool.lower(forUpdate), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerOptionTypeAskarKeyEntryTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func insertKey(name: String, key: AskarLocalKey, metadata: String?, tags: String?, expiryMs: Int64?) async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_insert_key( + self.pointer, + + FfiConverterString.lower(name), + FfiConverterTypeAskarLocalKey.lower(key), + FfiConverterOptionString.lower(metadata), + FfiConverterOptionString.lower(tags), + FfiConverterOptionInt64.lower(expiryMs), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func removeAll(category: String, tagFilter: String?) async throws -> Int64 { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_remove_all( + self.pointer, + + FfiConverterString.lower(category), + FfiConverterOptionString.lower(tagFilter), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerInt64TypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func removeKey(name: String) async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_remove_key( + self.pointer, + + FfiConverterString.lower(name), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func update(operation: AskarEntryOperation, category: String, name: String, value: [UInt8], tags: String?, expiryMs: Int64?) async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_update( + self.pointer, + + FfiConverterTypeAskarEntryOperation.lower(operation), + FfiConverterString.lower(category), + FfiConverterString.lower(name), + FfiConverterSequenceUInt8.lower(value), + FfiConverterOptionString.lower(tags), + FfiConverterOptionInt64.lower(expiryMs), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func updateKey(name: String, metadata: String?, tags: String?, expiryMs: Int64?) async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarsession_update_key( + self.pointer, + + FfiConverterString.lower(name), + FfiConverterOptionString.lower(metadata), + FfiConverterOptionString.lower(tags), + FfiConverterOptionInt64.lower(expiryMs), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } +} + +public struct FfiConverterTypeAskarSession: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarSession + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarSession { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarSession, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarSession { + return AskarSession(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarSession) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarSession_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarSession { + return try FfiConverterTypeAskarSession.lift(pointer) +} + +public func FfiConverterTypeAskarSession_lower(_ value: AskarSession) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarSession.lower(value) +} + +public protocol AskarStoreProtocol { + func close() async throws + func createProfile(profile: String?) async throws -> String + func getProfileName() async throws -> String + func rekey(keyMethod: String?, passKey: String?) async throws + func removeProfile(profile: String) async throws -> Bool + func scan(profile: String?, categogy: String, tagFilter: String?, offset: Int64?, limit: Int64?) async throws -> AskarScan + func session(profile: String?) async throws -> AskarSession +} + +public class AskarStore: AskarStoreProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarstore(pointer, $0) } + } + + public func close() async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_close( + self.pointer, + + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func createProfile(profile: String?) async throws -> String { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_create_profile( + self.pointer, + + FfiConverterOptionString.lower(profile), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerStringTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func getProfileName() async throws -> String { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_get_profile_name( + self.pointer, + + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerStringTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func rekey(keyMethod: String?, passKey: String?) async throws { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_rekey( + self.pointer, + + FfiConverterOptionString.lower(keyMethod), + FfiConverterOptionString.lower(passKey), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerVoidTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func removeProfile(profile: String) async throws -> Bool { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_remove_profile( + self.pointer, + + FfiConverterString.lower(profile), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerBoolTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func scan(profile: String?, categogy: String, tagFilter: String?, offset: Int64?, limit: Int64?) async throws -> AskarScan { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_scan( + self.pointer, + + FfiConverterOptionString.lower(profile), + FfiConverterString.lower(categogy), + FfiConverterOptionString.lower(tagFilter), + FfiConverterOptionInt64.lower(offset), + FfiConverterOptionInt64.lower(limit), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerTypeAskarScanTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func session(profile: String?) async throws -> AskarSession { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstore_session( + self.pointer, + + FfiConverterOptionString.lower(profile), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerTypeAskarSessionTypeErrorCode, + &continuation, + $0 + ) + } + } + } +} + +public struct FfiConverterTypeAskarStore: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarStore + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarStore { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarStore, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarStore { + return AskarStore(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarStore) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarStore_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarStore { + return try FfiConverterTypeAskarStore.lift(pointer) +} + +public func FfiConverterTypeAskarStore_lower(_ value: AskarStore) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarStore.lower(value) +} + +public protocol AskarStoreManagerProtocol { + func generateRawStoreKey(seed: String?) throws -> String + func open(specUri: String, keyMethod: String?, passKey: String?, profile: String?) async throws -> AskarStore + func provision(specUri: String, keyMethod: String?, passKey: String?, profile: String?, recreate: Bool) async throws -> AskarStore + func remove(specUri: String) async throws -> Bool + func setDefaultLogger() throws +} + +public class AskarStoreManager: AskarStoreManagerProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + public convenience init() { + self.init(unsafeFromRawPointer: try! rustCall { + uniffi_aries_askar_fn_constructor_askarstoremanager_new($0) + }) + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_askarstoremanager(pointer, $0) } + } + + public func generateRawStoreKey(seed: String?) throws -> String { + return try FfiConverterString.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarstoremanager_generate_raw_store_key(self.pointer, + FfiConverterOptionString.lower(seed), $0) + } + ) + } + + public func open(specUri: String, keyMethod: String?, passKey: String?, profile: String?) async throws -> AskarStore { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstoremanager_open( + self.pointer, + + FfiConverterString.lower(specUri), + FfiConverterOptionString.lower(keyMethod), + FfiConverterOptionString.lower(passKey), + FfiConverterOptionString.lower(profile), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerTypeAskarStoreTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func provision(specUri: String, keyMethod: String?, passKey: String?, profile: String?, recreate: Bool) async throws -> AskarStore { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstoremanager_provision( + self.pointer, + + FfiConverterString.lower(specUri), + FfiConverterOptionString.lower(keyMethod), + FfiConverterOptionString.lower(passKey), + FfiConverterOptionString.lower(profile), + FfiConverterBool.lower(recreate), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerTypeAskarStoreTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func remove(specUri: String) async throws -> Bool { + // Suspend the function and call the scaffolding function, passing it a callback handler from + // `AsyncTypes.swift` + // + // Make sure to hold on to a reference to the continuation in the top-level scope so that + // it's not freed before the callback is invoked. + var continuation: CheckedContinuation? = nil + return try await withCheckedThrowingContinuation { + continuation = $0 + try! rustCall { + uniffi_aries_askar_fn_method_askarstoremanager_remove( + self.pointer, + + FfiConverterString.lower(specUri), + FfiConverterForeignExecutor.lower(UniFfiForeignExecutor()), + uniffiFutureCallbackHandlerBoolTypeErrorCode, + &continuation, + $0 + ) + } + } + } + + public func setDefaultLogger() throws { + try + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_askarstoremanager_set_default_logger(self.pointer, $0) + } + } +} + +public struct FfiConverterTypeAskarStoreManager: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = AskarStoreManager + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarStoreManager { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: AskarStoreManager, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarStoreManager { + return AskarStoreManager(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: AskarStoreManager) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeAskarStoreManager_lift(_ pointer: UnsafeMutableRawPointer) throws -> AskarStoreManager { + return try FfiConverterTypeAskarStoreManager.lift(pointer) +} + +public func FfiConverterTypeAskarStoreManager_lower(_ value: AskarStoreManager) -> UnsafeMutableRawPointer { + return FfiConverterTypeAskarStoreManager.lower(value) +} + +public protocol EncryptedBufferProtocol { + func ciphertext() -> [UInt8] + func ciphertextTag() -> [UInt8] + func nonce() -> [UInt8] + func tag() -> [UInt8] +} + +public class EncryptedBuffer: EncryptedBufferProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_encryptedbuffer(pointer, $0) } + } + + public func ciphertext() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_encryptedbuffer_ciphertext(self.pointer, $0) + } + ) + } + + public func ciphertextTag() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_encryptedbuffer_ciphertext_tag(self.pointer, $0) + } + ) + } + + public func nonce() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_encryptedbuffer_nonce(self.pointer, $0) + } + ) + } + + public func tag() -> [UInt8] { + return try! FfiConverterSequenceUInt8.lift( + try! + rustCall { + uniffi_aries_askar_fn_method_encryptedbuffer_tag(self.pointer, $0) + } + ) + } +} + +public struct FfiConverterTypeEncryptedBuffer: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = EncryptedBuffer + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> EncryptedBuffer { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: EncryptedBuffer, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> EncryptedBuffer { + return EncryptedBuffer(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: EncryptedBuffer) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeEncryptedBuffer_lift(_ pointer: UnsafeMutableRawPointer) throws -> EncryptedBuffer { + return try FfiConverterTypeEncryptedBuffer.lift(pointer) +} + +public func FfiConverterTypeEncryptedBuffer_lower(_ value: EncryptedBuffer) -> UnsafeMutableRawPointer { + return FfiConverterTypeEncryptedBuffer.lower(value) +} + +public protocol LocalKeyFactoryProtocol { + func fromJwk(jwk: String) throws -> AskarLocalKey + func fromJwkSlice(jwk: [UInt8]) throws -> AskarLocalKey + func fromPublicBytes(alg: AskarKeyAlg, bytes: [UInt8]) throws -> AskarLocalKey + func fromSecretBytes(alg: AskarKeyAlg, bytes: [UInt8]) throws -> AskarLocalKey + func fromSeed(alg: AskarKeyAlg, seed: [UInt8], method: SeedMethod?) throws -> AskarLocalKey + func generate(alg: AskarKeyAlg, ephemeral: Bool) throws -> AskarLocalKey +} + +public class LocalKeyFactory: LocalKeyFactoryProtocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + public convenience init() { + self.init(unsafeFromRawPointer: try! rustCall { + uniffi_aries_askar_fn_constructor_localkeyfactory_new($0) + }) + } + + deinit { + try! rustCall { uniffi_aries_askar_fn_free_localkeyfactory(pointer, $0) } + } + + public func fromJwk(jwk: String) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_localkeyfactory_from_jwk(self.pointer, + FfiConverterString.lower(jwk), $0) + } + ) + } + + public func fromJwkSlice(jwk: [UInt8]) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_localkeyfactory_from_jwk_slice(self.pointer, + FfiConverterSequenceUInt8.lower(jwk), $0) + } + ) + } + + public func fromPublicBytes(alg: AskarKeyAlg, bytes: [UInt8]) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_localkeyfactory_from_public_bytes(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), + FfiConverterSequenceUInt8.lower(bytes), $0) + } + ) + } + + public func fromSecretBytes(alg: AskarKeyAlg, bytes: [UInt8]) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_localkeyfactory_from_secret_bytes(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), + FfiConverterSequenceUInt8.lower(bytes), $0) + } + ) + } + + public func fromSeed(alg: AskarKeyAlg, seed: [UInt8], method: SeedMethod?) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_localkeyfactory_from_seed(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), + FfiConverterSequenceUInt8.lower(seed), + FfiConverterOptionTypeSeedMethod.lower(method), $0) + } + ) + } + + public func generate(alg: AskarKeyAlg, ephemeral: Bool) throws -> AskarLocalKey { + return try FfiConverterTypeAskarLocalKey.lift( + rustCallWithError(FfiConverterTypeErrorCode.lift) { + uniffi_aries_askar_fn_method_localkeyfactory_generate(self.pointer, + FfiConverterTypeAskarKeyAlg.lower(alg), + FfiConverterBool.lower(ephemeral), $0) + } + ) + } +} + +public struct FfiConverterTypeLocalKeyFactory: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = LocalKeyFactory + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> LocalKeyFactory { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if ptr == nil { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: LocalKeyFactory, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> LocalKeyFactory { + return LocalKeyFactory(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: LocalKeyFactory) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +public func FfiConverterTypeLocalKeyFactory_lift(_ pointer: UnsafeMutableRawPointer) throws -> LocalKeyFactory { + return try FfiConverterTypeLocalKeyFactory.lift(pointer) +} + +public func FfiConverterTypeLocalKeyFactory_lower(_ value: LocalKeyFactory) -> UnsafeMutableRawPointer { + return FfiConverterTypeLocalKeyFactory.lower(value) +} + +// Encapsulates an executor that can run Rust tasks +// +// On Swift, `Task.detached` can handle this we just need to know what priority to send it. +public struct UniFfiForeignExecutor { + var priority: TaskPriority + + public init(priority: TaskPriority) { + self.priority = priority + } + + public init() { + priority = Task.currentPriority + } +} + +private struct FfiConverterForeignExecutor: FfiConverter { + typealias SwiftType = UniFfiForeignExecutor + // Rust uses a pointer to represent the FfiConverterForeignExecutor, but we only need a u8. + // let's use `Int`, which is equivalent to `size_t` + typealias FfiType = Int + + static func lift(_ value: FfiType) throws -> SwiftType { + UniFfiForeignExecutor(priority: TaskPriority(rawValue: numericCast(value))) + } + + static func lower(_ value: SwiftType) -> FfiType { + numericCast(value.priority.rawValue) + } + + static func read(from _: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + fatalError("FfiConverterForeignExecutor.read not implemented yet") + } + + static func write(_: SwiftType, into _: inout [UInt8]) { + fatalError("FfiConverterForeignExecutor.read not implemented yet") + } +} + +private func uniffiForeignExecutorCallback(executorHandle: Int, delayMs: UInt32, rustTask: UniFfiRustTaskCallback?, taskData: UnsafeRawPointer?) { + if let rustTask = rustTask { + let executor = try! FfiConverterForeignExecutor.lift(executorHandle) + Task.detached(priority: executor.priority) { + if delayMs != 0 { + let nanoseconds: UInt64 = numericCast(delayMs * 1_000_000) + try! await Task.sleep(nanoseconds: nanoseconds) + } + rustTask(taskData) + } + } + // No else branch: when rustTask is null, we should drop the foreign executor. However, since + // its just a value type, we don't need to do anything here. +} + +private func uniffiInitForeignExecutor() { + uniffi_foreign_executor_callback_set(uniffiForeignExecutorCallback) +} + +public struct AeadParams { + public var nonceLength: Int32 + public var tagLength: Int32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(nonceLength: Int32, tagLength: Int32) { + self.nonceLength = nonceLength + self.tagLength = tagLength + } +} + +extension AeadParams: Equatable, Hashable { + public static func == (lhs: AeadParams, rhs: AeadParams) -> Bool { + if lhs.nonceLength != rhs.nonceLength { + return false + } + if lhs.tagLength != rhs.tagLength { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(nonceLength) + hasher.combine(tagLength) + } +} + +public struct FfiConverterTypeAeadParams: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AeadParams { + return try AeadParams( + nonceLength: FfiConverterInt32.read(from: &buf), + tagLength: FfiConverterInt32.read(from: &buf) + ) + } + + public static func write(_ value: AeadParams, into buf: inout [UInt8]) { + FfiConverterInt32.write(value.nonceLength, into: &buf) + FfiConverterInt32.write(value.tagLength, into: &buf) + } +} + +public func FfiConverterTypeAeadParams_lift(_ buf: RustBuffer) throws -> AeadParams { + return try FfiConverterTypeAeadParams.lift(buf) +} + +public func FfiConverterTypeAeadParams_lower(_ value: AeadParams) -> RustBuffer { + return FfiConverterTypeAeadParams.lower(value) +} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum AskarEntryOperation { + case insert + case replace + case remove +} + +public struct FfiConverterTypeAskarEntryOperation: FfiConverterRustBuffer { + typealias SwiftType = AskarEntryOperation + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarEntryOperation { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .insert + + case 2: return .replace + + case 3: return .remove + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AskarEntryOperation, into buf: inout [UInt8]) { + switch value { + case .insert: + writeInt(&buf, Int32(1)) + + case .replace: + writeInt(&buf, Int32(2)) + + case .remove: + writeInt(&buf, Int32(3)) + } + } +} + +public func FfiConverterTypeAskarEntryOperation_lift(_ buf: RustBuffer) throws -> AskarEntryOperation { + return try FfiConverterTypeAskarEntryOperation.lift(buf) +} + +public func FfiConverterTypeAskarEntryOperation_lower(_ value: AskarEntryOperation) -> RustBuffer { + return FfiConverterTypeAskarEntryOperation.lower(value) +} + +extension AskarEntryOperation: Equatable, Hashable {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum AskarKeyAlg { + case a128Gcm + case a256Gcm + case a128CbcHs256 + case a256CbcHs512 + case a128Kw + case a256Kw + case bls12381g1 + case bls12381g2 + case bls12381g1g2 + case c20p + case xc20p + case ed25519 + case x25519 + case k256 + case p256 + case p384 +} + +public struct FfiConverterTypeAskarKeyAlg: FfiConverterRustBuffer { + typealias SwiftType = AskarKeyAlg + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AskarKeyAlg { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .a128Gcm + + case 2: return .a256Gcm + + case 3: return .a128CbcHs256 + + case 4: return .a256CbcHs512 + + case 5: return .a128Kw + + case 6: return .a256Kw + + case 7: return .bls12381g1 + + case 8: return .bls12381g2 + + case 9: return .bls12381g1g2 + + case 10: return .c20p + + case 11: return .xc20p + + case 12: return .ed25519 + + case 13: return .x25519 + + case 14: return .k256 + + case 15: return .p256 + + case 16: return .p384 + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AskarKeyAlg, into buf: inout [UInt8]) { + switch value { + case .a128Gcm: + writeInt(&buf, Int32(1)) + + case .a256Gcm: + writeInt(&buf, Int32(2)) + + case .a128CbcHs256: + writeInt(&buf, Int32(3)) + + case .a256CbcHs512: + writeInt(&buf, Int32(4)) + + case .a128Kw: + writeInt(&buf, Int32(5)) + + case .a256Kw: + writeInt(&buf, Int32(6)) + + case .bls12381g1: + writeInt(&buf, Int32(7)) + + case .bls12381g2: + writeInt(&buf, Int32(8)) + + case .bls12381g1g2: + writeInt(&buf, Int32(9)) + + case .c20p: + writeInt(&buf, Int32(10)) + + case .xc20p: + writeInt(&buf, Int32(11)) + + case .ed25519: + writeInt(&buf, Int32(12)) + + case .x25519: + writeInt(&buf, Int32(13)) + + case .k256: + writeInt(&buf, Int32(14)) + + case .p256: + writeInt(&buf, Int32(15)) + + case .p384: + writeInt(&buf, Int32(16)) + } + } +} + +public func FfiConverterTypeAskarKeyAlg_lift(_ buf: RustBuffer) throws -> AskarKeyAlg { + return try FfiConverterTypeAskarKeyAlg.lift(buf) +} + +public func FfiConverterTypeAskarKeyAlg_lower(_ value: AskarKeyAlg) -> RustBuffer { + return FfiConverterTypeAskarKeyAlg.lower(value) +} + +extension AskarKeyAlg: Equatable, Hashable {} + +public enum ErrorCode { + case Success(message: String) + case Backend(message: String) + case Busy(message: String) + case Duplicate(message: String) + case Encryption(message: String) + case Input(message: String) + case NotFound(message: String) + case Unexpected(message: String) + case Unsupported(message: String) + case Custom(message: String) + + fileprivate static func uniffiErrorHandler(_ error: RustBuffer) throws -> Error { + return try FfiConverterTypeErrorCode.lift(error) + } +} + +public struct FfiConverterTypeErrorCode: FfiConverterRustBuffer { + typealias SwiftType = ErrorCode + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ErrorCode { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return try .Success( + message: FfiConverterString.read(from: &buf) + ) + case 2: return try .Backend( + message: FfiConverterString.read(from: &buf) + ) + case 3: return try .Busy( + message: FfiConverterString.read(from: &buf) + ) + case 4: return try .Duplicate( + message: FfiConverterString.read(from: &buf) + ) + case 5: return try .Encryption( + message: FfiConverterString.read(from: &buf) + ) + case 6: return try .Input( + message: FfiConverterString.read(from: &buf) + ) + case 7: return try .NotFound( + message: FfiConverterString.read(from: &buf) + ) + case 8: return try .Unexpected( + message: FfiConverterString.read(from: &buf) + ) + case 9: return try .Unsupported( + message: FfiConverterString.read(from: &buf) + ) + case 10: return try .Custom( + message: FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: ErrorCode, into buf: inout [UInt8]) { + switch value { + case let .Success(message): + writeInt(&buf, Int32(1)) + FfiConverterString.write(message, into: &buf) + + case let .Backend(message): + writeInt(&buf, Int32(2)) + FfiConverterString.write(message, into: &buf) + + case let .Busy(message): + writeInt(&buf, Int32(3)) + FfiConverterString.write(message, into: &buf) + + case let .Duplicate(message): + writeInt(&buf, Int32(4)) + FfiConverterString.write(message, into: &buf) + + case let .Encryption(message): + writeInt(&buf, Int32(5)) + FfiConverterString.write(message, into: &buf) + + case let .Input(message): + writeInt(&buf, Int32(6)) + FfiConverterString.write(message, into: &buf) + + case let .NotFound(message): + writeInt(&buf, Int32(7)) + FfiConverterString.write(message, into: &buf) + + case let .Unexpected(message): + writeInt(&buf, Int32(8)) + FfiConverterString.write(message, into: &buf) + + case let .Unsupported(message): + writeInt(&buf, Int32(9)) + FfiConverterString.write(message, into: &buf) + + case let .Custom(message): + writeInt(&buf, Int32(10)) + FfiConverterString.write(message, into: &buf) + } + } +} + +extension ErrorCode: Equatable, Hashable {} + +extension ErrorCode: Error {} + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +public enum SeedMethod { + case blsKeyGen +} + +public struct FfiConverterTypeSeedMethod: FfiConverterRustBuffer { + typealias SwiftType = SeedMethod + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SeedMethod { + let variant: Int32 = try readInt(&buf) + switch variant { + case 1: return .blsKeyGen + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: SeedMethod, into buf: inout [UInt8]) { + switch value { + case .blsKeyGen: + writeInt(&buf, Int32(1)) + } + } +} + +public func FfiConverterTypeSeedMethod_lift(_ buf: RustBuffer) throws -> SeedMethod { + return try FfiConverterTypeSeedMethod.lift(buf) +} + +public func FfiConverterTypeSeedMethod_lower(_ value: SeedMethod) -> RustBuffer { + return FfiConverterTypeSeedMethod.lower(value) +} + +extension SeedMethod: Equatable, Hashable {} + +private struct FfiConverterOptionInt64: FfiConverterRustBuffer { + typealias SwiftType = Int64? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterInt64.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterInt64.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionString: FfiConverterRustBuffer { + typealias SwiftType = String? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterString.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterString.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionTypeAskarEntry: FfiConverterRustBuffer { + typealias SwiftType = AskarEntry? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeAskarEntry.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeAskarEntry.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionTypeAskarKeyEntry: FfiConverterRustBuffer { + typealias SwiftType = AskarKeyEntry? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeAskarKeyEntry.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeAskarKeyEntry.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionTypeAskarKeyAlg: FfiConverterRustBuffer { + typealias SwiftType = AskarKeyAlg? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeAskarKeyAlg.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeAskarKeyAlg.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionTypeSeedMethod: FfiConverterRustBuffer { + typealias SwiftType = SeedMethod? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeSeedMethod.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeSeedMethod.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionSequenceUInt8: FfiConverterRustBuffer { + typealias SwiftType = [UInt8]? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterSequenceUInt8.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterSequenceUInt8.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterOptionSequenceTypeAskarEntry: FfiConverterRustBuffer { + typealias SwiftType = [AskarEntry]? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterSequenceTypeAskarEntry.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterSequenceTypeAskarEntry.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + +private struct FfiConverterSequenceUInt8: FfiConverterRustBuffer { + typealias SwiftType = [UInt8] + + public static func write(_ value: [UInt8], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterUInt8.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt8] { + let len: Int32 = try readInt(&buf) + var seq = [UInt8]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterUInt8.read(from: &buf)) + } + return seq + } +} + +private struct FfiConverterSequenceString: FfiConverterRustBuffer { + typealias SwiftType = [String] + + public static func write(_ value: [String], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterString.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] { + let len: Int32 = try readInt(&buf) + var seq = [String]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterString.read(from: &buf)) + } + return seq + } +} + +private struct FfiConverterSequenceTypeAskarEntry: FfiConverterRustBuffer { + typealias SwiftType = [AskarEntry] + + public static func write(_ value: [AskarEntry], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeAskarEntry.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [AskarEntry] { + let len: Int32 = try readInt(&buf) + var seq = [AskarEntry]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeAskarEntry.read(from: &buf)) + } + return seq + } +} + +private struct FfiConverterSequenceTypeAskarKeyEntry: FfiConverterRustBuffer { + typealias SwiftType = [AskarKeyEntry] + + public static func write(_ value: [AskarKeyEntry], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeAskarKeyEntry.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [AskarKeyEntry] { + let len: Int32 = try readInt(&buf) + var seq = [AskarKeyEntry]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeAskarKeyEntry.read(from: &buf)) + } + return seq + } +} + +private struct FfiConverterDictionaryStringString: FfiConverterRustBuffer { + public static func write(_ value: [String: String], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for (key, value) in value { + FfiConverterString.write(key, into: &buf) + FfiConverterString.write(value, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String: String] { + let len: Int32 = try readInt(&buf) + var dict = [String: String]() + dict.reserveCapacity(Int(len)) + for _ in 0 ..< len { + let key = try FfiConverterString.read(from: &buf) + let value = try FfiConverterString.read(from: &buf) + dict[key] = value + } + return dict + } +} // Callbacks for async functions + +// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They +// lift the return value or error and resume the suspended function. +private func uniffiFutureCallbackHandlerVoidTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue _: UInt8, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + continuation.pointee.resume(returning: ()) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerInt32( + rawContinutation: UnsafeRawPointer, + returnValue: Int32, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterInt32.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerInt64TypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: Int64, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterInt64.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerBool( + rawContinutation: UnsafeRawPointer, + returnValue: Int8, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterBool.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerBoolTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: Int8, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterBool.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerString( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterString.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerStringTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterString.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarCrypto( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterTypeAskarCrypto.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarEcdh1PU( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterTypeAskarEcdh1PU.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarEcdhEs( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterTypeAskarEcdhEs.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarLocalKeyTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterTypeAskarLocalKey.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarScanTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterTypeAskarScan.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarSessionTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterTypeAskarSession.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarStoreTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterTypeAskarStore.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarStoreManager( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterTypeAskarStoreManager.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeEncryptedBufferTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterTypeEncryptedBuffer.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeLocalKeyFactory( + rawContinutation: UnsafeRawPointer, + returnValue: UnsafeMutableRawPointer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterTypeLocalKeyFactory.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAeadParamsTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterTypeAeadParams.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerTypeAskarKeyAlg( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterTypeAskarKeyAlg.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerOptionString( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterOptionString.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerOptionTypeAskarEntryTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterOptionTypeAskarEntry.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerOptionTypeAskarKeyEntryTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterOptionTypeAskarKeyEntry.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerOptionSequenceTypeAskarEntryTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[AskarEntry]?, Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterOptionSequenceTypeAskarEntry.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerSequenceUInt8( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[UInt8], Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterSequenceUInt8.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerSequenceUInt8TypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[UInt8], Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterSequenceUInt8.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerSequenceStringTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[String], Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterSequenceString.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerSequenceTypeAskarEntryTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[AskarEntry], Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterSequenceTypeAskarEntry.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerSequenceTypeAskarKeyEntryTypeErrorCode( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[AskarKeyEntry], Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: FfiConverterTypeErrorCode.lift) + try continuation.pointee.resume(returning: FfiConverterSequenceTypeAskarKeyEntry.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private func uniffiFutureCallbackHandlerDictionaryStringString( + rawContinutation: UnsafeRawPointer, + returnValue: RustBuffer, + callStatus: RustCallStatus +) { + let continuation = rawContinutation.bindMemory( + to: CheckedContinuation<[String: String], Error>.self, + capacity: 1 + ) + + do { + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: nil) + try continuation.pointee.resume(returning: FfiConverterDictionaryStringString.lift(returnValue)) + } catch { + continuation.pointee.resume(throwing: error) + } +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} + +// Use a global variables to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private var initializationResult: InitializationResult { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 22 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_aries_askar_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if uniffi_aries_askar_checksum_method_askarentry_category() != 3260 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarentry_name() != 32165 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarentry_tags() != 25644 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarentry_value() != 15374 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarkeyentry_algorithm() != 49759 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarkeyentry_is_local() != 55452 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarkeyentry_load_local_key() != 54061 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarkeyentry_metadata() != 37970 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarkeyentry_name() != 37206 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarkeyentry_tags() != 44110 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarscan_fetch_all() != 38256 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarscan_next() != 61044 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_close() != 21663 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_count() != 23751 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_fetch() != 15446 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_fetch_all() != 14311 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_fetch_all_keys() != 20309 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_fetch_key() != 29640 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_insert_key() != 50809 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_remove_all() != 30181 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_remove_key() != 7409 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_update() != 45947 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarsession_update_key() != 58440 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_close() != 5720 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_create_profile() != 52699 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_get_profile_name() != 43933 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_rekey() != 35956 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_remove_profile() != 36069 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_scan() != 18668 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstore_session() != 46605 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_aead_decrypt() != 28744 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_aead_encrypt() != 26220 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_aead_padding() != 19466 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_aead_params() != 51278 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_aead_random_nonce() != 61893 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_algorithm() != 53705 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_convert_key() != 35516 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_sign_message() != 39020 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_jwk_public() != 54824 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_jwk_secret() != 54958 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_jwk_thumbprint() != 30788 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_jwk_thumbprints() != 2898 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_key_exchange() != 29493 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_public_bytes() != 10734 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_to_secret_bytes() != 33910 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_unwrap_key() != 32063 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_verify_signature() != 24569 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarlocalkey_wrap_key() != 48354 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_encryptedbuffer_ciphertext() != 25707 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_encryptedbuffer_ciphertext_tag() != 4068 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_encryptedbuffer_nonce() != 58146 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_encryptedbuffer_tag() != 5792 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_localkeyfactory_from_jwk() != 44160 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_localkeyfactory_from_jwk_slice() != 57872 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_localkeyfactory_from_public_bytes() != 47192 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_localkeyfactory_from_secret_bytes() != 44895 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_localkeyfactory_from_seed() != 47817 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_localkeyfactory_generate() != 15969 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstoremanager_generate_raw_store_key() != 65070 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstoremanager_open() != 59212 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstoremanager_provision() != 51063 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstoremanager_remove() != 60582 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarstoremanager_set_default_logger() != 42575 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarcrypto_box_open() != 21968 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarcrypto_box_seal() != 6843 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarcrypto_box_seal_open() != 65089 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarcrypto_crypto_box() != 6491 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarcrypto_random_nonce() != 3121 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdhes_decrypt_direct() != 57738 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdhes_derive_key() != 30605 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdhes_encrypt_direct() != 39447 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdhes_receiver_unwrap_key() != 44741 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdhes_sender_wrap_key() != 43003 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdh1pu_decrypt_direct() != 45235 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdh1pu_derive_key() != 856 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdh1pu_encrypt_direct() != 19815 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdh1pu_receiver_unwrap_key() != 16953 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_aries_askar_checksum_method_askarecdh1pu_sender_wrap_key() != 48518 { + return InitializationResult.apiChecksumMismatch + } + if uniffi__checksum_constructor_localkeyfactory_new() != 64154 { + return InitializationResult.apiChecksumMismatch + } + if uniffi__checksum_constructor_askarstoremanager_new() != 57892 { + return InitializationResult.apiChecksumMismatch + } + if uniffi__checksum_constructor_askarcrypto_new() != 42300 { + return InitializationResult.apiChecksumMismatch + } + if uniffi__checksum_constructor_askarecdhes_new() != 15713 { + return InitializationResult.apiChecksumMismatch + } + if uniffi__checksum_constructor_askarecdh1pu_new() != 32728 { + return InitializationResult.apiChecksumMismatch + } + + uniffiInitForeignExecutor() + return InitializationResult.ok +} + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} diff --git a/wrappers/swift/Askar/Tests/AskarTests/CryptoTests.swift b/wrappers/swift/Askar/Tests/AskarTests/CryptoTests.swift new file mode 100644 index 00000000..0304a278 --- /dev/null +++ b/wrappers/swift/Askar/Tests/AskarTests/CryptoTests.swift @@ -0,0 +1,25 @@ +import XCTest +@testable import Askar + +final class CryptoTests: XCTestCase { + let keyFactory = LocalKeyFactory() + let crypto = AskarCrypto() + + func testCryptoBoxSeal() throws { + let key = try keyFactory.generate(alg: .x25519, ephemeral: false) + let message = "test message".data(using: .utf8)! + let enc = try crypto.boxSeal(receiverKey: key, message: [UInt8](message)) + let dec = try crypto.boxSealOpen(receiverKey: key, ciphertext: [UInt8](enc)) + XCTAssertEqual(message, Data(dec)) + } + + func testCryptoBox() throws { + let senderKey = try keyFactory.generate(alg: .x25519, ephemeral: false) + let receiverKey = try keyFactory.generate(alg: .x25519, ephemeral: false) + let message = "test message".data(using: .utf8)! + let nonce = try crypto.randomNonce() + let enc = try crypto.cryptoBox(receiverKey: receiverKey, senderKey: senderKey, message: [UInt8](message), nonce: nonce) + let dec = try crypto.boxOpen(receiverKey: receiverKey, senderKey: senderKey, message: enc, nonce: nonce) + XCTAssertEqual(message, Data(dec)) + } +} diff --git a/wrappers/swift/Askar/Tests/AskarTests/JoseEcdhTests.swift b/wrappers/swift/Askar/Tests/AskarTests/JoseEcdhTests.swift new file mode 100644 index 00000000..2f6962c2 --- /dev/null +++ b/wrappers/swift/Askar/Tests/AskarTests/JoseEcdhTests.swift @@ -0,0 +1,206 @@ +import XCTest +@testable import Askar + +extension String { + func base64url() -> String { + return self.data(using: .utf8)!.base64url() + } +} + +extension Data { + func base64url() -> String { + let base64url = self.base64EncodedString() + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "=", with: "") + return base64url + } + + static func fromHex(_ string: String) -> Data? { + let len = string.count / 2 + var data = Data(capacity: len) + for i in 0..