diff --git a/.gitignore b/.gitignore index fbad06e..ed371f1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ Cargo.lock sphinx-key/Cargo.lock notes.md test-flash -.env \ No newline at end of file +.env diff --git a/Cargo.toml b/Cargo.toml index 6108ea6..ad25896 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ members = [ exclude = [ "sphinx-key", - "crypter" + "crypter", + "crypter-ffi" ] [patch.crates-io] diff --git a/crypter-ffi/Cargo.toml b/crypter-ffi/Cargo.toml new file mode 100644 index 0000000..27d15a2 --- /dev/null +++ b/crypter-ffi/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "crypter-ffi" +version = "0.1.0" +authors = ["Evan Feenstra "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] +name = "crypter" + +[dependencies] +sphinx-key-crypter = { path = "../crypter" } +uniffi = "0.19.2" +hex = "0.4.3" +thiserror = "1.0.31" +uniffi_macros = "0.11.0" + +[build-dependencies] +uniffi_build = "0.19.2" + +[patch.crates-io] +getrandom = { version = "0.2", git = "https://github.com/esp-rs-compat/getrandom.git" } +secp256k1 = { git = "https://github.com/Evanfeenstra/rust-secp256k1", branch = "v0.22.0-new-rand" } +lightning = { git = "https://github.com/Evanfeenstra/rust-lightning", branch = "v0.0.108-branch" } + diff --git a/crypter-ffi/build.rs b/crypter-ffi/build.rs new file mode 100644 index 0000000..b191816 --- /dev/null +++ b/crypter-ffi/build.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi_build::generate_scaffolding("./src/crypter.udl").unwrap(); +} \ No newline at end of file diff --git a/crypter-ffi/readme.md b/crypter-ffi/readme.md new file mode 100644 index 0000000..5ae03dc --- /dev/null +++ b/crypter-ffi/readme.md @@ -0,0 +1,10 @@ +uniffi-bindgen --version +should match the uniffi version in Cargo.toml + +uniffi-bindgen generate src/crypter.udl --language kotlin + +uniffi-bindgen generate src/crypter.udl --language swift + +### manually build the C ffi + +uniffi-bindgen scaffolding src/crypter.udl diff --git a/crypter-ffi/src/crypter.udl b/crypter-ffi/src/crypter.udl new file mode 100644 index 0000000..049cae1 --- /dev/null +++ b/crypter-ffi/src/crypter.udl @@ -0,0 +1,19 @@ +[Error] +enum CrypterError { + "DeriveSharedSecret", + "Encrypt", + "Decrypt", + "BadPubkey", + "BadSecret", + "BadNonce", + "BadCiper", +}; + +namespace crypter { + [Throws=CrypterError] + string derive_shared_secret(string their_pubkey, string my_secret_key); + [Throws=CrypterError] + string encrypt(string plaintext, string secret, string nonce); + [Throws=CrypterError] + string decrypt(string ciphertext, string secret); +}; \ No newline at end of file diff --git a/crypter-ffi/src/lib.rs b/crypter-ffi/src/lib.rs new file mode 100644 index 0000000..a454820 --- /dev/null +++ b/crypter-ffi/src/lib.rs @@ -0,0 +1,98 @@ +mod parse; + +use sphinx_key_crypter::chacha::{decrypt as chacha_decrypt, encrypt as chacha_encrypt}; +use sphinx_key_crypter::ecdh::derive_shared_secret_from_slice; + +uniffi_macros::include_scaffolding!("crypter"); + +pub type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum CrypterError { + #[error("Failed to derive shared secret")] + DeriveSharedSecret, + #[error("Failed to encrypt")] + Encrypt, + #[error("Failed to decrypt")] + Decrypt, + #[error("Bad pubkey")] + BadPubkey, + #[error("Bad secret")] + BadSecret, + #[error("Bad nonce")] + BadNonce, + #[error("Bad cipher")] + BadCiper, +} + +// their_pubkey: 33 bytes +// my_secret_key: 32 bytes +// return shared secret: 32 bytes +pub fn derive_shared_secret(their_pubkey: String, my_secret_key: String) -> Result { + let pubkey = parse::parse_public_key_string(their_pubkey)?; + let secret_key = parse::parse_secret_string(my_secret_key)?; + let secret = match derive_shared_secret_from_slice(pubkey, secret_key) { + Ok(s) => s, + Err(_) => return Err(CrypterError::DeriveSharedSecret), + }; + Ok(hex::encode(secret)) +} + +// plaintext: 32 bytes +// secret: 32 bytes +// nonce: 8 bytes +// return ciphertext: 56 bytes +pub fn encrypt(plaintext: String, secret: String, nonce: String) -> Result { + let plain = parse::parse_secret_string(plaintext)?; + let sec = parse::parse_secret_string(secret)?; + let non = parse::parse_nonce_string(nonce)?; + let cipher = match chacha_encrypt(plain, sec, non) { + Ok(c) => c, + Err(_) => return Err(CrypterError::Encrypt), + }; + Ok(hex::encode(cipher)) +} + +// ciphertext: 56 bytes +// secret: 32 bytes +// return plaintext: 32 bytes +pub fn decrypt(ciphertext: String, secret: String) -> Result { + let cipher = parse::parse_cipher_string(ciphertext)?; + let sec = parse::parse_secret_string(secret)?; + let plain = match chacha_decrypt(cipher, sec) { + Ok(c) => c, + Err(_) => return Err(CrypterError::Decrypt), + }; + Ok(hex::encode(plain)) +} + +#[cfg(test)] +mod tests { + use crate::{decrypt, derive_shared_secret, encrypt, Result}; + + #[test] + fn test_crypter() -> Result<()> { + let sk1 = "86c8977989592a97beb409bc27fde76e981ce3543499fd61743755b832e92a3e"; + let pk1 = "0362a684901b8d065fb034bc44ea972619a409aeafc2a698016a74f6eee1008aca"; + + let sk2 = "21c2d41c7394b0a87dae89576bee2552aedb54a204cdcdbf5cdceb0b4c1c2a17"; + let pk2 = "027dd6297aff570a409fe05032b6e1dab39f309daa8c438a65c32e3d7b4722b7c3"; + + // derive shared secrets + let sec1 = derive_shared_secret(pk2.to_string(), sk1.to_string())?; + let sec2 = derive_shared_secret(pk1.to_string(), sk2.to_string())?; + assert_eq!(sec1, sec2); + + // encrypt plaintext with sec1 + let plaintext = "59ff446bec1d96dc7d1a69232cd69ca409e069294e983df7f1e3e5fb3c95c41c"; + let nonce = "0da01cc0c0a73ad3"; + let cipher = encrypt(plaintext.to_string(), sec1, nonce.to_string())?; + + // decrypt with sec2 + let plain = decrypt(cipher, sec2)?; + assert_eq!(plaintext, plain); + + println!("PLAINTEXT MATCHES!"); + Ok(()) + } +} diff --git a/crypter-ffi/src/parse.rs b/crypter-ffi/src/parse.rs new file mode 100644 index 0000000..2b68409 --- /dev/null +++ b/crypter-ffi/src/parse.rs @@ -0,0 +1,65 @@ +use crate::{Result, CrypterError}; + +use sphinx_key_crypter::ecdh::PUBLIC_KEY_LEN; +use sphinx_key_crypter::chacha::{NONCE_END_LEN, KEY_LEN, CIPHER_LEN}; +use std::convert::TryInto; + +pub(crate) fn parse_secret_string(sk: String) -> Result<[u8; KEY_LEN]> { + if sk.len() != KEY_LEN * 2 { + return Err(CrypterError::BadSecret) + } + let secret_key_bytes: Vec = match hex::decode(sk) { + Ok(sk) => sk, + Err(_) => return Err(CrypterError::BadSecret), + }; + let secret_key: [u8; KEY_LEN] = match secret_key_bytes.try_into() { + Ok(sk) => sk, + Err(_) => return Err(CrypterError::BadSecret), + }; + Ok(secret_key) +} + +pub(crate) fn parse_public_key_string(pk: String) -> Result<[u8; PUBLIC_KEY_LEN]> { + if pk.len() != PUBLIC_KEY_LEN * 2 { + return Err(CrypterError::BadPubkey) + } + let pubkey_bytes: Vec = match hex::decode(pk) { + Ok(pk) => pk, + Err(_) => return Err(CrypterError::BadPubkey), + }; + let pubkey: [u8; PUBLIC_KEY_LEN] = match pubkey_bytes.try_into() { + Ok(pk) => pk, + Err(_) => return Err(CrypterError::BadPubkey), + }; + Ok(pubkey) +} + +pub(crate) fn parse_nonce_string(n: String) -> Result<[u8; NONCE_END_LEN]> { + if n.len() != NONCE_END_LEN * 2 { + return Err(CrypterError::BadNonce) + } + let nonce_bytes: Vec = match hex::decode(n) { + Ok(n) => n, + Err(_) => return Err(CrypterError::BadNonce), + }; + let nonce: [u8; NONCE_END_LEN] = match nonce_bytes.try_into() { + Ok(n) => n, + Err(_) => return Err(CrypterError::BadNonce), + }; + Ok(nonce) +} + +pub(crate) fn parse_cipher_string(c: String) -> Result<[u8; CIPHER_LEN]> { + if c.len() != CIPHER_LEN * 2 { + return Err(CrypterError::BadCiper) + } + let cipher_bytes: Vec = match hex::decode(c) { + Ok(n) => n, + Err(_) => return Err(CrypterError::BadCiper), + }; + let cipher: [u8; CIPHER_LEN] = match cipher_bytes.try_into() { + Ok(n) => n, + Err(_) => return Err(CrypterError::BadCiper), + }; + Ok(cipher) +} diff --git a/crypter-ffi/src/uniffi/crypter/crypter.kt b/crypter-ffi/src/uniffi/crypter/crypter.kt new file mode 100644 index 0000000..10e2a63 --- /dev/null +++ b/crypter-ffi/src/uniffi/crypter/crypter.kt @@ -0,0 +1,419 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +@file:Suppress("NAME_SHADOWING") + +package uniffi.crypter; + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the detils of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +import com.sun.jna.Library +import com.sun.jna.Native +import com.sun.jna.Pointer +import com.sun.jna.Structure +import com.sun.jna.ptr.ByReference +import java.nio.ByteBuffer +import java.nio.ByteOrder + +// This is a helper for safely working with byte buffers returned from the Rust code. +// A rust-owned buffer is represented by its capacity, its current length, and a +// pointer to the underlying data. + +@Structure.FieldOrder("capacity", "len", "data") +open class RustBuffer : Structure() { + @JvmField var capacity: Int = 0 + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue : RustBuffer(), Structure.ByValue + class ByReference : RustBuffer(), Structure.ByReference + + companion object { + internal fun alloc(size: Int = 0) = rustCall() { status -> + _UniFFILib.INSTANCE.ffi_crypter_b428_rustbuffer_alloc(size, status).also { + if(it.data == null) { + throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") + } + } + } + + internal fun free(buf: RustBuffer.ByValue) = rustCall() { status -> + _UniFFILib.INSTANCE.ffi_crypter_b428_rustbuffer_free(buf, status) + } + } + + @Suppress("TooGenericExceptionThrown") + fun asByteBuffer() = + this.data?.getByteBuffer(0, this.len.toLong())?.also { + it.order(ByteOrder.BIG_ENDIAN) + } +} + +/** + * The equivalent of the `*mut RustBuffer` type. + * Required for callbacks taking in an out pointer. + * + * Size is the sum of all values in the struct. + */ +class RustBufferByReference : ByReference(16) { + /** + * Set the pointed-to `RustBuffer` to the given value. + */ + fun setValue(value: RustBuffer.ByValue) { + // NOTE: The offsets are as they are in the C-like struct. + val pointer = getPointer() + pointer.setInt(0, value.capacity) + pointer.setInt(4, value.len) + pointer.setPointer(8, value.data) + } +} + +// This is a helper for safely passing byte references into the rust code. +// It's not actually used at the moment, because there aren't many things that you +// can take a direct pointer to in the JVM, and if we're going to copy something +// then we might as well copy it into a `RustBuffer`. But it's here for API +// completeness. + +@Structure.FieldOrder("len", "data") +open class ForeignBytes : Structure() { + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue : ForeignBytes(), Structure.ByValue +} +// The FfiConverter interface handles converter types to and from the FFI +// +// All implementing objects should be public to support external types. When a +// type is external we need to import it's FfiConverter. +public interface FfiConverter { + // Convert an FFI type to a Kotlin type + fun lift(value: FfiType): KotlinType + + // Convert an Kotlin type to an FFI type + fun lower(value: KotlinType): FfiType + + // Read a Kotlin type from a `ByteBuffer` + fun read(buf: ByteBuffer): KotlinType + + // Calculate bytes to allocate when creating a `RustBuffer` + // + // This must return at least as many bytes as the write() function will + // write. It can return more bytes than needed, for example when writing + // Strings we can't know the exact bytes needed until we the UTF-8 + // encoding, so we pessimistically allocate the largest size possible (3 + // bytes per codepoint). Allocating extra bytes is not really a big deal + // because the `RustBuffer` is short-lived. + fun allocationSize(value: KotlinType): Int + + // Write a Kotlin type to a `ByteBuffer` + fun write(value: KotlinType, buf: ByteBuffer) + + // Lower a value into a `RustBuffer` + // + // This method lowers a value into a `RustBuffer` rather than the normal + // FfiType. It's used by the callback interface code. Callback interface + // returns are always serialized into a `RustBuffer` regardless of their + // normal FFI type. + fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { + val rbuf = RustBuffer.alloc(allocationSize(value)) + try { + val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + write(value, bbuf) + rbuf.writeField("len", bbuf.position()) + return rbuf + } catch (e: Throwable) { + RustBuffer.free(rbuf) + throw e + } + } + + // Lift a value from a `RustBuffer`. + // + // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. + // It's currently only used by the `FfiConverterRustBuffer` class below. + fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { + val byteBuf = rbuf.asByteBuffer()!! + try { + val item = read(byteBuf) + if (byteBuf.hasRemaining()) { + throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") + } + return item + } finally { + RustBuffer.free(rbuf) + } + } +} + +// FfiConverter that uses `RustBuffer` as the FfiType +public interface FfiConverterRustBuffer: FfiConverter { + override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) + override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) +} +// A handful of classes and functions to support the generated data structures. +// This would be a good candidate for isolating in its own ffi-support lib. +// Error runtime. +@Structure.FieldOrder("code", "error_buf") +internal open class RustCallStatus : Structure() { + @JvmField var code: Int = 0 + @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() + + fun isSuccess(): Boolean { + return code == 0 + } + + fun isError(): Boolean { + return code == 1 + } + + fun isPanic(): Boolean { + return code == 2 + } +} + +class InternalException(message: String) : Exception(message) + +// Each top-level error class has a companion object that can lift the error from the call status's rust buffer +interface CallStatusErrorHandler { + fun lift(error_buf: RustBuffer.ByValue): E; +} + +// Helpers for calling Rust +// In practice we usually need to be synchronized to call this safely, so it doesn't +// synchronize itself + +// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err +private inline fun rustCallWithError(errorHandler: CallStatusErrorHandler, callback: (RustCallStatus) -> U): U { + var status = RustCallStatus(); + val return_value = callback(status) + if (status.isSuccess()) { + return return_value + } else if (status.isError()) { + throw errorHandler.lift(status.error_buf) + } else if (status.isPanic()) { + // 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 (status.error_buf.len > 0) { + throw InternalException(FfiConverterString.lift(status.error_buf)) + } else { + throw InternalException("Rust panic") + } + } else { + throw InternalException("Unknown rust call status: $status.code") + } +} + +// CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object NullCallStatusErrorHandler: CallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): InternalException { + RustBuffer.free(error_buf) + return InternalException("Unexpected CALL_ERROR") + } +} + +// Call a rust function that returns a plain value +private inline fun rustCall(callback: (RustCallStatus) -> U): U { + return rustCallWithError(NullCallStatusErrorHandler, callback); +} + +// Contains loading, initialization code, +// and the FFI Function declarations in a com.sun.jna.Library. +@Synchronized +private fun findLibraryName(componentName: String): String { + val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") + if (libOverride != null) { + return libOverride + } + return "uniffi_crypter" +} + +private inline fun loadIndirect( + componentName: String +): Lib { + return Native.load(findLibraryName(componentName), Lib::class.java) +} + +// A JNA Library to expose the extern-C FFI definitions. +// This is an implementation detail which will be called internally by the public API. + +internal interface _UniFFILib : Library { + companion object { + internal val INSTANCE: _UniFFILib by lazy { + loadIndirect<_UniFFILib>(componentName = "crypter") + + } + } + + fun crypter_b428_derive_shared_secret(`theirPubkey`: RustBuffer.ByValue,`mySecretKey`: RustBuffer.ByValue, + _uniffi_out_err: RustCallStatus + ): RustBuffer.ByValue + + fun crypter_b428_encrypt(`plaintext`: RustBuffer.ByValue,`secret`: RustBuffer.ByValue,`nonce`: RustBuffer.ByValue, + _uniffi_out_err: RustCallStatus + ): RustBuffer.ByValue + + fun crypter_b428_decrypt(`ciphertext`: RustBuffer.ByValue,`secret`: RustBuffer.ByValue, + _uniffi_out_err: RustCallStatus + ): RustBuffer.ByValue + + fun ffi_crypter_b428_rustbuffer_alloc(`size`: Int, + _uniffi_out_err: RustCallStatus + ): RustBuffer.ByValue + + fun ffi_crypter_b428_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue, + _uniffi_out_err: RustCallStatus + ): RustBuffer.ByValue + + fun ffi_crypter_b428_rustbuffer_free(`buf`: RustBuffer.ByValue, + _uniffi_out_err: RustCallStatus + ): Unit + + fun ffi_crypter_b428_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Int, + _uniffi_out_err: RustCallStatus + ): RustBuffer.ByValue + + +} + +// Public interface members begin here. + + +public object FfiConverterString: FfiConverter { + // Note: we don't inherit from FfiConverterRustBuffer, because we use a + // special encoding when lowering/lifting. We can use `RustBuffer.len` to + // store our length and avoid writing it out to the buffer. + override fun lift(value: RustBuffer.ByValue): String { + try { + val byteArr = ByteArray(value.len) + value.asByteBuffer()!!.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } finally { + RustBuffer.free(value) + } + } + + override fun read(buf: ByteBuffer): String { + val len = buf.getInt() + val byteArr = ByteArray(len) + buf.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } + + override fun lower(value: String): RustBuffer.ByValue { + val byteArr = value.toByteArray(Charsets.UTF_8) + // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us + // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. + val rbuf = RustBuffer.alloc(byteArr.size) + rbuf.asByteBuffer()!!.put(byteArr) + return rbuf + } + + // We aren't sure exactly how many bytes our string will be once it's UTF-8 + // encoded. Allocate 3 bytes per unicode codepoint which will always be + // enough. + override fun allocationSize(value: String): Int { + val sizeForLength = 4 + val sizeForString = value.length * 3 + return sizeForLength + sizeForString + } + + override fun write(value: String, buf: ByteBuffer) { + val byteArr = value.toByteArray(Charsets.UTF_8) + buf.putInt(byteArr.size) + buf.put(byteArr) + } +} + + + + + +sealed class CrypterException(message: String): Exception(message) { + // Each variant is a nested class + // Flat enums carries a string error message, so no special implementation is necessary. + class DeriveSharedSecret(message: String) : CrypterException(message) + class Encrypt(message: String) : CrypterException(message) + class Decrypt(message: String) : CrypterException(message) + class BadPubkey(message: String) : CrypterException(message) + class BadSecret(message: String) : CrypterException(message) + class BadNonce(message: String) : CrypterException(message) + class BadCiper(message: String) : CrypterException(message) + + + companion object ErrorHandler : CallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): CrypterException = FfiConverterTypeCrypterError.lift(error_buf) + } +} + +public object FfiConverterTypeCrypterError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CrypterException { + + return when(buf.getInt()) { + 1 -> CrypterException.DeriveSharedSecret(FfiConverterString.read(buf)) + 2 -> CrypterException.Encrypt(FfiConverterString.read(buf)) + 3 -> CrypterException.Decrypt(FfiConverterString.read(buf)) + 4 -> CrypterException.BadPubkey(FfiConverterString.read(buf)) + 5 -> CrypterException.BadSecret(FfiConverterString.read(buf)) + 6 -> CrypterException.BadNonce(FfiConverterString.read(buf)) + 7 -> CrypterException.BadCiper(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + + } + + @Suppress("UNUSED_PARAMETER") + override fun allocationSize(value: CrypterException): Int { + throw RuntimeException("Writing Errors is not supported") + } + + @Suppress("UNUSED_PARAMETER") + override fun write(value: CrypterException, buf: ByteBuffer) { + throw RuntimeException("Writing Errors is not supported") + } + +} +@Throws(CrypterException::class) + +fun `deriveSharedSecret`(`theirPubkey`: String, `mySecretKey`: String): String { + return FfiConverterString.lift( + rustCallWithError(CrypterException) { _status -> + _UniFFILib.INSTANCE.crypter_b428_derive_shared_secret(FfiConverterString.lower(`theirPubkey`), FfiConverterString.lower(`mySecretKey`), _status) +}) +} + + +@Throws(CrypterException::class) + +fun `encrypt`(`plaintext`: String, `secret`: String, `nonce`: String): String { + return FfiConverterString.lift( + rustCallWithError(CrypterException) { _status -> + _UniFFILib.INSTANCE.crypter_b428_encrypt(FfiConverterString.lower(`plaintext`), FfiConverterString.lower(`secret`), FfiConverterString.lower(`nonce`), _status) +}) +} + + +@Throws(CrypterException::class) + +fun `decrypt`(`ciphertext`: String, `secret`: String): String { + return FfiConverterString.lift( + rustCallWithError(CrypterException) { _status -> + _UniFFILib.INSTANCE.crypter_b428_decrypt(FfiConverterString.lower(`ciphertext`), FfiConverterString.lower(`secret`), _status) +}) +} + + + + diff --git a/crypter/Cargo.toml b/crypter/Cargo.toml index e21c893..f0cad64 100644 --- a/crypter/Cargo.toml +++ b/crypter/Cargo.toml @@ -5,17 +5,17 @@ authors = ["Evan Feenstra "] edition = "2018" [dependencies] -rand = "0.8" anyhow = {version = "1", features = ["backtrace"]} -log = "0.4" -base64 = { version = "0.13.0" } secp256k1 = { version = "0.22.0", features = ["std", "rand-std"] } +rand = "0.8.5" [dependencies.lightning] version = "0.0.108" default-features = false features = ["std", "grind_signatures"] +# [dev-dependencies] + [patch.crates-io] getrandom = { version = "0.2", git = "https://github.com/esp-rs-compat/getrandom.git" } secp256k1 = { git = "https://github.com/Evanfeenstra/rust-secp256k1", branch = "v0.22.0-new-rand" }